blob: ed1c9b0033bea121fb04e6c6a3b20ce067f98fdd [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>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000040#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000041#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040042#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000043#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000044#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000045#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000046#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000047#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000048#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020049#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000050//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000051#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000052#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020053#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000054#include <linux/icmp.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010055#include <linux/icmpv6.h>
56#include <linux/errqueue.h>
Marco A L Barbosad6d6d6f2017-10-05 10:55:30 -030057#include <linux/random.h>
Riku Voipiod80a1902014-10-01 16:05:46 +030058#ifdef CONFIG_TIMERFD
59#include <sys/timerfd.h>
60#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030061#ifdef CONFIG_EVENTFD
62#include <sys/eventfd.h>
63#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000064#ifdef CONFIG_EPOLL
65#include <sys/epoll.h>
66#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070067#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010068#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070069#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000070#ifdef CONFIG_SENDFILE
71#include <sys/sendfile.h>
72#endif
bellard31e31b82003-02-18 22:55:36 +000073
74#define termios host_termios
75#define winsize host_winsize
76#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000077#define sgttyb host_sgttyb /* same as target */
78#define tchars host_tchars /* same as target */
79#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000080
81#include <linux/termios.h>
82#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000083#include <linux/cdrom.h>
84#include <linux/hdreg.h>
85#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000086#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000087#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030088#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000089#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000090#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000091#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020092#include <linux/fb.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -070093#if defined(CONFIG_USBFS)
94#include <linux/usbdevice_fs.h>
Cortland Tölvaa1333672018-10-08 09:35:21 -070095#include <linux/usb/ch9.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -070096#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020097#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010098#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +000099#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100100#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200101#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100102#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200103#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200104#include <linux/netlink.h>
Yunqiang Suf31dddd2019-06-19 16:17:11 +0200105#include <linux/if_alg.h>
pbrookd7e40362008-05-23 16:06:43 +0000106#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200107#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000108
bellard3ef693a2003-03-23 20:17:16 +0000109#include "qemu.h"
Richard Henderson5ebdd772019-03-14 13:10:53 -0700110#include "qemu/guest-random.h"
Richard Henderson51977e22019-03-12 19:22:20 -0700111#include "qapi/error.h"
Laurent Vivierf7e6a402018-08-24 00:22:15 +0200112#include "fd-trans.h"
bellard31e31b82003-02-18 22:55:36 +0000113
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100114#ifndef CLONE_IO
115#define CLONE_IO 0x80000000 /* Clone io context */
116#endif
117
118/* We can't directly call the host clone syscall, because this will
119 * badly confuse libc (breaking mutexes, for example). So we must
120 * divide clone flags into:
121 * * flag combinations that look like pthread_create()
122 * * flag combinations that look like fork()
123 * * flags we can implement within QEMU itself
124 * * flags we can't support and will return an error for
125 */
126/* For thread creation, all these flags must be present; for
127 * fork, none must be present.
128 */
129#define CLONE_THREAD_FLAGS \
130 (CLONE_VM | CLONE_FS | CLONE_FILES | \
131 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
132
133/* These flags are ignored:
134 * CLONE_DETACHED is now ignored by the kernel;
135 * CLONE_IO is just an optimisation hint to the I/O scheduler
136 */
137#define CLONE_IGNORED_FLAGS \
138 (CLONE_DETACHED | CLONE_IO)
139
140/* Flags for fork which we can implement within QEMU itself */
141#define CLONE_OPTIONAL_FORK_FLAGS \
142 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
143 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
144
145/* Flags for thread creation which we can implement within QEMU itself */
146#define CLONE_OPTIONAL_THREAD_FLAGS \
147 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
148 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
149
150#define CLONE_INVALID_FORK_FLAGS \
151 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
152
153#define CLONE_INVALID_THREAD_FLAGS \
154 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
155 CLONE_IGNORED_FLAGS))
156
157/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
158 * have almost all been allocated. We cannot support any of
159 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
160 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
161 * The checks against the invalid thread masks above will catch these.
162 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
163 */
pbrook30813ce2008-06-02 15:45:44 +0000164
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100165/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
166 * once. This exercises the codepaths for restart.
167 */
168//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000169
bellard1a9353d2003-03-16 20:28:50 +0000170//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000171#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
172#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000173
bellard70a194b2003-08-11 22:20:16 +0000174#undef _syscall0
175#undef _syscall1
176#undef _syscall2
177#undef _syscall3
178#undef _syscall4
179#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000180#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000181
bellard83fcb512006-06-14 13:37:16 +0000182#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000183static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000184{ \
185 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000186}
187
bellard83fcb512006-06-14 13:37:16 +0000188#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000189static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000190{ \
191 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000192}
193
bellard83fcb512006-06-14 13:37:16 +0000194#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000195static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000196{ \
197 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000198}
199
bellard83fcb512006-06-14 13:37:16 +0000200#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000201static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000202{ \
203 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000204}
205
bellard83fcb512006-06-14 13:37:16 +0000206#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000207static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000208{ \
209 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000210}
211
bellard83fcb512006-06-14 13:37:16 +0000212#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
213 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000214static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000215{ \
216 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000217}
bellard83fcb512006-06-14 13:37:16 +0000218
219
220#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
221 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000222static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
223 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000224{ \
225 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
226}
227
bellard70a194b2003-08-11 22:20:16 +0000228
bellard31e31b82003-02-18 22:55:36 +0000229#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000230#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000231#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000232#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000233#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000234#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200235#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000236#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000237#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000238#define __NR_sys_inotify_init __NR_inotify_init
239#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
240#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000241
Peter Maydellb1cef6d2018-01-25 16:19:49 +0000242#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000243#define __NR__llseek __NR_lseek
244#endif
245
James Hogana29e5ba2014-03-25 21:51:08 +0000246/* Newer kernel ports have llseek() instead of _llseek() */
247#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
248#define TARGET_NR__llseek TARGET_NR_llseek
249#endif
250
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +0000251#define __NR_sys_gettid __NR_gettid
252_syscall0(int, sys_gettid)
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100253
254/* For the 64-bit guest on 32-bit host case we must emulate
255 * getdents using getdents64, because otherwise the host
256 * might hand us back more dirent records than we can fit
257 * into the guest buffer after structure format conversion.
258 * Otherwise we emulate getdents with getdents if the host has it.
259 */
260#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
261#define EMULATE_GETDENTS_WITH_GETDENTS
262#endif
263
264#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
aurel323b3f24a2009-04-15 16:12:13 +0000265_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100266#endif
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100267#if (defined(TARGET_NR_getdents) && \
268 !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
Peter Maydell3307e232013-06-12 16:20:21 +0100269 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000270_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
271#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700272#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000273_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
274 loff_t *, res, uint, wh);
275#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200276_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200277_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
278 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000279_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000280#ifdef __NR_exit_group
281_syscall1(int,exit_group,int,error_code)
282#endif
283#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
284_syscall1(int,set_tid_address,int *,tidptr)
285#endif
aurel323b3f24a2009-04-15 16:12:13 +0000286#if defined(TARGET_NR_futex) && defined(__NR_futex)
287_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
288 const struct timespec *,timeout,int *,uaddr2,int,val3)
289#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500290#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
291_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
292 unsigned long *, user_mask_ptr);
293#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
294_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
295 unsigned long *, user_mask_ptr);
Samuel Thibaultb827c3e2018-01-12 09:14:35 +0100296#define __NR_sys_getcpu __NR_getcpu
297_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200298_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
299 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000300_syscall2(int, capget, struct __user_cap_header_struct *, header,
301 struct __user_cap_data_struct *, data);
302_syscall2(int, capset, struct __user_cap_header_struct *, header,
303 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100304#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
305_syscall2(int, ioprio_get, int, which, int, who)
306#endif
307#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
308_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
309#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100310#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
311_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
312#endif
aurel323b3f24a2009-04-15 16:12:13 +0000313
Laurent Vivier2f147882016-09-25 22:20:20 +0200314#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
315_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
316 unsigned long, idx1, unsigned long, idx2)
317#endif
318
aurel323b3f24a2009-04-15 16:12:13 +0000319static bitmask_transtbl fcntl_flags_tbl[] = {
320 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
321 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
322 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
323 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
324 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
325 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
326 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
327 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700328 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000329 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
330 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
331 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
332 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000333#if defined(O_DIRECT)
334 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
335#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700336#if defined(O_NOATIME)
337 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
338#endif
339#if defined(O_CLOEXEC)
340 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
341#endif
342#if defined(O_PATH)
343 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
344#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300345#if defined(O_TMPFILE)
346 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
347#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700348 /* Don't terminate the list prematurely on 64-bit host+guest. */
349#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
350 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
351#endif
aurel323b3f24a2009-04-15 16:12:13 +0000352 { 0, 0, 0, 0 }
353};
354
aurel323b3f24a2009-04-15 16:12:13 +0000355static int sys_getcwd1(char *buf, size_t size)
356{
357 if (getcwd(buf, size) == NULL) {
358 /* getcwd() sets errno */
359 return (-1);
360 }
aurel32aaf4ad32009-04-16 14:17:14 +0000361 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000362}
363
Peter Maydell1acae9f2013-07-02 14:04:12 +0100364#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100365#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100366#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000367_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
368 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100369#else
370static int sys_utimensat(int dirfd, const char *pathname,
371 const struct timespec times[2], int flags)
372{
373 errno = ENOSYS;
374 return -1;
375}
ths9007f0e2007-09-25 17:50:37 +0000376#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100377#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000378
Andreas Schwab95d03072018-01-23 11:53:31 +0100379#ifdef TARGET_NR_renameat2
380#if defined(__NR_renameat2)
381#define __NR_sys_renameat2 __NR_renameat2
382_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
383 const char *, new, unsigned int, flags)
384#else
385static int sys_renameat2(int oldfd, const char *old,
386 int newfd, const char *new, int flags)
387{
388 if (flags == 0) {
389 return renameat(oldfd, old, newfd, new);
390 }
391 errno = ENOSYS;
392 return -1;
393}
394#endif
395#endif /* TARGET_NR_renameat2 */
396
aurel323b3f24a2009-04-15 16:12:13 +0000397#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000398#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000399
aurel3239b59762008-10-01 21:46:50 +0000400#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000401static int sys_inotify_init(void)
402{
403 return (inotify_init());
404}
aurel3239b59762008-10-01 21:46:50 +0000405#endif
406#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000407static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
408{
409 return (inotify_add_watch(fd, pathname, mask));
410}
aurel3239b59762008-10-01 21:46:50 +0000411#endif
412#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000413static int sys_inotify_rm_watch(int fd, int32_t wd)
414{
aurel328690e422009-04-17 13:50:32 +0000415 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000416}
aurel3239b59762008-10-01 21:46:50 +0000417#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000418#ifdef CONFIG_INOTIFY1
419#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
420static int sys_inotify_init1(int flags)
421{
422 return (inotify_init1(flags));
423}
424#endif
425#endif
aurel323b3f24a2009-04-15 16:12:13 +0000426#else
427/* Userspace can usually survive runtime without inotify */
428#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000429#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000430#undef TARGET_NR_inotify_add_watch
431#undef TARGET_NR_inotify_rm_watch
432#endif /* CONFIG_INOTIFY */
433
Peter Maydell163a05a2011-06-27 17:44:52 +0100434#if defined(TARGET_NR_prlimit64)
435#ifndef __NR_prlimit64
436# define __NR_prlimit64 -1
437#endif
438#define __NR_sys_prlimit64 __NR_prlimit64
439/* The glibc rlimit structure may not be that used by the underlying syscall */
440struct host_rlimit64 {
441 uint64_t rlim_cur;
442 uint64_t rlim_max;
443};
444_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
445 const struct host_rlimit64 *, new_limit,
446 struct host_rlimit64 *, old_limit)
447#endif
448
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100449
450#if defined(TARGET_NR_timer_create)
451/* Maxiumum of 32 active POSIX timers allowed at any one time. */
452static timer_t g_posix_timers[32] = { 0, } ;
453
454static inline int next_free_host_timer(void)
455{
456 int k ;
457 /* FIXME: Does finding the next free slot require a lock? */
458 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
459 if (g_posix_timers[k] == 0) {
460 g_posix_timers[k] = (timer_t) 1;
461 return k;
462 }
463 }
464 return -1;
465}
466#endif
467
Riku Voipio48e515d2011-07-12 15:40:51 +0300468/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000469#ifdef TARGET_ARM
James Clarke8bf8e9d2017-09-15 20:33:13 +0100470static inline int regpairs_aligned(void *cpu_env, int num)
471{
Riku Voipio48e515d2011-07-12 15:40:51 +0300472 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
473}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200474#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
James Clarke8bf8e9d2017-09-15 20:33:13 +0100475static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000476#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
477/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
478 * of registers which translates to the same as ARM/MIPS, because we start with
479 * r3 as arg1 */
James Clarke8bf8e9d2017-09-15 20:33:13 +0100480static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
481#elif defined(TARGET_SH4)
482/* SH4 doesn't align register pairs, except for p{read,write}64 */
483static inline int regpairs_aligned(void *cpu_env, int num)
484{
485 switch (num) {
486 case TARGET_NR_pread64:
487 case TARGET_NR_pwrite64:
488 return 1;
489
490 default:
491 return 0;
492 }
493}
Max Filippovba7651f2017-01-25 10:54:11 -0800494#elif defined(TARGET_XTENSA)
495static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300496#else
James Clarke8bf8e9d2017-09-15 20:33:13 +0100497static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300498#endif
499
thsb92c47c2007-11-01 00:07:38 +0000500#define ERRNO_TABLE_SIZE 1200
501
502/* target_to_host_errno_table[] is initialized from
503 * host_to_target_errno_table[] in syscall_init(). */
504static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
505};
506
ths637947f2007-06-01 12:09:19 +0000507/*
thsfe8f0962007-07-12 10:59:21 +0000508 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000509 * minus the errnos that are not actually generic to all archs.
510 */
thsb92c47c2007-11-01 00:07:38 +0000511static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800512 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000513 [EIDRM] = TARGET_EIDRM,
514 [ECHRNG] = TARGET_ECHRNG,
515 [EL2NSYNC] = TARGET_EL2NSYNC,
516 [EL3HLT] = TARGET_EL3HLT,
517 [EL3RST] = TARGET_EL3RST,
518 [ELNRNG] = TARGET_ELNRNG,
519 [EUNATCH] = TARGET_EUNATCH,
520 [ENOCSI] = TARGET_ENOCSI,
521 [EL2HLT] = TARGET_EL2HLT,
522 [EDEADLK] = TARGET_EDEADLK,
523 [ENOLCK] = TARGET_ENOLCK,
524 [EBADE] = TARGET_EBADE,
525 [EBADR] = TARGET_EBADR,
526 [EXFULL] = TARGET_EXFULL,
527 [ENOANO] = TARGET_ENOANO,
528 [EBADRQC] = TARGET_EBADRQC,
529 [EBADSLT] = TARGET_EBADSLT,
530 [EBFONT] = TARGET_EBFONT,
531 [ENOSTR] = TARGET_ENOSTR,
532 [ENODATA] = TARGET_ENODATA,
533 [ETIME] = TARGET_ETIME,
534 [ENOSR] = TARGET_ENOSR,
535 [ENONET] = TARGET_ENONET,
536 [ENOPKG] = TARGET_ENOPKG,
537 [EREMOTE] = TARGET_EREMOTE,
538 [ENOLINK] = TARGET_ENOLINK,
539 [EADV] = TARGET_EADV,
540 [ESRMNT] = TARGET_ESRMNT,
541 [ECOMM] = TARGET_ECOMM,
542 [EPROTO] = TARGET_EPROTO,
543 [EDOTDOT] = TARGET_EDOTDOT,
544 [EMULTIHOP] = TARGET_EMULTIHOP,
545 [EBADMSG] = TARGET_EBADMSG,
546 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
547 [EOVERFLOW] = TARGET_EOVERFLOW,
548 [ENOTUNIQ] = TARGET_ENOTUNIQ,
549 [EBADFD] = TARGET_EBADFD,
550 [EREMCHG] = TARGET_EREMCHG,
551 [ELIBACC] = TARGET_ELIBACC,
552 [ELIBBAD] = TARGET_ELIBBAD,
553 [ELIBSCN] = TARGET_ELIBSCN,
554 [ELIBMAX] = TARGET_ELIBMAX,
555 [ELIBEXEC] = TARGET_ELIBEXEC,
556 [EILSEQ] = TARGET_EILSEQ,
557 [ENOSYS] = TARGET_ENOSYS,
558 [ELOOP] = TARGET_ELOOP,
559 [ERESTART] = TARGET_ERESTART,
560 [ESTRPIPE] = TARGET_ESTRPIPE,
561 [ENOTEMPTY] = TARGET_ENOTEMPTY,
562 [EUSERS] = TARGET_EUSERS,
563 [ENOTSOCK] = TARGET_ENOTSOCK,
564 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
565 [EMSGSIZE] = TARGET_EMSGSIZE,
566 [EPROTOTYPE] = TARGET_EPROTOTYPE,
567 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
568 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
569 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
570 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
571 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
572 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
573 [EADDRINUSE] = TARGET_EADDRINUSE,
574 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
575 [ENETDOWN] = TARGET_ENETDOWN,
576 [ENETUNREACH] = TARGET_ENETUNREACH,
577 [ENETRESET] = TARGET_ENETRESET,
578 [ECONNABORTED] = TARGET_ECONNABORTED,
579 [ECONNRESET] = TARGET_ECONNRESET,
580 [ENOBUFS] = TARGET_ENOBUFS,
581 [EISCONN] = TARGET_EISCONN,
582 [ENOTCONN] = TARGET_ENOTCONN,
583 [EUCLEAN] = TARGET_EUCLEAN,
584 [ENOTNAM] = TARGET_ENOTNAM,
585 [ENAVAIL] = TARGET_ENAVAIL,
586 [EISNAM] = TARGET_EISNAM,
587 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200588 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000589 [ESHUTDOWN] = TARGET_ESHUTDOWN,
590 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
591 [ETIMEDOUT] = TARGET_ETIMEDOUT,
592 [ECONNREFUSED] = TARGET_ECONNREFUSED,
593 [EHOSTDOWN] = TARGET_EHOSTDOWN,
594 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
595 [EALREADY] = TARGET_EALREADY,
596 [EINPROGRESS] = TARGET_EINPROGRESS,
597 [ESTALE] = TARGET_ESTALE,
598 [ECANCELED] = TARGET_ECANCELED,
599 [ENOMEDIUM] = TARGET_ENOMEDIUM,
600 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000601#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000602 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000603#endif
604#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000605 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000606#endif
607#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000608 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000609#endif
610#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000611 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000612#endif
613#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000614 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000615#endif
616#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000617 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000618#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200619#ifdef ENOMSG
620 [ENOMSG] = TARGET_ENOMSG,
621#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800622#ifdef ERKFILL
623 [ERFKILL] = TARGET_ERFKILL,
624#endif
625#ifdef EHWPOISON
626 [EHWPOISON] = TARGET_EHWPOISON,
627#endif
thsb92c47c2007-11-01 00:07:38 +0000628};
ths637947f2007-06-01 12:09:19 +0000629
630static inline int host_to_target_errno(int err)
631{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100632 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
633 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000634 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100635 }
ths637947f2007-06-01 12:09:19 +0000636 return err;
637}
638
thsb92c47c2007-11-01 00:07:38 +0000639static inline int target_to_host_errno(int err)
640{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100641 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
642 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000643 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100644 }
thsb92c47c2007-11-01 00:07:38 +0000645 return err;
646}
647
blueswir1992f48a2007-10-14 16:27:31 +0000648static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000649{
650 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000651 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000652 else
653 return ret;
654}
655
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100656const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000657{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100658 if (err == TARGET_ERESTARTSYS) {
659 return "To be restarted";
660 }
661 if (err == TARGET_QEMU_ESIGRETURN) {
662 return "Successful exit from sigreturn";
663 }
664
Alexander Graf962b2892011-11-21 12:04:07 +0100665 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
666 return NULL;
667 }
thsb92c47c2007-11-01 00:07:38 +0000668 return strerror(target_to_host_errno(err));
669}
670
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100671#define safe_syscall0(type, name) \
672static type safe_##name(void) \
673{ \
674 return safe_syscall(__NR_##name); \
675}
676
677#define safe_syscall1(type, name, type1, arg1) \
678static type safe_##name(type1 arg1) \
679{ \
680 return safe_syscall(__NR_##name, arg1); \
681}
682
683#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
684static type safe_##name(type1 arg1, type2 arg2) \
685{ \
686 return safe_syscall(__NR_##name, arg1, arg2); \
687}
688
689#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
690static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
691{ \
692 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
693}
694
695#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
696 type4, arg4) \
697static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
698{ \
699 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
700}
701
702#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
703 type4, arg4, type5, arg5) \
704static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
705 type5 arg5) \
706{ \
707 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
708}
709
710#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
711 type4, arg4, type5, arg5, type6, arg6) \
712static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
713 type5 arg5, type6 arg6) \
714{ \
715 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
716}
717
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100718safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
719safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100720safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
721 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100722safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
723 struct rusage *, rusage)
724safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
725 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100726safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100727safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
728 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100729safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
730 struct timespec *, tsp, const sigset_t *, sigmask,
731 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100732safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
733 int, maxevents, int, timeout, const sigset_t *, sigmask,
734 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100735safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
736 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100737safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100738safe_syscall2(int, kill, pid_t, pid, int, sig)
739safe_syscall2(int, tkill, int, tid, int, sig)
740safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100741safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
742safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200743safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
744 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200745safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
746 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100747safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
748 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100749safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
750 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
751safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
752 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
753safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
754safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100755safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100756safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
757 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100758safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
759 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100760safe_syscall2(int, nanosleep, const struct timespec *, req,
761 struct timespec *, rem)
762#ifdef TARGET_NR_clock_nanosleep
763safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
764 const struct timespec *, req, struct timespec *, rem)
765#endif
Laurent Vivier524fa342019-05-29 10:48:04 +0200766#ifdef __NR_ipc
Peter Maydell89f9fe42016-06-06 19:58:05 +0100767safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
768 void *, ptr, long, fifth)
Laurent Vivier86e63692019-05-23 19:54:13 +0200769#endif
770#ifdef __NR_msgsnd
771safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
772 int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200773#endif
774#ifdef __NR_msgrcv
775safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
776 long, msgtype, int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200777#endif
778#ifdef __NR_semtimedop
779safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
780 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100781#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100782#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
783safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
784 size_t, len, unsigned, prio, const struct timespec *, timeout)
785safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
786 size_t, len, unsigned *, prio, const struct timespec *, timeout)
787#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100788/* We do ioctl like this rather than via safe_syscall3 to preserve the
789 * "third argument might be integer or pointer or not present" behaviour of
790 * the libc function.
791 */
792#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100793/* Similarly for fcntl. Note that callers must always:
794 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
795 * use the flock64 struct rather than unsuffixed flock
796 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
797 */
798#ifdef __NR_fcntl64
799#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
800#else
801#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
802#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100803
Paul Burton8289d112014-06-22 11:25:33 +0100804static inline int host_to_target_sock_type(int host_type)
805{
806 int target_type;
807
808 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
809 case SOCK_DGRAM:
810 target_type = TARGET_SOCK_DGRAM;
811 break;
812 case SOCK_STREAM:
813 target_type = TARGET_SOCK_STREAM;
814 break;
815 default:
816 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
817 break;
818 }
819
820#if defined(SOCK_CLOEXEC)
821 if (host_type & SOCK_CLOEXEC) {
822 target_type |= TARGET_SOCK_CLOEXEC;
823 }
824#endif
825
826#if defined(SOCK_NONBLOCK)
827 if (host_type & SOCK_NONBLOCK) {
828 target_type |= TARGET_SOCK_NONBLOCK;
829 }
830#endif
831
832 return target_type;
833}
834
blueswir1992f48a2007-10-14 16:27:31 +0000835static abi_ulong target_brk;
836static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000837static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000838
blueswir1992f48a2007-10-14 16:27:31 +0000839void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000840{
blueswir14c1de732007-07-07 20:45:44 +0000841 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000842 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000843}
844
vincent4d1de872011-06-14 21:56:33 +0000845//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
846#define DEBUGF_BRK(message, args...)
847
ths0da46a62007-10-20 20:23:07 +0000848/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000849abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000850{
blueswir1992f48a2007-10-14 16:27:31 +0000851 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +0100852 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +0000853
Paul Brook3a0c6c42012-02-09 19:04:27 +0000854 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000855
vincent4d1de872011-06-14 21:56:33 +0000856 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000857 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000858 return target_brk;
859 }
860 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000861 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
862 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000863 return target_brk;
864 }
bellard31e31b82003-02-18 22:55:36 +0000865
vincent4d1de872011-06-14 21:56:33 +0000866 /* If the new brk is less than the highest page reserved to the
867 * target heap allocation, set it and we're almost done... */
868 if (new_brk <= brk_page) {
869 /* Heap contents are initialized to zero, as for anonymous
870 * mapped pages. */
871 if (new_brk > target_brk) {
872 memset(g2h(target_brk), 0, new_brk - target_brk);
873 }
bellard31e31b82003-02-18 22:55:36 +0000874 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000875 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
Paolo Bonzini72e21db2018-12-13 23:37:36 +0100876 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000877 }
878
Peter Maydell00faf082011-04-18 16:34:24 +0100879 /* We need to allocate more memory after the brk... Note that
880 * we don't use MAP_FIXED because that will map over the top of
881 * any existing mapping (like the one with the host libc or qemu
882 * itself); instead we treat "mapped but at wrong address" as
883 * a failure and unmap again.
884 */
vincent4d1de872011-06-14 21:56:33 +0000885 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000886 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000887 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100888 MAP_ANON|MAP_PRIVATE, 0, 0));
889
890 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200891 /* Heap contents are initialized to zero, as for anonymous
892 * mapped pages. Technically the new pages are already
893 * initialized to zero since they *are* anonymous mapped
894 * pages, however we have to take care with the contents that
895 * come from the remaining part of the previous page: it may
896 * contains garbage data due to a previous heap usage (grown
897 * then shrunken). */
898 memset(g2h(target_brk), 0, brk_page - target_brk);
899
Peter Maydell00faf082011-04-18 16:34:24 +0100900 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000901 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000902 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
903 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100904 return target_brk;
905 } else if (mapped_addr != -1) {
906 /* Mapped but at wrong address, meaning there wasn't actually
907 * enough space for this brk.
908 */
909 target_munmap(mapped_addr, new_alloc_size);
910 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000911 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000912 }
913 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000914 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100915 }
balrog7ab240a2008-04-26 12:17:34 +0000916
Richard Henderson7dd46c02010-05-03 10:07:49 -0700917#if defined(TARGET_ALPHA)
918 /* We (partially) emulate OSF/1 on Alpha, which requires we
919 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100920 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700921#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100922 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000923 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000924}
925
ths26edcf42007-12-09 02:25:24 +0000926static inline abi_long copy_from_user_fdset(fd_set *fds,
927 abi_ulong target_fds_addr,
928 int n)
bellard31e31b82003-02-18 22:55:36 +0000929{
ths26edcf42007-12-09 02:25:24 +0000930 int i, nw, j, k;
931 abi_ulong b, *target_fds;
932
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200933 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000934 if (!(target_fds = lock_user(VERIFY_READ,
935 target_fds_addr,
936 sizeof(abi_ulong) * nw,
937 1)))
938 return -TARGET_EFAULT;
939
940 FD_ZERO(fds);
941 k = 0;
942 for (i = 0; i < nw; i++) {
943 /* grab the abi_ulong */
944 __get_user(b, &target_fds[i]);
945 for (j = 0; j < TARGET_ABI_BITS; j++) {
946 /* check the bit inside the abi_ulong */
947 if ((b >> j) & 1)
948 FD_SET(k, fds);
949 k++;
bellard31e31b82003-02-18 22:55:36 +0000950 }
bellard31e31b82003-02-18 22:55:36 +0000951 }
ths26edcf42007-12-09 02:25:24 +0000952
953 unlock_user(target_fds, target_fds_addr, 0);
954
955 return 0;
bellard31e31b82003-02-18 22:55:36 +0000956}
957
Mike Frysinger055e0902011-06-03 17:01:49 -0400958static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
959 abi_ulong target_fds_addr,
960 int n)
961{
962 if (target_fds_addr) {
963 if (copy_from_user_fdset(fds, target_fds_addr, n))
964 return -TARGET_EFAULT;
965 *fds_ptr = fds;
966 } else {
967 *fds_ptr = NULL;
968 }
969 return 0;
970}
971
ths26edcf42007-12-09 02:25:24 +0000972static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
973 const fd_set *fds,
974 int n)
bellard31e31b82003-02-18 22:55:36 +0000975{
bellard31e31b82003-02-18 22:55:36 +0000976 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000977 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000978 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000979
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200980 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000981 if (!(target_fds = lock_user(VERIFY_WRITE,
982 target_fds_addr,
983 sizeof(abi_ulong) * nw,
984 0)))
985 return -TARGET_EFAULT;
986
987 k = 0;
988 for (i = 0; i < nw; i++) {
989 v = 0;
990 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000991 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000992 k++;
bellard31e31b82003-02-18 22:55:36 +0000993 }
ths26edcf42007-12-09 02:25:24 +0000994 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000995 }
ths26edcf42007-12-09 02:25:24 +0000996
997 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
998
999 return 0;
bellard31e31b82003-02-18 22:55:36 +00001000}
1001
bellardc596ed12003-07-13 17:32:31 +00001002#if defined(__alpha__)
1003#define HOST_HZ 1024
1004#else
1005#define HOST_HZ 100
1006#endif
1007
blueswir1992f48a2007-10-14 16:27:31 +00001008static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001009{
1010#if HOST_HZ == TARGET_HZ
1011 return ticks;
1012#else
1013 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1014#endif
1015}
1016
bellard579a97f2007-11-11 14:26:47 +00001017static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1018 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001019{
pbrook53a59602006-03-25 19:31:22 +00001020 struct target_rusage *target_rusage;
1021
bellard579a97f2007-11-11 14:26:47 +00001022 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1023 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001024 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1025 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1026 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1027 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1028 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1029 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1030 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1031 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1032 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1033 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1034 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1035 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1036 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1037 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1038 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1039 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1040 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1041 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001042 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001043
1044 return 0;
bellardb4091862003-05-16 15:39:34 +00001045}
1046
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001047static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001048{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001049 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001050 rlim_t result;
1051
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001052 target_rlim_swap = tswapal(target_rlim);
1053 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1054 return RLIM_INFINITY;
1055
1056 result = target_rlim_swap;
1057 if (target_rlim_swap != (rlim_t)result)
1058 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001059
1060 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001061}
1062
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001063static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001064{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001065 abi_ulong target_rlim_swap;
1066 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001067
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001068 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001069 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001070 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001071 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001072 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001073
1074 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001075}
1076
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001077static inline int target_to_host_resource(int code)
1078{
1079 switch (code) {
1080 case TARGET_RLIMIT_AS:
1081 return RLIMIT_AS;
1082 case TARGET_RLIMIT_CORE:
1083 return RLIMIT_CORE;
1084 case TARGET_RLIMIT_CPU:
1085 return RLIMIT_CPU;
1086 case TARGET_RLIMIT_DATA:
1087 return RLIMIT_DATA;
1088 case TARGET_RLIMIT_FSIZE:
1089 return RLIMIT_FSIZE;
1090 case TARGET_RLIMIT_LOCKS:
1091 return RLIMIT_LOCKS;
1092 case TARGET_RLIMIT_MEMLOCK:
1093 return RLIMIT_MEMLOCK;
1094 case TARGET_RLIMIT_MSGQUEUE:
1095 return RLIMIT_MSGQUEUE;
1096 case TARGET_RLIMIT_NICE:
1097 return RLIMIT_NICE;
1098 case TARGET_RLIMIT_NOFILE:
1099 return RLIMIT_NOFILE;
1100 case TARGET_RLIMIT_NPROC:
1101 return RLIMIT_NPROC;
1102 case TARGET_RLIMIT_RSS:
1103 return RLIMIT_RSS;
1104 case TARGET_RLIMIT_RTPRIO:
1105 return RLIMIT_RTPRIO;
1106 case TARGET_RLIMIT_SIGPENDING:
1107 return RLIMIT_SIGPENDING;
1108 case TARGET_RLIMIT_STACK:
1109 return RLIMIT_STACK;
1110 default:
1111 return code;
1112 }
1113}
1114
ths788f5ec2007-12-09 02:37:05 +00001115static inline abi_long copy_from_user_timeval(struct timeval *tv,
1116 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001117{
pbrook53a59602006-03-25 19:31:22 +00001118 struct target_timeval *target_tv;
1119
ths788f5ec2007-12-09 02:37:05 +00001120 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001121 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001122
1123 __get_user(tv->tv_sec, &target_tv->tv_sec);
1124 __get_user(tv->tv_usec, &target_tv->tv_usec);
1125
1126 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001127
1128 return 0;
bellard31e31b82003-02-18 22:55:36 +00001129}
1130
ths788f5ec2007-12-09 02:37:05 +00001131static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1132 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001133{
pbrook53a59602006-03-25 19:31:22 +00001134 struct target_timeval *target_tv;
1135
ths788f5ec2007-12-09 02:37:05 +00001136 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001137 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001138
1139 __put_user(tv->tv_sec, &target_tv->tv_sec);
1140 __put_user(tv->tv_usec, &target_tv->tv_usec);
1141
1142 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001143
1144 return 0;
bellard31e31b82003-02-18 22:55:36 +00001145}
1146
Paul Burtonef4467e2014-06-22 11:25:40 +01001147static inline abi_long copy_from_user_timezone(struct timezone *tz,
1148 abi_ulong target_tz_addr)
1149{
1150 struct target_timezone *target_tz;
1151
1152 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1153 return -TARGET_EFAULT;
1154 }
1155
1156 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1157 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1158
1159 unlock_user_struct(target_tz, target_tz_addr, 0);
1160
1161 return 0;
1162}
1163
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001164#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1165#include <mqueue.h>
1166
aurel3224e10032009-04-15 16:11:43 +00001167static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1168 abi_ulong target_mq_attr_addr)
1169{
1170 struct target_mq_attr *target_mq_attr;
1171
1172 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1173 target_mq_attr_addr, 1))
1174 return -TARGET_EFAULT;
1175
1176 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1177 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1178 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1179 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1180
1181 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1182
1183 return 0;
1184}
1185
1186static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1187 const struct mq_attr *attr)
1188{
1189 struct target_mq_attr *target_mq_attr;
1190
1191 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1192 target_mq_attr_addr, 0))
1193 return -TARGET_EFAULT;
1194
1195 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1196 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1197 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1198 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1199
1200 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1201
1202 return 0;
1203}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001204#endif
bellard31e31b82003-02-18 22:55:36 +00001205
Mike Frysinger055e0902011-06-03 17:01:49 -04001206#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001207/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001208static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001209 abi_ulong rfd_addr, abi_ulong wfd_addr,
1210 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001211{
1212 fd_set rfds, wfds, efds;
1213 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001214 struct timeval tv;
1215 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001216 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001217
Mike Frysinger055e0902011-06-03 17:01:49 -04001218 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1219 if (ret) {
1220 return ret;
pbrook53a59602006-03-25 19:31:22 +00001221 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001222 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1223 if (ret) {
1224 return ret;
pbrook53a59602006-03-25 19:31:22 +00001225 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001226 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1227 if (ret) {
1228 return ret;
pbrook53a59602006-03-25 19:31:22 +00001229 }
ths3b46e622007-09-17 08:09:54 +00001230
ths26edcf42007-12-09 02:25:24 +00001231 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001232 if (copy_from_user_timeval(&tv, target_tv_addr))
1233 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001234 ts.tv_sec = tv.tv_sec;
1235 ts.tv_nsec = tv.tv_usec * 1000;
1236 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001237 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001238 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001239 }
ths26edcf42007-12-09 02:25:24 +00001240
Peter Maydell6df9d382016-05-12 18:47:51 +01001241 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1242 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001243
ths26edcf42007-12-09 02:25:24 +00001244 if (!is_error(ret)) {
1245 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1246 return -TARGET_EFAULT;
1247 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1248 return -TARGET_EFAULT;
1249 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1250 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001251
Peter Maydell6df9d382016-05-12 18:47:51 +01001252 if (target_tv_addr) {
1253 tv.tv_sec = ts.tv_sec;
1254 tv.tv_usec = ts.tv_nsec / 1000;
1255 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1256 return -TARGET_EFAULT;
1257 }
1258 }
bellard31e31b82003-02-18 22:55:36 +00001259 }
bellard579a97f2007-11-11 14:26:47 +00001260
bellard31e31b82003-02-18 22:55:36 +00001261 return ret;
1262}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001263
1264#if defined(TARGET_WANT_OLD_SYS_SELECT)
1265static abi_long do_old_select(abi_ulong arg1)
1266{
1267 struct target_sel_arg_struct *sel;
1268 abi_ulong inp, outp, exp, tvp;
1269 long nsel;
1270
1271 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1272 return -TARGET_EFAULT;
1273 }
1274
1275 nsel = tswapal(sel->n);
1276 inp = tswapal(sel->inp);
1277 outp = tswapal(sel->outp);
1278 exp = tswapal(sel->exp);
1279 tvp = tswapal(sel->tvp);
1280
1281 unlock_user_struct(sel, arg1, 0);
1282
1283 return do_select(nsel, inp, outp, exp, tvp);
1284}
1285#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001286#endif
bellard31e31b82003-02-18 22:55:36 +00001287
Riku Voipio099d6b02009-05-05 12:10:04 +03001288static abi_long do_pipe2(int host_pipe[], int flags)
1289{
1290#ifdef CONFIG_PIPE2
1291 return pipe2(host_pipe, flags);
1292#else
1293 return -ENOSYS;
1294#endif
1295}
1296
Richard Hendersonfb41a662010-05-03 10:07:52 -07001297static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1298 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001299{
1300 int host_pipe[2];
1301 abi_long ret;
1302 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1303
1304 if (is_error(ret))
1305 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001306
1307 /* Several targets have special calling conventions for the original
1308 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1309 if (!is_pipe2) {
1310#if defined(TARGET_ALPHA)
1311 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1312 return host_pipe[0];
1313#elif defined(TARGET_MIPS)
1314 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1315 return host_pipe[0];
1316#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001317 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001318 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001319#elif defined(TARGET_SPARC)
1320 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1321 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001322#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001323 }
1324
Riku Voipio099d6b02009-05-05 12:10:04 +03001325 if (put_user_s32(host_pipe[0], pipedes)
1326 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1327 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001328 return get_errno(ret);
1329}
1330
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001331static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1332 abi_ulong target_addr,
1333 socklen_t len)
1334{
1335 struct target_ip_mreqn *target_smreqn;
1336
1337 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1338 if (!target_smreqn)
1339 return -TARGET_EFAULT;
1340 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1341 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1342 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001343 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001344 unlock_user(target_smreqn, target_addr, 0);
1345
1346 return 0;
1347}
1348
Laurent Vivier7b36f782015-10-28 21:40:44 +01001349static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001350 abi_ulong target_addr,
1351 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001352{
aurel32607175e2009-04-15 16:11:59 +00001353 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1354 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001355 struct target_sockaddr *target_saddr;
1356
Laurent Vivier7b36f782015-10-28 21:40:44 +01001357 if (fd_trans_target_to_host_addr(fd)) {
1358 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1359 }
1360
bellard579a97f2007-11-11 14:26:47 +00001361 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1362 if (!target_saddr)
1363 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001364
1365 sa_family = tswap16(target_saddr->sa_family);
1366
1367 /* Oops. The caller might send a incomplete sun_path; sun_path
1368 * must be terminated by \0 (see the manual page), but
1369 * unfortunately it is quite common to specify sockaddr_un
1370 * length as "strlen(x->sun_path)" while it should be
1371 * "strlen(...) + 1". We'll fix that here if needed.
1372 * Linux kernel has a similar feature.
1373 */
1374
1375 if (sa_family == AF_UNIX) {
1376 if (len < unix_maxlen && len > 0) {
1377 char *cp = (char*)target_saddr;
1378
1379 if ( cp[len-1] && !cp[len] )
1380 len++;
1381 }
1382 if (len > unix_maxlen)
1383 len = unix_maxlen;
1384 }
1385
pbrook53a59602006-03-25 19:31:22 +00001386 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001387 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001388 if (sa_family == AF_NETLINK) {
1389 struct sockaddr_nl *nladdr;
1390
1391 nladdr = (struct sockaddr_nl *)addr;
1392 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1393 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1394 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001395 struct target_sockaddr_ll *lladdr;
1396
1397 lladdr = (struct target_sockaddr_ll *)addr;
1398 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1399 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1400 }
pbrook53a59602006-03-25 19:31:22 +00001401 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001402
1403 return 0;
bellard7854b052003-03-29 17:22:23 +00001404}
1405
bellard579a97f2007-11-11 14:26:47 +00001406static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1407 struct sockaddr *addr,
1408 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001409{
pbrook53a59602006-03-25 19:31:22 +00001410 struct target_sockaddr *target_saddr;
1411
Peter Maydella1e22192016-07-07 15:44:43 +01001412 if (len == 0) {
1413 return 0;
1414 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001415 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001416
bellard579a97f2007-11-11 14:26:47 +00001417 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1418 if (!target_saddr)
1419 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001420 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001421 if (len >= offsetof(struct target_sockaddr, sa_family) +
1422 sizeof(target_saddr->sa_family)) {
1423 target_saddr->sa_family = tswap16(addr->sa_family);
1424 }
1425 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001426 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1427 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1428 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001429 } else if (addr->sa_family == AF_PACKET) {
1430 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1431 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1432 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001433 } else if (addr->sa_family == AF_INET6 &&
1434 len >= sizeof(struct target_sockaddr_in6)) {
1435 struct target_sockaddr_in6 *target_in6 =
1436 (struct target_sockaddr_in6 *)target_saddr;
1437 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001438 }
pbrook53a59602006-03-25 19:31:22 +00001439 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001440
1441 return 0;
bellard7854b052003-03-29 17:22:23 +00001442}
1443
bellard5a4a8982007-11-11 17:39:18 +00001444static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1445 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001446{
1447 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001448 abi_long msg_controllen;
1449 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001450 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001451 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001452
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001453 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001454 if (msg_controllen < sizeof (struct target_cmsghdr))
1455 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001456 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001457 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001458 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001459 if (!target_cmsg)
1460 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001461
1462 while (cmsg && target_cmsg) {
1463 void *data = CMSG_DATA(cmsg);
1464 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1465
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001466 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001467 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001468
1469 space += CMSG_SPACE(len);
1470 if (space > msgh->msg_controllen) {
1471 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001472 /* This is a QEMU bug, since we allocated the payload
1473 * area ourselves (unlike overflow in host-to-target
1474 * conversion, which is just the guest giving us a buffer
1475 * that's too small). It can't happen for the payload types
1476 * we currently support; if it becomes an issue in future
1477 * we would need to improve our allocation strategy to
1478 * something more intelligent than "twice the size of the
1479 * target buffer we're reading from".
1480 */
bellard31febb72005-12-18 20:03:27 +00001481 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001482 break;
1483 }
1484
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001485 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1486 cmsg->cmsg_level = SOL_SOCKET;
1487 } else {
1488 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1489 }
bellard7854b052003-03-29 17:22:23 +00001490 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1491 cmsg->cmsg_len = CMSG_LEN(len);
1492
Alex Suykov30b8b682014-12-23 07:52:58 +02001493 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001494 int *fd = (int *)data;
1495 int *target_fd = (int *)target_data;
1496 int i, numfds = len / sizeof(int);
1497
Peter Maydell876e23c2015-05-26 19:46:32 +01001498 for (i = 0; i < numfds; i++) {
1499 __get_user(fd[i], target_fd + i);
1500 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001501 } else if (cmsg->cmsg_level == SOL_SOCKET
1502 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1503 struct ucred *cred = (struct ucred *)data;
1504 struct target_ucred *target_cred =
1505 (struct target_ucred *)target_data;
1506
Peter Maydell876e23c2015-05-26 19:46:32 +01001507 __get_user(cred->pid, &target_cred->pid);
1508 __get_user(cred->uid, &target_cred->uid);
1509 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001510 } else {
1511 gemu_log("Unsupported ancillary data: %d/%d\n",
1512 cmsg->cmsg_level, cmsg->cmsg_type);
1513 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001514 }
1515
1516 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001517 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1518 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001519 }
bellard5a4a8982007-11-11 17:39:18 +00001520 unlock_user(target_cmsg, target_cmsg_addr, 0);
1521 the_end:
bellard7854b052003-03-29 17:22:23 +00001522 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001523 return 0;
bellard7854b052003-03-29 17:22:23 +00001524}
1525
bellard5a4a8982007-11-11 17:39:18 +00001526static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1527 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001528{
1529 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001530 abi_long msg_controllen;
1531 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001532 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001533 socklen_t space = 0;
1534
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001535 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001536 if (msg_controllen < sizeof (struct target_cmsghdr))
1537 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001538 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001539 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001540 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001541 if (!target_cmsg)
1542 return -TARGET_EFAULT;
1543
bellard7854b052003-03-29 17:22:23 +00001544 while (cmsg && target_cmsg) {
1545 void *data = CMSG_DATA(cmsg);
1546 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1547
Peter Maydellad762b92017-12-15 13:52:56 +00001548 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001549 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001550
Peter Maydellc2aeb252015-05-26 19:46:31 +01001551 /* We never copy a half-header but may copy half-data;
1552 * this is Linux's behaviour in put_cmsg(). Note that
1553 * truncation here is a guest problem (which we report
1554 * to the guest via the CTRUNC bit), unlike truncation
1555 * in target_to_host_cmsg, which is a QEMU bug.
1556 */
Peter Maydell71749702017-12-15 13:52:55 +00001557 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001558 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001559 break;
1560 }
1561
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001562 if (cmsg->cmsg_level == SOL_SOCKET) {
1563 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1564 } else {
1565 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1566 }
bellard7854b052003-03-29 17:22:23 +00001567 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001568
Peter Maydellc2aeb252015-05-26 19:46:31 +01001569 /* Payload types which need a different size of payload on
1570 * the target must adjust tgt_len here.
1571 */
Peter Maydell309786c2018-05-18 19:47:15 +01001572 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001573 switch (cmsg->cmsg_level) {
1574 case SOL_SOCKET:
1575 switch (cmsg->cmsg_type) {
1576 case SO_TIMESTAMP:
1577 tgt_len = sizeof(struct target_timeval);
1578 break;
1579 default:
1580 break;
1581 }
Peter Maydell309786c2018-05-18 19:47:15 +01001582 break;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001583 default:
1584 break;
1585 }
1586
Peter Maydell71749702017-12-15 13:52:55 +00001587 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001588 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001589 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001590 }
1591
1592 /* We must now copy-and-convert len bytes of payload
1593 * into tgt_len bytes of destination space. Bear in mind
1594 * that in both source and destination we may be dealing
1595 * with a truncated value!
1596 */
Huw Davies52b65492014-04-17 14:02:47 +01001597 switch (cmsg->cmsg_level) {
1598 case SOL_SOCKET:
1599 switch (cmsg->cmsg_type) {
1600 case SCM_RIGHTS:
1601 {
1602 int *fd = (int *)data;
1603 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001604 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001605
Peter Maydell876e23c2015-05-26 19:46:32 +01001606 for (i = 0; i < numfds; i++) {
1607 __put_user(fd[i], target_fd + i);
1608 }
Huw Davies52b65492014-04-17 14:02:47 +01001609 break;
1610 }
1611 case SO_TIMESTAMP:
1612 {
1613 struct timeval *tv = (struct timeval *)data;
1614 struct target_timeval *target_tv =
1615 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001616
Peter Maydellc2aeb252015-05-26 19:46:31 +01001617 if (len != sizeof(struct timeval) ||
1618 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001619 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001620 }
Huw Davies52b65492014-04-17 14:02:47 +01001621
1622 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001623 __put_user(tv->tv_sec, &target_tv->tv_sec);
1624 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001625 break;
1626 }
Huw Davies4bc29752014-04-17 14:02:48 +01001627 case SCM_CREDENTIALS:
1628 {
1629 struct ucred *cred = (struct ucred *)data;
1630 struct target_ucred *target_cred =
1631 (struct target_ucred *)target_data;
1632
1633 __put_user(cred->pid, &target_cred->pid);
1634 __put_user(cred->uid, &target_cred->uid);
1635 __put_user(cred->gid, &target_cred->gid);
1636 break;
1637 }
Huw Davies52b65492014-04-17 14:02:47 +01001638 default:
1639 goto unimplemented;
1640 }
1641 break;
1642
Helge Delleree1ac3a2017-02-18 23:31:30 +01001643 case SOL_IP:
1644 switch (cmsg->cmsg_type) {
1645 case IP_TTL:
1646 {
1647 uint32_t *v = (uint32_t *)data;
1648 uint32_t *t_int = (uint32_t *)target_data;
1649
Peter Maydell71749702017-12-15 13:52:55 +00001650 if (len != sizeof(uint32_t) ||
1651 tgt_len != sizeof(uint32_t)) {
1652 goto unimplemented;
1653 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001654 __put_user(*v, t_int);
1655 break;
1656 }
1657 case IP_RECVERR:
1658 {
1659 struct errhdr_t {
1660 struct sock_extended_err ee;
1661 struct sockaddr_in offender;
1662 };
1663 struct errhdr_t *errh = (struct errhdr_t *)data;
1664 struct errhdr_t *target_errh =
1665 (struct errhdr_t *)target_data;
1666
Peter Maydell71749702017-12-15 13:52:55 +00001667 if (len != sizeof(struct errhdr_t) ||
1668 tgt_len != sizeof(struct errhdr_t)) {
1669 goto unimplemented;
1670 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001671 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1672 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1673 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1674 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1675 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1676 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1677 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1678 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1679 (void *) &errh->offender, sizeof(errh->offender));
1680 break;
1681 }
1682 default:
1683 goto unimplemented;
1684 }
1685 break;
1686
1687 case SOL_IPV6:
1688 switch (cmsg->cmsg_type) {
1689 case IPV6_HOPLIMIT:
1690 {
1691 uint32_t *v = (uint32_t *)data;
1692 uint32_t *t_int = (uint32_t *)target_data;
1693
Peter Maydell71749702017-12-15 13:52:55 +00001694 if (len != sizeof(uint32_t) ||
1695 tgt_len != sizeof(uint32_t)) {
1696 goto unimplemented;
1697 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001698 __put_user(*v, t_int);
1699 break;
1700 }
1701 case IPV6_RECVERR:
1702 {
1703 struct errhdr6_t {
1704 struct sock_extended_err ee;
1705 struct sockaddr_in6 offender;
1706 };
1707 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1708 struct errhdr6_t *target_errh =
1709 (struct errhdr6_t *)target_data;
1710
Peter Maydell71749702017-12-15 13:52:55 +00001711 if (len != sizeof(struct errhdr6_t) ||
1712 tgt_len != sizeof(struct errhdr6_t)) {
1713 goto unimplemented;
1714 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001715 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1716 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1717 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1718 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1719 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1720 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1721 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1722 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1723 (void *) &errh->offender, sizeof(errh->offender));
1724 break;
1725 }
1726 default:
1727 goto unimplemented;
1728 }
1729 break;
1730
Huw Davies52b65492014-04-17 14:02:47 +01001731 default:
1732 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001733 gemu_log("Unsupported ancillary data: %d/%d\n",
1734 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001735 memcpy(target_data, data, MIN(len, tgt_len));
1736 if (tgt_len > len) {
1737 memset(target_data + len, 0, tgt_len - len);
1738 }
bellard7854b052003-03-29 17:22:23 +00001739 }
1740
Peter Maydell71749702017-12-15 13:52:55 +00001741 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
1742 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001743 if (msg_controllen < tgt_space) {
1744 tgt_space = msg_controllen;
1745 }
1746 msg_controllen -= tgt_space;
1747 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001748 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001749 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1750 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001751 }
bellard5a4a8982007-11-11 17:39:18 +00001752 unlock_user(target_cmsg, target_cmsg_addr, space);
1753 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001754 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001755 return 0;
bellard7854b052003-03-29 17:22:23 +00001756}
1757
ths0da46a62007-10-20 20:23:07 +00001758/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001759static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001760 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001761{
blueswir1992f48a2007-10-14 16:27:31 +00001762 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001763 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001764 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001765 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001766
bellard8853f862004-02-22 14:57:26 +00001767 switch(level) {
1768 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001769 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001770 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001771 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001772
bellard2f619692007-11-16 10:46:05 +00001773 if (get_user_u32(val, optval_addr))
1774 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001775 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1776 break;
1777 case SOL_IP:
1778 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001779 case IP_TOS:
1780 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001781 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001782 case IP_ROUTER_ALERT:
1783 case IP_RECVOPTS:
1784 case IP_RETOPTS:
1785 case IP_PKTINFO:
1786 case IP_MTU_DISCOVER:
1787 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01001788 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00001789 case IP_RECVTOS:
1790#ifdef IP_FREEBIND
1791 case IP_FREEBIND:
1792#endif
1793 case IP_MULTICAST_TTL:
1794 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001795 val = 0;
1796 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001797 if (get_user_u32(val, optval_addr))
1798 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001799 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001800 if (get_user_u8(val, optval_addr))
1801 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001802 }
1803 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1804 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001805 case IP_ADD_MEMBERSHIP:
1806 case IP_DROP_MEMBERSHIP:
1807 if (optlen < sizeof (struct target_ip_mreq) ||
1808 optlen > sizeof (struct target_ip_mreqn))
1809 return -TARGET_EINVAL;
1810
1811 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1812 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1813 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1814 break;
1815
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001816 case IP_BLOCK_SOURCE:
1817 case IP_UNBLOCK_SOURCE:
1818 case IP_ADD_SOURCE_MEMBERSHIP:
1819 case IP_DROP_SOURCE_MEMBERSHIP:
1820 if (optlen != sizeof (struct target_ip_mreq_source))
1821 return -TARGET_EINVAL;
1822
1823 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1824 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1825 unlock_user (ip_mreq_source, optval_addr, 0);
1826 break;
1827
bellard8853f862004-02-22 14:57:26 +00001828 default:
1829 goto unimplemented;
1830 }
1831 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001832 case SOL_IPV6:
1833 switch (optname) {
1834 case IPV6_MTU_DISCOVER:
1835 case IPV6_MTU:
1836 case IPV6_V6ONLY:
1837 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01001838 case IPV6_UNICAST_HOPS:
Laurent Vivier21749c42018-06-27 23:21:52 +02001839 case IPV6_MULTICAST_HOPS:
1840 case IPV6_MULTICAST_LOOP:
Helge Delleree1ac3a2017-02-18 23:31:30 +01001841 case IPV6_RECVERR:
1842 case IPV6_RECVHOPLIMIT:
1843 case IPV6_2292HOPLIMIT:
1844 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01001845 case IPV6_ADDRFORM:
1846 case IPV6_2292PKTINFO:
1847 case IPV6_RECVTCLASS:
1848 case IPV6_RECVRTHDR:
1849 case IPV6_2292RTHDR:
1850 case IPV6_RECVHOPOPTS:
1851 case IPV6_2292HOPOPTS:
1852 case IPV6_RECVDSTOPTS:
1853 case IPV6_2292DSTOPTS:
1854 case IPV6_TCLASS:
1855#ifdef IPV6_RECVPATHMTU
1856 case IPV6_RECVPATHMTU:
1857#endif
1858#ifdef IPV6_TRANSPARENT
1859 case IPV6_TRANSPARENT:
1860#endif
1861#ifdef IPV6_FREEBIND
1862 case IPV6_FREEBIND:
1863#endif
1864#ifdef IPV6_RECVORIGDSTADDR
1865 case IPV6_RECVORIGDSTADDR:
1866#endif
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001867 val = 0;
1868 if (optlen < sizeof(uint32_t)) {
1869 return -TARGET_EINVAL;
1870 }
1871 if (get_user_u32(val, optval_addr)) {
1872 return -TARGET_EFAULT;
1873 }
1874 ret = get_errno(setsockopt(sockfd, level, optname,
1875 &val, sizeof(val)));
1876 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01001877 case IPV6_PKTINFO:
1878 {
1879 struct in6_pktinfo pki;
1880
1881 if (optlen < sizeof(pki)) {
1882 return -TARGET_EINVAL;
1883 }
1884
1885 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
1886 return -TARGET_EFAULT;
1887 }
1888
1889 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
1890
1891 ret = get_errno(setsockopt(sockfd, level, optname,
1892 &pki, sizeof(pki)));
1893 break;
1894 }
1895 default:
1896 goto unimplemented;
1897 }
1898 break;
1899 case SOL_ICMPV6:
1900 switch (optname) {
1901 case ICMPV6_FILTER:
1902 {
1903 struct icmp6_filter icmp6f;
1904
1905 if (optlen > sizeof(icmp6f)) {
1906 optlen = sizeof(icmp6f);
1907 }
1908
1909 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
1910 return -TARGET_EFAULT;
1911 }
1912
1913 for (val = 0; val < 8; val++) {
1914 icmp6f.data[val] = tswap32(icmp6f.data[val]);
1915 }
1916
1917 ret = get_errno(setsockopt(sockfd, level, optname,
1918 &icmp6f, optlen));
1919 break;
1920 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001921 default:
1922 goto unimplemented;
1923 }
1924 break;
Jing Huang920394d2012-07-24 13:59:23 +00001925 case SOL_RAW:
1926 switch (optname) {
1927 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01001928 case IPV6_CHECKSUM:
1929 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00001930 if (optlen < sizeof(uint32_t)) {
1931 return -TARGET_EINVAL;
1932 }
1933
1934 if (get_user_u32(val, optval_addr)) {
1935 return -TARGET_EFAULT;
1936 }
1937 ret = get_errno(setsockopt(sockfd, level, optname,
1938 &val, sizeof(val)));
1939 break;
1940
1941 default:
1942 goto unimplemented;
1943 }
1944 break;
Yunqiang Suf31dddd2019-06-19 16:17:11 +02001945#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE)
1946 case SOL_ALG:
1947 switch (optname) {
1948 case ALG_SET_KEY:
1949 {
1950 char *alg_key = g_malloc(optlen);
1951
1952 if (!alg_key) {
1953 return -TARGET_ENOMEM;
1954 }
1955 if (copy_from_user(alg_key, optval_addr, optlen)) {
1956 g_free(alg_key);
1957 return -TARGET_EFAULT;
1958 }
1959 ret = get_errno(setsockopt(sockfd, level, optname,
1960 alg_key, optlen));
1961 g_free(alg_key);
1962 break;
1963 }
1964 case ALG_SET_AEAD_AUTHSIZE:
1965 {
1966 ret = get_errno(setsockopt(sockfd, level, optname,
1967 NULL, optlen));
1968 break;
1969 }
1970 default:
1971 goto unimplemented;
1972 }
1973 break;
1974#endif
bellard3532fa72006-06-24 15:06:03 +00001975 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001976 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001977 case TARGET_SO_RCVTIMEO:
1978 {
1979 struct timeval tv;
1980
1981 optname = SO_RCVTIMEO;
1982
1983set_timeout:
1984 if (optlen != sizeof(struct target_timeval)) {
1985 return -TARGET_EINVAL;
1986 }
1987
1988 if (copy_from_user_timeval(&tv, optval_addr)) {
1989 return -TARGET_EFAULT;
1990 }
1991
1992 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1993 &tv, sizeof(tv)));
1994 return ret;
1995 }
1996 case TARGET_SO_SNDTIMEO:
1997 optname = SO_SNDTIMEO;
1998 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001999 case TARGET_SO_ATTACH_FILTER:
2000 {
2001 struct target_sock_fprog *tfprog;
2002 struct target_sock_filter *tfilter;
2003 struct sock_fprog fprog;
2004 struct sock_filter *filter;
2005 int i;
2006
2007 if (optlen != sizeof(*tfprog)) {
2008 return -TARGET_EINVAL;
2009 }
2010 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2011 return -TARGET_EFAULT;
2012 }
2013 if (!lock_user_struct(VERIFY_READ, tfilter,
2014 tswapal(tfprog->filter), 0)) {
2015 unlock_user_struct(tfprog, optval_addr, 1);
2016 return -TARGET_EFAULT;
2017 }
2018
2019 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302020 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002021 if (filter == NULL) {
2022 unlock_user_struct(tfilter, tfprog->filter, 1);
2023 unlock_user_struct(tfprog, optval_addr, 1);
2024 return -TARGET_ENOMEM;
2025 }
2026 for (i = 0; i < fprog.len; i++) {
2027 filter[i].code = tswap16(tfilter[i].code);
2028 filter[i].jt = tfilter[i].jt;
2029 filter[i].jf = tfilter[i].jf;
2030 filter[i].k = tswap32(tfilter[i].k);
2031 }
2032 fprog.filter = filter;
2033
2034 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2035 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302036 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002037
2038 unlock_user_struct(tfilter, tfprog->filter, 1);
2039 unlock_user_struct(tfprog, optval_addr, 1);
2040 return ret;
2041 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002042 case TARGET_SO_BINDTODEVICE:
2043 {
2044 char *dev_ifname, *addr_ifname;
2045
2046 if (optlen > IFNAMSIZ - 1) {
2047 optlen = IFNAMSIZ - 1;
2048 }
2049 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2050 if (!dev_ifname) {
2051 return -TARGET_EFAULT;
2052 }
2053 optname = SO_BINDTODEVICE;
2054 addr_ifname = alloca(IFNAMSIZ);
2055 memcpy(addr_ifname, dev_ifname, optlen);
2056 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002057 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2058 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002059 unlock_user (dev_ifname, optval_addr, 0);
2060 return ret;
2061 }
Carlo Marcelo Arenas Belón83eb6e52018-08-24 01:56:01 -07002062 case TARGET_SO_LINGER:
2063 {
2064 struct linger lg;
2065 struct target_linger *tlg;
2066
2067 if (optlen != sizeof(struct target_linger)) {
2068 return -TARGET_EINVAL;
2069 }
2070 if (!lock_user_struct(VERIFY_READ, tlg, optval_addr, 1)) {
2071 return -TARGET_EFAULT;
2072 }
2073 __get_user(lg.l_onoff, &tlg->l_onoff);
2074 __get_user(lg.l_linger, &tlg->l_linger);
2075 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
2076 &lg, sizeof(lg)));
2077 unlock_user_struct(tlg, optval_addr, 0);
2078 return ret;
2079 }
bellard8853f862004-02-22 14:57:26 +00002080 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002081 case TARGET_SO_DEBUG:
2082 optname = SO_DEBUG;
2083 break;
2084 case TARGET_SO_REUSEADDR:
2085 optname = SO_REUSEADDR;
2086 break;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002087#ifdef SO_REUSEPORT
2088 case TARGET_SO_REUSEPORT:
2089 optname = SO_REUSEPORT;
2090 break;
2091#endif
bellard3532fa72006-06-24 15:06:03 +00002092 case TARGET_SO_TYPE:
2093 optname = SO_TYPE;
2094 break;
2095 case TARGET_SO_ERROR:
2096 optname = SO_ERROR;
2097 break;
2098 case TARGET_SO_DONTROUTE:
2099 optname = SO_DONTROUTE;
2100 break;
2101 case TARGET_SO_BROADCAST:
2102 optname = SO_BROADCAST;
2103 break;
2104 case TARGET_SO_SNDBUF:
2105 optname = SO_SNDBUF;
2106 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002107 case TARGET_SO_SNDBUFFORCE:
2108 optname = SO_SNDBUFFORCE;
2109 break;
bellard3532fa72006-06-24 15:06:03 +00002110 case TARGET_SO_RCVBUF:
2111 optname = SO_RCVBUF;
2112 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002113 case TARGET_SO_RCVBUFFORCE:
2114 optname = SO_RCVBUFFORCE;
2115 break;
bellard3532fa72006-06-24 15:06:03 +00002116 case TARGET_SO_KEEPALIVE:
2117 optname = SO_KEEPALIVE;
2118 break;
2119 case TARGET_SO_OOBINLINE:
2120 optname = SO_OOBINLINE;
2121 break;
2122 case TARGET_SO_NO_CHECK:
2123 optname = SO_NO_CHECK;
2124 break;
2125 case TARGET_SO_PRIORITY:
2126 optname = SO_PRIORITY;
2127 break;
bellard5e83e8e2005-03-01 22:32:06 +00002128#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002129 case TARGET_SO_BSDCOMPAT:
2130 optname = SO_BSDCOMPAT;
2131 break;
bellard5e83e8e2005-03-01 22:32:06 +00002132#endif
bellard3532fa72006-06-24 15:06:03 +00002133 case TARGET_SO_PASSCRED:
2134 optname = SO_PASSCRED;
2135 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002136 case TARGET_SO_PASSSEC:
2137 optname = SO_PASSSEC;
2138 break;
bellard3532fa72006-06-24 15:06:03 +00002139 case TARGET_SO_TIMESTAMP:
2140 optname = SO_TIMESTAMP;
2141 break;
2142 case TARGET_SO_RCVLOWAT:
2143 optname = SO_RCVLOWAT;
2144 break;
bellard8853f862004-02-22 14:57:26 +00002145 default:
2146 goto unimplemented;
2147 }
bellard3532fa72006-06-24 15:06:03 +00002148 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002149 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002150
bellard2f619692007-11-16 10:46:05 +00002151 if (get_user_u32(val, optval_addr))
2152 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002153 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002154 break;
bellard7854b052003-03-29 17:22:23 +00002155 default:
bellard8853f862004-02-22 14:57:26 +00002156 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002157 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002158 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002159 }
bellard8853f862004-02-22 14:57:26 +00002160 return ret;
bellard7854b052003-03-29 17:22:23 +00002161}
2162
ths0da46a62007-10-20 20:23:07 +00002163/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002164static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002165 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002166{
blueswir1992f48a2007-10-14 16:27:31 +00002167 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002168 int len, val;
2169 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002170
2171 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002172 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002173 level = SOL_SOCKET;
2174 switch (optname) {
2175 /* These don't just return a single integer */
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002176 case TARGET_SO_RCVTIMEO:
2177 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002178 case TARGET_SO_PEERNAME:
2179 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002180 case TARGET_SO_PEERCRED: {
2181 struct ucred cr;
2182 socklen_t crlen;
2183 struct target_ucred *tcr;
2184
2185 if (get_user_u32(len, optlen)) {
2186 return -TARGET_EFAULT;
2187 }
2188 if (len < 0) {
2189 return -TARGET_EINVAL;
2190 }
2191
2192 crlen = sizeof(cr);
2193 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2194 &cr, &crlen));
2195 if (ret < 0) {
2196 return ret;
2197 }
2198 if (len > crlen) {
2199 len = crlen;
2200 }
2201 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2202 return -TARGET_EFAULT;
2203 }
2204 __put_user(cr.pid, &tcr->pid);
2205 __put_user(cr.uid, &tcr->uid);
2206 __put_user(cr.gid, &tcr->gid);
2207 unlock_user_struct(tcr, optval_addr, 1);
2208 if (put_user_u32(len, optlen)) {
2209 return -TARGET_EFAULT;
2210 }
2211 break;
2212 }
Carlo Marcelo Arenas Belón83eb6e52018-08-24 01:56:01 -07002213 case TARGET_SO_LINGER:
2214 {
2215 struct linger lg;
2216 socklen_t lglen;
2217 struct target_linger *tlg;
2218
2219 if (get_user_u32(len, optlen)) {
2220 return -TARGET_EFAULT;
2221 }
2222 if (len < 0) {
2223 return -TARGET_EINVAL;
2224 }
2225
2226 lglen = sizeof(lg);
2227 ret = get_errno(getsockopt(sockfd, level, SO_LINGER,
2228 &lg, &lglen));
2229 if (ret < 0) {
2230 return ret;
2231 }
2232 if (len > lglen) {
2233 len = lglen;
2234 }
2235 if (!lock_user_struct(VERIFY_WRITE, tlg, optval_addr, 0)) {
2236 return -TARGET_EFAULT;
2237 }
2238 __put_user(lg.l_onoff, &tlg->l_onoff);
2239 __put_user(lg.l_linger, &tlg->l_linger);
2240 unlock_user_struct(tlg, optval_addr, 1);
2241 if (put_user_u32(len, optlen)) {
2242 return -TARGET_EFAULT;
2243 }
2244 break;
2245 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002246 /* Options with 'int' argument. */
2247 case TARGET_SO_DEBUG:
2248 optname = SO_DEBUG;
2249 goto int_case;
2250 case TARGET_SO_REUSEADDR:
2251 optname = SO_REUSEADDR;
2252 goto int_case;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002253#ifdef SO_REUSEPORT
2254 case TARGET_SO_REUSEPORT:
2255 optname = SO_REUSEPORT;
2256 goto int_case;
2257#endif
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002258 case TARGET_SO_TYPE:
2259 optname = SO_TYPE;
2260 goto int_case;
2261 case TARGET_SO_ERROR:
2262 optname = SO_ERROR;
2263 goto int_case;
2264 case TARGET_SO_DONTROUTE:
2265 optname = SO_DONTROUTE;
2266 goto int_case;
2267 case TARGET_SO_BROADCAST:
2268 optname = SO_BROADCAST;
2269 goto int_case;
2270 case TARGET_SO_SNDBUF:
2271 optname = SO_SNDBUF;
2272 goto int_case;
2273 case TARGET_SO_RCVBUF:
2274 optname = SO_RCVBUF;
2275 goto int_case;
2276 case TARGET_SO_KEEPALIVE:
2277 optname = SO_KEEPALIVE;
2278 goto int_case;
2279 case TARGET_SO_OOBINLINE:
2280 optname = SO_OOBINLINE;
2281 goto int_case;
2282 case TARGET_SO_NO_CHECK:
2283 optname = SO_NO_CHECK;
2284 goto int_case;
2285 case TARGET_SO_PRIORITY:
2286 optname = SO_PRIORITY;
2287 goto int_case;
2288#ifdef SO_BSDCOMPAT
2289 case TARGET_SO_BSDCOMPAT:
2290 optname = SO_BSDCOMPAT;
2291 goto int_case;
2292#endif
2293 case TARGET_SO_PASSCRED:
2294 optname = SO_PASSCRED;
2295 goto int_case;
2296 case TARGET_SO_TIMESTAMP:
2297 optname = SO_TIMESTAMP;
2298 goto int_case;
2299 case TARGET_SO_RCVLOWAT:
2300 optname = SO_RCVLOWAT;
2301 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002302 case TARGET_SO_ACCEPTCONN:
2303 optname = SO_ACCEPTCONN;
2304 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002305 default:
bellard2efbe912005-07-23 15:10:20 +00002306 goto int_case;
2307 }
2308 break;
2309 case SOL_TCP:
2310 /* TCP options all take an 'int' value. */
2311 int_case:
bellard2f619692007-11-16 10:46:05 +00002312 if (get_user_u32(len, optlen))
2313 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002314 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002315 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002316 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002317 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2318 if (ret < 0)
2319 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002320 if (optname == SO_TYPE) {
2321 val = host_to_target_sock_type(val);
2322 }
bellard2efbe912005-07-23 15:10:20 +00002323 if (len > lv)
2324 len = lv;
bellard2f619692007-11-16 10:46:05 +00002325 if (len == 4) {
2326 if (put_user_u32(val, optval_addr))
2327 return -TARGET_EFAULT;
2328 } else {
2329 if (put_user_u8(val, optval_addr))
2330 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002331 }
bellard2f619692007-11-16 10:46:05 +00002332 if (put_user_u32(len, optlen))
2333 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002334 break;
2335 case SOL_IP:
2336 switch(optname) {
2337 case IP_TOS:
2338 case IP_TTL:
2339 case IP_HDRINCL:
2340 case IP_ROUTER_ALERT:
2341 case IP_RECVOPTS:
2342 case IP_RETOPTS:
2343 case IP_PKTINFO:
2344 case IP_MTU_DISCOVER:
2345 case IP_RECVERR:
2346 case IP_RECVTOS:
2347#ifdef IP_FREEBIND
2348 case IP_FREEBIND:
2349#endif
2350 case IP_MULTICAST_TTL:
2351 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002352 if (get_user_u32(len, optlen))
2353 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002354 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002355 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002356 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002357 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2358 if (ret < 0)
2359 return ret;
bellard2efbe912005-07-23 15:10:20 +00002360 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002361 len = 1;
bellard2f619692007-11-16 10:46:05 +00002362 if (put_user_u32(len, optlen)
2363 || put_user_u8(val, optval_addr))
2364 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002365 } else {
bellard2efbe912005-07-23 15:10:20 +00002366 if (len > sizeof(int))
2367 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002368 if (put_user_u32(len, optlen)
2369 || put_user_u32(val, optval_addr))
2370 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002371 }
bellard8853f862004-02-22 14:57:26 +00002372 break;
bellard2efbe912005-07-23 15:10:20 +00002373 default:
thsc02f4992007-12-18 02:39:59 +00002374 ret = -TARGET_ENOPROTOOPT;
2375 break;
bellard8853f862004-02-22 14:57:26 +00002376 }
2377 break;
Tom Deseynbd8ed482018-12-13 14:06:11 +01002378 case SOL_IPV6:
2379 switch (optname) {
2380 case IPV6_MTU_DISCOVER:
2381 case IPV6_MTU:
2382 case IPV6_V6ONLY:
2383 case IPV6_RECVPKTINFO:
2384 case IPV6_UNICAST_HOPS:
2385 case IPV6_MULTICAST_HOPS:
2386 case IPV6_MULTICAST_LOOP:
2387 case IPV6_RECVERR:
2388 case IPV6_RECVHOPLIMIT:
2389 case IPV6_2292HOPLIMIT:
2390 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002391 case IPV6_ADDRFORM:
2392 case IPV6_2292PKTINFO:
2393 case IPV6_RECVTCLASS:
2394 case IPV6_RECVRTHDR:
2395 case IPV6_2292RTHDR:
2396 case IPV6_RECVHOPOPTS:
2397 case IPV6_2292HOPOPTS:
2398 case IPV6_RECVDSTOPTS:
2399 case IPV6_2292DSTOPTS:
2400 case IPV6_TCLASS:
2401#ifdef IPV6_RECVPATHMTU
2402 case IPV6_RECVPATHMTU:
2403#endif
2404#ifdef IPV6_TRANSPARENT
2405 case IPV6_TRANSPARENT:
2406#endif
2407#ifdef IPV6_FREEBIND
2408 case IPV6_FREEBIND:
2409#endif
2410#ifdef IPV6_RECVORIGDSTADDR
2411 case IPV6_RECVORIGDSTADDR:
2412#endif
Tom Deseynbd8ed482018-12-13 14:06:11 +01002413 if (get_user_u32(len, optlen))
2414 return -TARGET_EFAULT;
2415 if (len < 0)
2416 return -TARGET_EINVAL;
2417 lv = sizeof(lv);
2418 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2419 if (ret < 0)
2420 return ret;
2421 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
2422 len = 1;
2423 if (put_user_u32(len, optlen)
2424 || put_user_u8(val, optval_addr))
2425 return -TARGET_EFAULT;
2426 } else {
2427 if (len > sizeof(int))
2428 len = sizeof(int);
2429 if (put_user_u32(len, optlen)
2430 || put_user_u32(val, optval_addr))
2431 return -TARGET_EFAULT;
2432 }
2433 break;
2434 default:
2435 ret = -TARGET_ENOPROTOOPT;
2436 break;
2437 }
2438 break;
bellard8853f862004-02-22 14:57:26 +00002439 default:
2440 unimplemented:
2441 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2442 level, optname);
thsc02f4992007-12-18 02:39:59 +00002443 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002444 break;
2445 }
2446 return ret;
bellard7854b052003-03-29 17:22:23 +00002447}
2448
Max Filippov9ac22512018-04-04 17:30:41 -07002449/* Convert target low/high pair representing file offset into the host
2450 * low/high pair. This function doesn't handle offsets bigger than 64 bits
2451 * as the kernel doesn't handle them either.
2452 */
2453static void target_to_host_low_high(abi_ulong tlow,
2454 abi_ulong thigh,
2455 unsigned long *hlow,
2456 unsigned long *hhigh)
2457{
2458 uint64_t off = tlow |
2459 ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
2460 TARGET_LONG_BITS / 2;
2461
2462 *hlow = off;
2463 *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
2464}
2465
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002466static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01002467 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002468{
2469 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002470 struct iovec *vec;
2471 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002472 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002473 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002474 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002475
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002476 if (count == 0) {
2477 errno = 0;
2478 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002479 }
Peter Maydelldab32b32016-07-15 14:57:26 +01002480 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002481 errno = EINVAL;
2482 return NULL;
2483 }
2484
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302485 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002486 if (vec == NULL) {
2487 errno = ENOMEM;
2488 return NULL;
2489 }
2490
2491 target_vec = lock_user(VERIFY_READ, target_addr,
2492 count * sizeof(struct target_iovec), 1);
2493 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002494 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002495 goto fail2;
2496 }
2497
2498 /* ??? If host page size > target page size, this will result in a
2499 value larger than what we can actually support. */
2500 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2501 total_len = 0;
2502
2503 for (i = 0; i < count; i++) {
2504 abi_ulong base = tswapal(target_vec[i].iov_base);
2505 abi_long len = tswapal(target_vec[i].iov_len);
2506
2507 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002508 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002509 goto fail;
2510 } else if (len == 0) {
2511 /* Zero length pointer is ignored. */
2512 vec[i].iov_base = 0;
2513 } else {
2514 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002515 /* If the first buffer pointer is bad, this is a fault. But
2516 * subsequent bad buffers will result in a partial write; this
2517 * is realized by filling the vector with null pointers and
2518 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002519 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002520 if (i == 0) {
2521 err = EFAULT;
2522 goto fail;
2523 } else {
2524 bad_address = true;
2525 }
2526 }
2527 if (bad_address) {
2528 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002529 }
2530 if (len > max_len - total_len) {
2531 len = max_len - total_len;
2532 }
2533 }
2534 vec[i].iov_len = len;
2535 total_len += len;
2536 }
2537
2538 unlock_user(target_vec, target_addr, 0);
2539 return vec;
2540
2541 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002542 while (--i >= 0) {
2543 if (tswapal(target_vec[i].iov_len) > 0) {
2544 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2545 }
2546 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002547 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002548 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302549 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002550 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002551 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002552}
2553
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002554static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01002555 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002556{
2557 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002558 int i;
2559
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002560 target_vec = lock_user(VERIFY_READ, target_addr,
2561 count * sizeof(struct target_iovec), 1);
2562 if (target_vec) {
2563 for (i = 0; i < count; i++) {
2564 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002565 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002566 if (len < 0) {
2567 break;
2568 }
balrogd732dcb2008-10-28 10:21:03 +00002569 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2570 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002571 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002572 }
bellard579a97f2007-11-11 14:26:47 +00002573
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302574 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002575}
2576
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002577static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002578{
2579 int host_type = 0;
2580 int target_type = *type;
2581
2582 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2583 case TARGET_SOCK_DGRAM:
2584 host_type = SOCK_DGRAM;
2585 break;
2586 case TARGET_SOCK_STREAM:
2587 host_type = SOCK_STREAM;
2588 break;
2589 default:
2590 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2591 break;
2592 }
2593 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002594#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002595 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002596#else
2597 return -TARGET_EINVAL;
2598#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002599 }
2600 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002601#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002602 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002603#elif !defined(O_NONBLOCK)
2604 return -TARGET_EINVAL;
2605#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002606 }
2607 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002608 return 0;
2609}
2610
2611/* Try to emulate socket type flags after socket creation. */
2612static int sock_flags_fixup(int fd, int target_type)
2613{
2614#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2615 if (target_type & TARGET_SOCK_NONBLOCK) {
2616 int flags = fcntl(fd, F_GETFL);
2617 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2618 close(fd);
2619 return -TARGET_EINVAL;
2620 }
2621 }
2622#endif
2623 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002624}
2625
ths0da46a62007-10-20 20:23:07 +00002626/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002627static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002628{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002629 int target_type = type;
2630 int ret;
2631
2632 ret = target_to_host_sock_type(&type);
2633 if (ret) {
2634 return ret;
2635 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002636
Laurent Vivier575b22b2016-06-02 22:14:15 +02002637 if (domain == PF_NETLINK && !(
2638#ifdef CONFIG_RTNETLINK
2639 protocol == NETLINK_ROUTE ||
2640#endif
2641 protocol == NETLINK_KOBJECT_UEVENT ||
2642 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002643 return -EPFNOSUPPORT;
2644 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002645
2646 if (domain == AF_PACKET ||
2647 (domain == AF_INET && type == SOCK_PACKET)) {
2648 protocol = tswap16(protocol);
2649 }
2650
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002651 ret = get_errno(socket(domain, type, protocol));
2652 if (ret >= 0) {
2653 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002654 if (type == SOCK_PACKET) {
2655 /* Manage an obsolete case :
2656 * if socket type is SOCK_PACKET, bind by name
2657 */
2658 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002659 } else if (domain == PF_NETLINK) {
2660 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002661#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002662 case NETLINK_ROUTE:
2663 fd_trans_register(ret, &target_netlink_route_trans);
2664 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002665#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002666 case NETLINK_KOBJECT_UEVENT:
2667 /* nothing to do: messages are strings */
2668 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002669 case NETLINK_AUDIT:
2670 fd_trans_register(ret, &target_netlink_audit_trans);
2671 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002672 default:
2673 g_assert_not_reached();
2674 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002675 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002676 }
2677 return ret;
bellard3532fa72006-06-24 15:06:03 +00002678}
2679
ths0da46a62007-10-20 20:23:07 +00002680/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002681static abi_long do_bind(int sockfd, abi_ulong target_addr,
2682 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002683{
aurel328f7aeaf2009-01-30 19:47:57 +00002684 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002685 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002686
Blue Swirl38724252010-09-18 05:53:14 +00002687 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002688 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002689 }
aurel328f7aeaf2009-01-30 19:47:57 +00002690
aurel32607175e2009-04-15 16:11:59 +00002691 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002692
Laurent Vivier7b36f782015-10-28 21:40:44 +01002693 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002694 if (ret)
2695 return ret;
2696
bellard3532fa72006-06-24 15:06:03 +00002697 return get_errno(bind(sockfd, addr, addrlen));
2698}
2699
ths0da46a62007-10-20 20:23:07 +00002700/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002701static abi_long do_connect(int sockfd, abi_ulong target_addr,
2702 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002703{
aurel328f7aeaf2009-01-30 19:47:57 +00002704 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002705 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002706
Blue Swirl38724252010-09-18 05:53:14 +00002707 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002708 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002709 }
aurel328f7aeaf2009-01-30 19:47:57 +00002710
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002711 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002712
Laurent Vivier7b36f782015-10-28 21:40:44 +01002713 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002714 if (ret)
2715 return ret;
2716
Peter Maydell2a3c7612016-06-06 19:58:03 +01002717 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002718}
2719
Alexander Graff19e00d2014-03-02 19:36:42 +00002720/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2721static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2722 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002723{
balrog6de645c2008-10-28 10:26:29 +00002724 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002725 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01002726 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00002727 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002728 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002729
bellard3532fa72006-06-24 15:06:03 +00002730 if (msgp->msg_name) {
2731 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002732 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002733 ret = target_to_host_sockaddr(fd, msg.msg_name,
2734 tswapal(msgp->msg_name),
2735 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01002736 if (ret == -TARGET_EFAULT) {
2737 /* For connected sockets msg_name and msg_namelen must
2738 * be ignored, so returning EFAULT immediately is wrong.
2739 * Instead, pass a bad msg_name to the host kernel, and
2740 * let it decide whether to return EFAULT or not.
2741 */
2742 msg.msg_name = (void *)-1;
2743 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002744 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002745 }
bellard3532fa72006-06-24 15:06:03 +00002746 } else {
2747 msg.msg_name = NULL;
2748 msg.msg_namelen = 0;
2749 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002750 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002751 msg.msg_control = alloca(msg.msg_controllen);
Jonas Schievink1d3d1b22018-07-12 00:12:44 +02002752 memset(msg.msg_control, 0, msg.msg_controllen);
2753
bellard3532fa72006-06-24 15:06:03 +00002754 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002755
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002756 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002757 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01002758
2759 if (count > IOV_MAX) {
2760 /* sendrcvmsg returns a different errno for this condition than
2761 * readv/writev, so we must catch it here before lock_iovec() does.
2762 */
2763 ret = -TARGET_EMSGSIZE;
2764 goto out2;
2765 }
2766
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002767 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2768 target_vec, count, send);
2769 if (vec == NULL) {
2770 ret = -host_to_target_errno(errno);
2771 goto out2;
2772 }
bellard3532fa72006-06-24 15:06:03 +00002773 msg.msg_iovlen = count;
2774 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002775
bellard3532fa72006-06-24 15:06:03 +00002776 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002777 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02002778 void *host_msg;
2779
2780 host_msg = g_malloc(msg.msg_iov->iov_len);
2781 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
2782 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002783 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02002784 if (ret >= 0) {
2785 msg.msg_iov->iov_base = host_msg;
2786 ret = get_errno(safe_sendmsg(fd, &msg, flags));
2787 }
2788 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002789 } else {
2790 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02002791 if (ret == 0) {
2792 ret = get_errno(safe_sendmsg(fd, &msg, flags));
2793 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002794 }
bellard3532fa72006-06-24 15:06:03 +00002795 } else {
Peter Maydell66687532016-06-06 19:58:04 +01002796 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002797 if (!is_error(ret)) {
2798 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002799 if (fd_trans_host_to_target_data(fd)) {
2800 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02002801 MIN(msg.msg_iov->iov_len, len));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002802 } else {
2803 ret = host_to_target_cmsg(msgp, &msg);
2804 }
Jing Huangca619062012-07-24 13:58:02 +00002805 if (!is_error(ret)) {
2806 msgp->msg_namelen = tswap32(msg.msg_namelen);
Andreas Schwab24894f32019-02-12 17:34:35 +01002807 msgp->msg_flags = tswap32(msg.msg_flags);
Peter Maydell26a6fc92016-07-15 14:57:28 +01002808 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00002809 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2810 msg.msg_name, msg.msg_namelen);
2811 if (ret) {
2812 goto out;
2813 }
2814 }
2815
balrog6de645c2008-10-28 10:26:29 +00002816 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002817 }
balrog6de645c2008-10-28 10:26:29 +00002818 }
bellard3532fa72006-06-24 15:06:03 +00002819 }
Jing Huangca619062012-07-24 13:58:02 +00002820
2821out:
bellard3532fa72006-06-24 15:06:03 +00002822 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002823out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002824 return ret;
2825}
2826
2827static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2828 int flags, int send)
2829{
2830 abi_long ret;
2831 struct target_msghdr *msgp;
2832
2833 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2834 msgp,
2835 target_msg,
2836 send ? 1 : 0)) {
2837 return -TARGET_EFAULT;
2838 }
2839 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002840 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002841 return ret;
2842}
2843
Alexander Graff19e00d2014-03-02 19:36:42 +00002844/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2845 * so it might not have this *mmsg-specific flag either.
2846 */
2847#ifndef MSG_WAITFORONE
2848#define MSG_WAITFORONE 0x10000
2849#endif
2850
2851static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2852 unsigned int vlen, unsigned int flags,
2853 int send)
2854{
2855 struct target_mmsghdr *mmsgp;
2856 abi_long ret = 0;
2857 int i;
2858
2859 if (vlen > UIO_MAXIOV) {
2860 vlen = UIO_MAXIOV;
2861 }
2862
2863 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2864 if (!mmsgp) {
2865 return -TARGET_EFAULT;
2866 }
2867
2868 for (i = 0; i < vlen; i++) {
2869 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2870 if (is_error(ret)) {
2871 break;
2872 }
2873 mmsgp[i].msg_len = tswap32(ret);
2874 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2875 if (flags & MSG_WAITFORONE) {
2876 flags |= MSG_DONTWAIT;
2877 }
2878 }
2879
2880 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2881
2882 /* Return number of datagrams sent if we sent any at all;
2883 * otherwise return the error.
2884 */
2885 if (i) {
2886 return i;
2887 }
2888 return ret;
2889}
Alexander Graff19e00d2014-03-02 19:36:42 +00002890
Peter Maydella94b4982013-02-08 04:35:04 +00002891/* do_accept4() Must return target values and target errnos. */
2892static abi_long do_accept4(int fd, abi_ulong target_addr,
2893 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002894{
Andreas Schwabcd813362019-02-14 12:43:40 +01002895 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00002896 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002897 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002898 int host_flags;
2899
2900 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002901
Peter Maydella94b4982013-02-08 04:35:04 +00002902 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01002903 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002904 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002905
2906 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002907 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002908 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002909
Blue Swirl38724252010-09-18 05:53:14 +00002910 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002911 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002912 }
aurel328f7aeaf2009-01-30 19:47:57 +00002913
Arnaud Patard917507b2009-06-19 10:44:45 +03002914 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2915 return -TARGET_EINVAL;
2916
bellard2f619692007-11-16 10:46:05 +00002917 addr = alloca(addrlen);
2918
Andreas Schwabcd813362019-02-14 12:43:40 +01002919 ret_addrlen = addrlen;
2920 ret = get_errno(safe_accept4(fd, addr, &ret_addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002921 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01002922 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
2923 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00002924 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01002925 }
pbrook1be9e1d2006-11-19 15:26:04 +00002926 }
2927 return ret;
2928}
2929
ths0da46a62007-10-20 20:23:07 +00002930/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002931static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002932 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002933{
Andreas Schwabcd813362019-02-14 12:43:40 +01002934 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00002935 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002936 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002937
bellard2f619692007-11-16 10:46:05 +00002938 if (get_user_u32(addrlen, target_addrlen_addr))
2939 return -TARGET_EFAULT;
2940
Blue Swirl38724252010-09-18 05:53:14 +00002941 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002942 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002943 }
aurel328f7aeaf2009-01-30 19:47:57 +00002944
Arnaud Patard917507b2009-06-19 10:44:45 +03002945 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2946 return -TARGET_EFAULT;
2947
bellard2f619692007-11-16 10:46:05 +00002948 addr = alloca(addrlen);
2949
Andreas Schwabcd813362019-02-14 12:43:40 +01002950 ret_addrlen = addrlen;
2951 ret = get_errno(getpeername(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00002952 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01002953 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
2954 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00002955 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01002956 }
pbrook1be9e1d2006-11-19 15:26:04 +00002957 }
2958 return ret;
2959}
2960
ths0da46a62007-10-20 20:23:07 +00002961/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002962static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002963 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002964{
Andreas Schwabcd813362019-02-14 12:43:40 +01002965 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00002966 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002967 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002968
bellard2f619692007-11-16 10:46:05 +00002969 if (get_user_u32(addrlen, target_addrlen_addr))
2970 return -TARGET_EFAULT;
2971
Blue Swirl38724252010-09-18 05:53:14 +00002972 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002973 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002974 }
aurel328f7aeaf2009-01-30 19:47:57 +00002975
Arnaud Patard917507b2009-06-19 10:44:45 +03002976 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2977 return -TARGET_EFAULT;
2978
bellard2f619692007-11-16 10:46:05 +00002979 addr = alloca(addrlen);
2980
Andreas Schwabcd813362019-02-14 12:43:40 +01002981 ret_addrlen = addrlen;
2982 ret = get_errno(getsockname(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00002983 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01002984 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
2985 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00002986 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01002987 }
pbrook1be9e1d2006-11-19 15:26:04 +00002988 }
2989 return ret;
2990}
2991
ths0da46a62007-10-20 20:23:07 +00002992/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002993static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002994 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002995{
2996 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002997 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002998
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002999 target_to_host_sock_type(&type);
3000
pbrook1be9e1d2006-11-19 15:26:04 +00003001 ret = get_errno(socketpair(domain, type, protocol, tab));
3002 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003003 if (put_user_s32(tab[0], target_tab_addr)
3004 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3005 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003006 }
3007 return ret;
3008}
3009
ths0da46a62007-10-20 20:23:07 +00003010/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003011static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3012 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003013{
3014 void *addr;
3015 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003016 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003017 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003018
Blue Swirl38724252010-09-18 05:53:14 +00003019 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003020 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003021 }
aurel328f7aeaf2009-01-30 19:47:57 +00003022
bellard579a97f2007-11-11 14:26:47 +00003023 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3024 if (!host_msg)
3025 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003026 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003027 copy_msg = host_msg;
3028 host_msg = g_malloc(len);
3029 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003030 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3031 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003032 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003033 }
3034 }
pbrook1be9e1d2006-11-19 15:26:04 +00003035 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003036 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003037 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003038 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003039 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003040 }
Peter Maydell66687532016-06-06 19:58:04 +01003041 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003042 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003043 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003044 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003045fail:
3046 if (copy_msg) {
3047 g_free(host_msg);
3048 host_msg = copy_msg;
3049 }
pbrook1be9e1d2006-11-19 15:26:04 +00003050 unlock_user(host_msg, msg, 0);
3051 return ret;
3052}
3053
ths0da46a62007-10-20 20:23:07 +00003054/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003055static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3056 abi_ulong target_addr,
3057 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003058{
Andreas Schwabcd813362019-02-14 12:43:40 +01003059 socklen_t addrlen, ret_addrlen;
pbrook1be9e1d2006-11-19 15:26:04 +00003060 void *addr;
3061 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003062 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003063
bellard579a97f2007-11-11 14:26:47 +00003064 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3065 if (!host_msg)
3066 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003067 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003068 if (get_user_u32(addrlen, target_addrlen)) {
3069 ret = -TARGET_EFAULT;
3070 goto fail;
3071 }
Blue Swirl38724252010-09-18 05:53:14 +00003072 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003073 ret = -TARGET_EINVAL;
3074 goto fail;
3075 }
pbrook1be9e1d2006-11-19 15:26:04 +00003076 addr = alloca(addrlen);
Andreas Schwabcd813362019-02-14 12:43:40 +01003077 ret_addrlen = addrlen;
Peter Maydell66687532016-06-06 19:58:04 +01003078 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
Andreas Schwabcd813362019-02-14 12:43:40 +01003079 addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003080 } else {
3081 addr = NULL; /* To keep compiler quiet. */
Andreas Schwabcd813362019-02-14 12:43:40 +01003082 addrlen = 0; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003083 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003084 }
3085 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003086 if (fd_trans_host_to_target_data(fd)) {
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02003087 abi_long trans;
3088 trans = fd_trans_host_to_target_data(fd)(host_msg, MIN(ret, len));
3089 if (is_error(trans)) {
3090 ret = trans;
3091 goto fail;
3092 }
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003093 }
pbrook1be9e1d2006-11-19 15:26:04 +00003094 if (target_addr) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003095 host_to_target_sockaddr(target_addr, addr,
3096 MIN(addrlen, ret_addrlen));
3097 if (put_user_u32(ret_addrlen, target_addrlen)) {
bellard2f619692007-11-16 10:46:05 +00003098 ret = -TARGET_EFAULT;
3099 goto fail;
3100 }
pbrook1be9e1d2006-11-19 15:26:04 +00003101 }
3102 unlock_user(host_msg, msg, len);
3103 } else {
bellard2f619692007-11-16 10:46:05 +00003104fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003105 unlock_user(host_msg, msg, 0);
3106 }
3107 return ret;
3108}
3109
j_mayer32407102007-09-26 23:01:49 +00003110#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003111/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003112static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003113{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003114 static const unsigned nargs[] = { /* number of arguments per operation */
3115 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
3116 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
3117 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
3118 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
3119 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
3120 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
3121 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
3122 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
3123 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
3124 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
3125 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
3126 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
3127 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
3128 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3129 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3130 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
3131 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
3132 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
3133 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
3134 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003135 };
3136 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003137 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00003138
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003139 /* check the range of the first argument num */
3140 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
3141 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
3142 return -TARGET_EINVAL;
3143 }
3144 /* ensure we have space for args */
3145 if (nargs[num] > ARRAY_SIZE(a)) {
3146 return -TARGET_EINVAL;
3147 }
3148 /* collect the arguments in a[] according to nargs[] */
3149 for (i = 0; i < nargs[num]; ++i) {
3150 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
3151 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01003152 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003153 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003154 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003155 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003156 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003157 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003158 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003159 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003160 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003161 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003162 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003163 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003164 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003165 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003166 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003167 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003168 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003169 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003170 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003171 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003172 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003173 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003174 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003175 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003176 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003177 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003178 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003179 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003180 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003181 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003182 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003183 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003184 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003185 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003186 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
3187 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3188 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
3189 return do_sendrecvmsg(a[0], a[1], a[2], 0);
3190 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
3191 return do_accept4(a[0], a[1], a[2], a[3]);
3192 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
3193 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
3194 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
3195 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00003196 default:
3197 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003198 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00003199 }
bellard31e31b82003-02-18 22:55:36 +00003200}
j_mayer32407102007-09-26 23:01:49 +00003201#endif
bellard31e31b82003-02-18 22:55:36 +00003202
bellard8853f862004-02-22 14:57:26 +00003203#define N_SHM_REGIONS 32
3204
3205static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003206 abi_ulong start;
3207 abi_ulong size;
3208 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003209} shm_regions[N_SHM_REGIONS];
3210
Peter Maydell005eb2a2016-07-15 16:50:47 +01003211#ifndef TARGET_SEMID64_DS
3212/* asm-generic version of this struct */
3213struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00003214{
3215 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003216 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003217#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003218 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003219#endif
blueswir1992f48a2007-10-14 16:27:31 +00003220 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003221#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003222 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003223#endif
blueswir1992f48a2007-10-14 16:27:31 +00003224 abi_ulong sem_nsems;
3225 abi_ulong __unused3;
3226 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003227};
Peter Maydell005eb2a2016-07-15 16:50:47 +01003228#endif
ths3eb6b042007-06-03 14:26:27 +00003229
bellard579a97f2007-11-11 14:26:47 +00003230static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3231 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003232{
3233 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003234 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003235
bellard579a97f2007-11-11 14:26:47 +00003236 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3237 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003238 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003239 host_ip->__key = tswap32(target_ip->__key);
3240 host_ip->uid = tswap32(target_ip->uid);
3241 host_ip->gid = tswap32(target_ip->gid);
3242 host_ip->cuid = tswap32(target_ip->cuid);
3243 host_ip->cgid = tswap32(target_ip->cgid);
3244#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3245 host_ip->mode = tswap32(target_ip->mode);
3246#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003247 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003248#endif
3249#if defined(TARGET_PPC)
3250 host_ip->__seq = tswap32(target_ip->__seq);
3251#else
3252 host_ip->__seq = tswap16(target_ip->__seq);
3253#endif
ths3eb6b042007-06-03 14:26:27 +00003254 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003255 return 0;
ths3eb6b042007-06-03 14:26:27 +00003256}
3257
bellard579a97f2007-11-11 14:26:47 +00003258static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3259 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003260{
3261 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003262 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003263
bellard579a97f2007-11-11 14:26:47 +00003264 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3265 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003266 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003267 target_ip->__key = tswap32(host_ip->__key);
3268 target_ip->uid = tswap32(host_ip->uid);
3269 target_ip->gid = tswap32(host_ip->gid);
3270 target_ip->cuid = tswap32(host_ip->cuid);
3271 target_ip->cgid = tswap32(host_ip->cgid);
3272#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3273 target_ip->mode = tswap32(host_ip->mode);
3274#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003275 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003276#endif
3277#if defined(TARGET_PPC)
3278 target_ip->__seq = tswap32(host_ip->__seq);
3279#else
3280 target_ip->__seq = tswap16(host_ip->__seq);
3281#endif
ths3eb6b042007-06-03 14:26:27 +00003282 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003283 return 0;
ths3eb6b042007-06-03 14:26:27 +00003284}
3285
bellard579a97f2007-11-11 14:26:47 +00003286static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3287 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003288{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003289 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003290
bellard579a97f2007-11-11 14:26:47 +00003291 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3292 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003293 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3294 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003295 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3296 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3297 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003298 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003299 return 0;
ths3eb6b042007-06-03 14:26:27 +00003300}
3301
bellard579a97f2007-11-11 14:26:47 +00003302static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3303 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003304{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003305 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003306
bellard579a97f2007-11-11 14:26:47 +00003307 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3308 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003309 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003310 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003311 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3312 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3313 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003314 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003315 return 0;
ths3eb6b042007-06-03 14:26:27 +00003316}
3317
aurel32e5289082009-04-18 16:16:12 +00003318struct target_seminfo {
3319 int semmap;
3320 int semmni;
3321 int semmns;
3322 int semmnu;
3323 int semmsl;
3324 int semopm;
3325 int semume;
3326 int semusz;
3327 int semvmx;
3328 int semaem;
3329};
3330
3331static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3332 struct seminfo *host_seminfo)
3333{
3334 struct target_seminfo *target_seminfo;
3335 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3336 return -TARGET_EFAULT;
3337 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3338 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3339 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3340 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3341 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3342 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3343 __put_user(host_seminfo->semume, &target_seminfo->semume);
3344 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3345 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3346 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3347 unlock_user_struct(target_seminfo, target_addr, 1);
3348 return 0;
3349}
3350
thsfa294812007-02-02 22:05:00 +00003351union semun {
3352 int val;
ths3eb6b042007-06-03 14:26:27 +00003353 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003354 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003355 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003356};
3357
ths3eb6b042007-06-03 14:26:27 +00003358union target_semun {
3359 int val;
aurel32e5289082009-04-18 16:16:12 +00003360 abi_ulong buf;
3361 abi_ulong array;
3362 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003363};
3364
aurel32e5289082009-04-18 16:16:12 +00003365static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3366 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003367{
aurel32e5289082009-04-18 16:16:12 +00003368 int nsems;
3369 unsigned short *array;
3370 union semun semun;
3371 struct semid_ds semid_ds;
3372 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003373
aurel32e5289082009-04-18 16:16:12 +00003374 semun.buf = &semid_ds;
3375
3376 ret = semctl(semid, 0, IPC_STAT, semun);
3377 if (ret == -1)
3378 return get_errno(ret);
3379
3380 nsems = semid_ds.sem_nsems;
3381
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303382 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003383 if (!*host_array) {
3384 return -TARGET_ENOMEM;
3385 }
aurel32e5289082009-04-18 16:16:12 +00003386 array = lock_user(VERIFY_READ, target_addr,
3387 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003388 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303389 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003390 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003391 }
aurel32e5289082009-04-18 16:16:12 +00003392
3393 for(i=0; i<nsems; i++) {
3394 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003395 }
aurel32e5289082009-04-18 16:16:12 +00003396 unlock_user(array, target_addr, 0);
3397
bellard579a97f2007-11-11 14:26:47 +00003398 return 0;
ths3eb6b042007-06-03 14:26:27 +00003399}
3400
aurel32e5289082009-04-18 16:16:12 +00003401static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3402 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003403{
aurel32e5289082009-04-18 16:16:12 +00003404 int nsems;
3405 unsigned short *array;
3406 union semun semun;
3407 struct semid_ds semid_ds;
3408 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003409
aurel32e5289082009-04-18 16:16:12 +00003410 semun.buf = &semid_ds;
3411
3412 ret = semctl(semid, 0, IPC_STAT, semun);
3413 if (ret == -1)
3414 return get_errno(ret);
3415
3416 nsems = semid_ds.sem_nsems;
3417
3418 array = lock_user(VERIFY_WRITE, target_addr,
3419 nsems*sizeof(unsigned short), 0);
3420 if (!array)
3421 return -TARGET_EFAULT;
3422
3423 for(i=0; i<nsems; i++) {
3424 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003425 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303426 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003427 unlock_user(array, target_addr, 1);
3428
bellard579a97f2007-11-11 14:26:47 +00003429 return 0;
ths3eb6b042007-06-03 14:26:27 +00003430}
3431
aurel32e5289082009-04-18 16:16:12 +00003432static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003433 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003434{
Stefan Weild1c002b2015-02-08 15:40:58 +01003435 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003436 union semun arg;
3437 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303438 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003439 struct seminfo seminfo;
3440 abi_long ret = -TARGET_EINVAL;
3441 abi_long err;
3442 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003443
3444 switch( cmd ) {
3445 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003446 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003447 /* In 64 bit cross-endian situations, we will erroneously pick up
3448 * the wrong half of the union for the "val" element. To rectify
3449 * this, the entire 8-byte structure is byteswapped, followed by
3450 * a swap of the 4 byte val field. In other cases, the data is
3451 * already in proper host byte order. */
3452 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3453 target_su.buf = tswapal(target_su.buf);
3454 arg.val = tswap32(target_su.val);
3455 } else {
3456 arg.val = target_su.val;
3457 }
aurel32e5289082009-04-18 16:16:12 +00003458 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003459 break;
3460 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003461 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003462 err = target_to_host_semarray(semid, &array, target_su.array);
3463 if (err)
3464 return err;
3465 arg.array = array;
3466 ret = get_errno(semctl(semid, semnum, cmd, arg));
3467 err = host_to_target_semarray(semid, target_su.array, &array);
3468 if (err)
3469 return err;
ths3eb6b042007-06-03 14:26:27 +00003470 break;
3471 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003472 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003473 case SEM_STAT:
3474 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3475 if (err)
3476 return err;
3477 arg.buf = &dsarg;
3478 ret = get_errno(semctl(semid, semnum, cmd, arg));
3479 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3480 if (err)
3481 return err;
ths3eb6b042007-06-03 14:26:27 +00003482 break;
aurel32e5289082009-04-18 16:16:12 +00003483 case IPC_INFO:
3484 case SEM_INFO:
3485 arg.__buf = &seminfo;
3486 ret = get_errno(semctl(semid, semnum, cmd, arg));
3487 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3488 if (err)
3489 return err;
3490 break;
3491 case IPC_RMID:
3492 case GETPID:
3493 case GETNCNT:
3494 case GETZCNT:
3495 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3496 break;
ths3eb6b042007-06-03 14:26:27 +00003497 }
3498
3499 return ret;
3500}
3501
aurel32e5289082009-04-18 16:16:12 +00003502struct target_sembuf {
3503 unsigned short sem_num;
3504 short sem_op;
3505 short sem_flg;
3506};
3507
3508static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3509 abi_ulong target_addr,
3510 unsigned nsops)
3511{
3512 struct target_sembuf *target_sembuf;
3513 int i;
3514
3515 target_sembuf = lock_user(VERIFY_READ, target_addr,
3516 nsops*sizeof(struct target_sembuf), 1);
3517 if (!target_sembuf)
3518 return -TARGET_EFAULT;
3519
3520 for(i=0; i<nsops; i++) {
3521 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3522 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3523 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3524 }
3525
3526 unlock_user(target_sembuf, target_addr, 0);
3527
3528 return 0;
3529}
3530
3531static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3532{
3533 struct sembuf sops[nsops];
Laurent Vivier524fa342019-05-29 10:48:04 +02003534 abi_long ret;
aurel32e5289082009-04-18 16:16:12 +00003535
3536 if (target_to_host_sembuf(sops, ptr, nsops))
3537 return -TARGET_EFAULT;
3538
Laurent Vivier524fa342019-05-29 10:48:04 +02003539 ret = -TARGET_ENOSYS;
3540#ifdef __NR_semtimedop
3541 ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL));
3542#endif
3543#ifdef __NR_ipc
3544 if (ret == -TARGET_ENOSYS) {
3545 ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0));
3546 }
3547#endif
3548 return ret;
aurel32e5289082009-04-18 16:16:12 +00003549}
3550
ths1bc012f2007-06-03 14:27:49 +00003551struct target_msqid_ds
3552{
aurel321c54ff92008-10-13 21:08:44 +00003553 struct target_ipc_perm msg_perm;
3554 abi_ulong msg_stime;
3555#if TARGET_ABI_BITS == 32
3556 abi_ulong __unused1;
3557#endif
3558 abi_ulong msg_rtime;
3559#if TARGET_ABI_BITS == 32
3560 abi_ulong __unused2;
3561#endif
3562 abi_ulong msg_ctime;
3563#if TARGET_ABI_BITS == 32
3564 abi_ulong __unused3;
3565#endif
3566 abi_ulong __msg_cbytes;
3567 abi_ulong msg_qnum;
3568 abi_ulong msg_qbytes;
3569 abi_ulong msg_lspid;
3570 abi_ulong msg_lrpid;
3571 abi_ulong __unused4;
3572 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003573};
3574
bellard579a97f2007-11-11 14:26:47 +00003575static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3576 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003577{
3578 struct target_msqid_ds *target_md;
3579
bellard579a97f2007-11-11 14:26:47 +00003580 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3581 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003582 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3583 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003584 host_md->msg_stime = tswapal(target_md->msg_stime);
3585 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3586 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3587 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3588 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3589 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3590 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3591 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003592 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003593 return 0;
ths1bc012f2007-06-03 14:27:49 +00003594}
3595
bellard579a97f2007-11-11 14:26:47 +00003596static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3597 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003598{
3599 struct target_msqid_ds *target_md;
3600
bellard579a97f2007-11-11 14:26:47 +00003601 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3602 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003603 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3604 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003605 target_md->msg_stime = tswapal(host_md->msg_stime);
3606 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3607 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3608 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3609 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3610 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3611 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3612 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003613 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003614 return 0;
ths1bc012f2007-06-03 14:27:49 +00003615}
3616
aurel321c54ff92008-10-13 21:08:44 +00003617struct target_msginfo {
3618 int msgpool;
3619 int msgmap;
3620 int msgmax;
3621 int msgmnb;
3622 int msgmni;
3623 int msgssz;
3624 int msgtql;
3625 unsigned short int msgseg;
3626};
3627
3628static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3629 struct msginfo *host_msginfo)
3630{
3631 struct target_msginfo *target_msginfo;
3632 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3633 return -TARGET_EFAULT;
3634 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3635 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3636 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3637 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3638 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3639 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3640 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3641 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3642 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003643 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003644}
3645
3646static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003647{
3648 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003649 struct msginfo msginfo;
3650 abi_long ret = -TARGET_EINVAL;
3651
3652 cmd &= 0xff;
3653
3654 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003655 case IPC_STAT:
3656 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003657 case MSG_STAT:
3658 if (target_to_host_msqid_ds(&dsarg,ptr))
3659 return -TARGET_EFAULT;
3660 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3661 if (host_to_target_msqid_ds(ptr,&dsarg))
3662 return -TARGET_EFAULT;
3663 break;
3664 case IPC_RMID:
3665 ret = get_errno(msgctl(msgid, cmd, NULL));
3666 break;
3667 case IPC_INFO:
3668 case MSG_INFO:
3669 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3670 if (host_to_target_msginfo(ptr, &msginfo))
3671 return -TARGET_EFAULT;
3672 break;
ths1bc012f2007-06-03 14:27:49 +00003673 }
aurel321c54ff92008-10-13 21:08:44 +00003674
ths1bc012f2007-06-03 14:27:49 +00003675 return ret;
3676}
3677
3678struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003679 abi_long mtype;
3680 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003681};
3682
blueswir1992f48a2007-10-14 16:27:31 +00003683static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003684 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003685{
3686 struct target_msgbuf *target_mb;
3687 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003688 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003689
Tom Mustaedcc5f92014-08-12 13:53:37 -05003690 if (msgsz < 0) {
3691 return -TARGET_EINVAL;
3692 }
3693
bellard579a97f2007-11-11 14:26:47 +00003694 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3695 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303696 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003697 if (!host_mb) {
3698 unlock_user_struct(target_mb, msgp, 0);
3699 return -TARGET_ENOMEM;
3700 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003701 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003702 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Laurent Vivier524fa342019-05-29 10:48:04 +02003703 ret = -TARGET_ENOSYS;
3704#ifdef __NR_msgsnd
Peter Maydell89f9fe42016-06-06 19:58:05 +01003705 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02003706#endif
3707#ifdef __NR_ipc
3708 if (ret == -TARGET_ENOSYS) {
3709 ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
3710 host_mb, 0));
3711 }
3712#endif
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303713 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003714 unlock_user_struct(target_mb, msgp, 0);
3715
3716 return ret;
3717}
3718
blueswir1992f48a2007-10-14 16:27:31 +00003719static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003720 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003721 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003722{
3723 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003724 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003725 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003726 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003727
Peter Maydell99874f62016-05-20 19:00:56 +01003728 if (msgsz < 0) {
3729 return -TARGET_EINVAL;
3730 }
3731
bellard579a97f2007-11-11 14:26:47 +00003732 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3733 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003734
Peter Maydell415d8472016-05-20 19:00:57 +01003735 host_mb = g_try_malloc(msgsz + sizeof(long));
3736 if (!host_mb) {
3737 ret = -TARGET_ENOMEM;
3738 goto end;
3739 }
Laurent Vivier524fa342019-05-29 10:48:04 +02003740 ret = -TARGET_ENOSYS;
3741#ifdef __NR_msgrcv
Peter Maydell89f9fe42016-06-06 19:58:05 +01003742 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02003743#endif
3744#ifdef __NR_ipc
3745 if (ret == -TARGET_ENOSYS) {
3746 ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz,
3747 msgflg, host_mb, msgtyp));
3748 }
3749#endif
aurel321c54ff92008-10-13 21:08:44 +00003750
bellard579a97f2007-11-11 14:26:47 +00003751 if (ret > 0) {
3752 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3753 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3754 if (!target_mtext) {
3755 ret = -TARGET_EFAULT;
3756 goto end;
3757 }
aurel321c54ff92008-10-13 21:08:44 +00003758 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003759 unlock_user(target_mtext, target_mtext_addr, ret);
3760 }
aurel321c54ff92008-10-13 21:08:44 +00003761
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003762 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003763
bellard579a97f2007-11-11 14:26:47 +00003764end:
3765 if (target_mb)
3766 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003767 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003768 return ret;
3769}
3770
Riku Voipio88a8c982009-04-03 10:42:00 +03003771static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3772 abi_ulong target_addr)
3773{
3774 struct target_shmid_ds *target_sd;
3775
3776 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3777 return -TARGET_EFAULT;
3778 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3779 return -TARGET_EFAULT;
3780 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3781 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3782 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3783 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3784 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3785 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3786 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3787 unlock_user_struct(target_sd, target_addr, 0);
3788 return 0;
3789}
3790
3791static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3792 struct shmid_ds *host_sd)
3793{
3794 struct target_shmid_ds *target_sd;
3795
3796 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3797 return -TARGET_EFAULT;
3798 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3799 return -TARGET_EFAULT;
3800 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3801 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3802 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3803 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3804 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3805 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3806 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3807 unlock_user_struct(target_sd, target_addr, 1);
3808 return 0;
3809}
3810
3811struct target_shminfo {
3812 abi_ulong shmmax;
3813 abi_ulong shmmin;
3814 abi_ulong shmmni;
3815 abi_ulong shmseg;
3816 abi_ulong shmall;
3817};
3818
3819static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3820 struct shminfo *host_shminfo)
3821{
3822 struct target_shminfo *target_shminfo;
3823 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3824 return -TARGET_EFAULT;
3825 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3826 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3827 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3828 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3829 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3830 unlock_user_struct(target_shminfo, target_addr, 1);
3831 return 0;
3832}
3833
3834struct target_shm_info {
3835 int used_ids;
3836 abi_ulong shm_tot;
3837 abi_ulong shm_rss;
3838 abi_ulong shm_swp;
3839 abi_ulong swap_attempts;
3840 abi_ulong swap_successes;
3841};
3842
3843static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3844 struct shm_info *host_shm_info)
3845{
3846 struct target_shm_info *target_shm_info;
3847 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3848 return -TARGET_EFAULT;
3849 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3850 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3851 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3852 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3853 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3854 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3855 unlock_user_struct(target_shm_info, target_addr, 1);
3856 return 0;
3857}
3858
3859static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3860{
3861 struct shmid_ds dsarg;
3862 struct shminfo shminfo;
3863 struct shm_info shm_info;
3864 abi_long ret = -TARGET_EINVAL;
3865
3866 cmd &= 0xff;
3867
3868 switch(cmd) {
3869 case IPC_STAT:
3870 case IPC_SET:
3871 case SHM_STAT:
3872 if (target_to_host_shmid_ds(&dsarg, buf))
3873 return -TARGET_EFAULT;
3874 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3875 if (host_to_target_shmid_ds(buf, &dsarg))
3876 return -TARGET_EFAULT;
3877 break;
3878 case IPC_INFO:
3879 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3880 if (host_to_target_shminfo(buf, &shminfo))
3881 return -TARGET_EFAULT;
3882 break;
3883 case SHM_INFO:
3884 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3885 if (host_to_target_shm_info(buf, &shm_info))
3886 return -TARGET_EFAULT;
3887 break;
3888 case IPC_RMID:
3889 case SHM_LOCK:
3890 case SHM_UNLOCK:
3891 ret = get_errno(shmctl(shmid, cmd, NULL));
3892 break;
3893 }
3894
3895 return ret;
3896}
3897
Peter Maydellee8e7612016-07-11 16:48:11 +01003898#ifndef TARGET_FORCE_SHMLBA
3899/* For most architectures, SHMLBA is the same as the page size;
3900 * some architectures have larger values, in which case they should
3901 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
3902 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
3903 * and defining its own value for SHMLBA.
3904 *
3905 * The kernel also permits SHMLBA to be set by the architecture to a
3906 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
3907 * this means that addresses are rounded to the large size if
3908 * SHM_RND is set but addresses not aligned to that size are not rejected
3909 * as long as they are at least page-aligned. Since the only architecture
3910 * which uses this is ia64 this code doesn't provide for that oddity.
3911 */
3912static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
3913{
3914 return TARGET_PAGE_SIZE;
3915}
3916#endif
3917
3918static inline abi_ulong do_shmat(CPUArchState *cpu_env,
3919 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03003920{
3921 abi_long raddr;
3922 void *host_raddr;
3923 struct shmid_ds shm_info;
3924 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01003925 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03003926
3927 /* find out the length of the shared memory segment */
3928 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3929 if (is_error(ret)) {
3930 /* can't get length, bail out */
3931 return ret;
3932 }
3933
Peter Maydellee8e7612016-07-11 16:48:11 +01003934 shmlba = target_shmlba(cpu_env);
3935
3936 if (shmaddr & (shmlba - 1)) {
3937 if (shmflg & SHM_RND) {
3938 shmaddr &= ~(shmlba - 1);
3939 } else {
3940 return -TARGET_EINVAL;
3941 }
3942 }
Max Filippovebf9a362018-03-07 13:50:10 -08003943 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
3944 return -TARGET_EINVAL;
3945 }
Peter Maydellee8e7612016-07-11 16:48:11 +01003946
Riku Voipio88a8c982009-04-03 10:42:00 +03003947 mmap_lock();
3948
3949 if (shmaddr)
3950 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3951 else {
3952 abi_ulong mmap_start;
3953
Richard Henderson30ab9ef2019-05-19 13:19:52 -07003954 /* In order to use the host shmat, we need to honor host SHMLBA. */
3955 mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
Riku Voipio88a8c982009-04-03 10:42:00 +03003956
3957 if (mmap_start == -1) {
3958 errno = ENOMEM;
3959 host_raddr = (void *)-1;
3960 } else
3961 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3962 }
3963
3964 if (host_raddr == (void *)-1) {
3965 mmap_unlock();
3966 return get_errno((long)host_raddr);
3967 }
3968 raddr=h2g((unsigned long)host_raddr);
3969
3970 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3971 PAGE_VALID | PAGE_READ |
3972 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3973
3974 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003975 if (!shm_regions[i].in_use) {
3976 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03003977 shm_regions[i].start = raddr;
3978 shm_regions[i].size = shm_info.shm_segsz;
3979 break;
3980 }
3981 }
3982
3983 mmap_unlock();
3984 return raddr;
3985
3986}
3987
3988static inline abi_long do_shmdt(abi_ulong shmaddr)
3989{
3990 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08003991 abi_long rv;
3992
3993 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03003994
3995 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00003996 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
3997 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003998 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003999 break;
4000 }
4001 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08004002 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03004003
Max Filippov3c5f6a52018-02-28 14:16:04 -08004004 mmap_unlock();
4005
4006 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03004007}
4008
aurel321c54ff92008-10-13 21:08:44 +00004009#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004010/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004011/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004012static abi_long do_ipc(CPUArchState *cpu_env,
4013 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004014 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004015 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004016{
4017 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004018 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004019
4020 version = call >> 16;
4021 call &= 0xffff;
4022
4023 switch (call) {
thsfa294812007-02-02 22:05:00 +00004024 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004025 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004026 break;
4027
4028 case IPCOP_semget:
4029 ret = get_errno(semget(first, second, third));
4030 break;
4031
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004032 case IPCOP_semctl: {
4033 /* The semun argument to semctl is passed by value, so dereference the
4034 * ptr argument. */
4035 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004036 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004037 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004038 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004039 }
thsd96372e2007-02-02 22:05:44 +00004040
aurel321c54ff92008-10-13 21:08:44 +00004041 case IPCOP_msgget:
4042 ret = get_errno(msgget(first, second));
4043 break;
thsd96372e2007-02-02 22:05:44 +00004044
aurel321c54ff92008-10-13 21:08:44 +00004045 case IPCOP_msgsnd:
4046 ret = do_msgsnd(first, ptr, second, third);
4047 break;
thsd96372e2007-02-02 22:05:44 +00004048
aurel321c54ff92008-10-13 21:08:44 +00004049 case IPCOP_msgctl:
4050 ret = do_msgctl(first, second, ptr);
4051 break;
thsd96372e2007-02-02 22:05:44 +00004052
aurel321c54ff92008-10-13 21:08:44 +00004053 case IPCOP_msgrcv:
4054 switch (version) {
4055 case 0:
4056 {
4057 struct target_ipc_kludge {
4058 abi_long msgp;
4059 abi_long msgtyp;
4060 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004061
aurel321c54ff92008-10-13 21:08:44 +00004062 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4063 ret = -TARGET_EFAULT;
4064 break;
ths1bc012f2007-06-03 14:27:49 +00004065 }
aurel321c54ff92008-10-13 21:08:44 +00004066
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004067 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004068
4069 unlock_user_struct(tmp, ptr, 0);
4070 break;
4071 }
4072 default:
4073 ret = do_msgrcv(first, ptr, second, fifth, third);
4074 }
4075 break;
thsd96372e2007-02-02 22:05:44 +00004076
bellard8853f862004-02-22 14:57:26 +00004077 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004078 switch (version) {
4079 default:
bellard5a4a8982007-11-11 17:39:18 +00004080 {
4081 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01004082 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03004083 if (is_error(raddr))
4084 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004085 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004086 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004087 break;
4088 }
4089 case 1:
4090 ret = -TARGET_EINVAL;
4091 break;
bellard5a4a8982007-11-11 17:39:18 +00004092 }
bellard8853f862004-02-22 14:57:26 +00004093 break;
4094 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004095 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004096 break;
4097
4098 case IPCOP_shmget:
4099 /* IPC_* flag values are the same on all linux platforms */
4100 ret = get_errno(shmget(first, second, third));
4101 break;
4102
4103 /* IPC_* and SHM_* command values are the same on all linux platforms */
4104 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004105 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004106 break;
4107 default:
j_mayer32407102007-09-26 23:01:49 +00004108 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004109 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004110 break;
4111 }
4112 return ret;
4113}
j_mayer32407102007-09-26 23:01:49 +00004114#endif
bellard8853f862004-02-22 14:57:26 +00004115
bellard31e31b82003-02-18 22:55:36 +00004116/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004117
Blue Swirl001faf32009-05-13 17:53:17 +00004118#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004119#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4120enum {
4121#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004122STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004123};
4124#undef STRUCT
4125#undef STRUCT_SPECIAL
4126
Blue Swirl001faf32009-05-13 17:53:17 +00004127#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004128#define STRUCT_SPECIAL(name)
4129#include "syscall_types.h"
4130#undef STRUCT
4131#undef STRUCT_SPECIAL
4132
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004133typedef struct IOCTLEntry IOCTLEntry;
4134
4135typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004136 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004137
4138struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004139 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004140 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004141 const char *name;
4142 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004143 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004144 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004145};
bellard31e31b82003-02-18 22:55:36 +00004146
4147#define IOC_R 0x0001
4148#define IOC_W 0x0002
4149#define IOC_RW (IOC_R | IOC_W)
4150
4151#define MAX_STRUCT_SIZE 4096
4152
Peter Maydelldace20d2011-01-10 13:11:24 +00004153#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004154/* So fiemap access checks don't overflow on 32 bit systems.
4155 * This is very slightly smaller than the limit imposed by
4156 * the underlying kernel.
4157 */
4158#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4159 / sizeof(struct fiemap_extent))
4160
4161static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004162 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004163{
4164 /* The parameter for this ioctl is a struct fiemap followed
4165 * by an array of struct fiemap_extent whose size is set
4166 * in fiemap->fm_extent_count. The array is filled in by the
4167 * ioctl.
4168 */
4169 int target_size_in, target_size_out;
4170 struct fiemap *fm;
4171 const argtype *arg_type = ie->arg_type;
4172 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4173 void *argptr, *p;
4174 abi_long ret;
4175 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4176 uint32_t outbufsz;
4177 int free_fm = 0;
4178
4179 assert(arg_type[0] == TYPE_PTR);
4180 assert(ie->access == IOC_RW);
4181 arg_type++;
4182 target_size_in = thunk_type_size(arg_type, 0);
4183 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4184 if (!argptr) {
4185 return -TARGET_EFAULT;
4186 }
4187 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4188 unlock_user(argptr, arg, 0);
4189 fm = (struct fiemap *)buf_temp;
4190 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4191 return -TARGET_EINVAL;
4192 }
4193
4194 outbufsz = sizeof (*fm) +
4195 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4196
4197 if (outbufsz > MAX_STRUCT_SIZE) {
4198 /* We can't fit all the extents into the fixed size buffer.
4199 * Allocate one that is large enough and use it instead.
4200 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304201 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004202 if (!fm) {
4203 return -TARGET_ENOMEM;
4204 }
4205 memcpy(fm, buf_temp, sizeof(struct fiemap));
4206 free_fm = 1;
4207 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004208 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004209 if (!is_error(ret)) {
4210 target_size_out = target_size_in;
4211 /* An extent_count of 0 means we were only counting the extents
4212 * so there are no structs to copy
4213 */
4214 if (fm->fm_extent_count != 0) {
4215 target_size_out += fm->fm_mapped_extents * extent_size;
4216 }
4217 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4218 if (!argptr) {
4219 ret = -TARGET_EFAULT;
4220 } else {
4221 /* Convert the struct fiemap */
4222 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4223 if (fm->fm_extent_count != 0) {
4224 p = argptr + target_size_in;
4225 /* ...and then all the struct fiemap_extents */
4226 for (i = 0; i < fm->fm_mapped_extents; i++) {
4227 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4228 THUNK_TARGET);
4229 p += extent_size;
4230 }
4231 }
4232 unlock_user(argptr, arg, target_size_out);
4233 }
4234 }
4235 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304236 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004237 }
4238 return ret;
4239}
Peter Maydelldace20d2011-01-10 13:11:24 +00004240#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004241
Laurent Vivier059c2f22011-03-30 00:12:12 +02004242static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004243 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004244{
4245 const argtype *arg_type = ie->arg_type;
4246 int target_size;
4247 void *argptr;
4248 int ret;
4249 struct ifconf *host_ifconf;
4250 uint32_t outbufsz;
4251 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4252 int target_ifreq_size;
4253 int nb_ifreq;
4254 int free_buf = 0;
4255 int i;
4256 int target_ifc_len;
4257 abi_long target_ifc_buf;
4258 int host_ifc_len;
4259 char *host_ifc_buf;
4260
4261 assert(arg_type[0] == TYPE_PTR);
4262 assert(ie->access == IOC_RW);
4263
4264 arg_type++;
4265 target_size = thunk_type_size(arg_type, 0);
4266
4267 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4268 if (!argptr)
4269 return -TARGET_EFAULT;
4270 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4271 unlock_user(argptr, arg, 0);
4272
4273 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004274 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004275 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004276
Kan Li22e4a2672018-10-24 20:13:03 +00004277 if (target_ifc_buf != 0) {
4278 target_ifc_len = host_ifconf->ifc_len;
4279 nb_ifreq = target_ifc_len / target_ifreq_size;
4280 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4281
4282 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4283 if (outbufsz > MAX_STRUCT_SIZE) {
4284 /*
4285 * We can't fit all the extents into the fixed size buffer.
4286 * Allocate one that is large enough and use it instead.
4287 */
4288 host_ifconf = malloc(outbufsz);
4289 if (!host_ifconf) {
4290 return -TARGET_ENOMEM;
4291 }
4292 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4293 free_buf = 1;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004294 }
Kan Li22e4a2672018-10-24 20:13:03 +00004295 host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004296
Kan Li22e4a2672018-10-24 20:13:03 +00004297 host_ifconf->ifc_len = host_ifc_len;
4298 } else {
4299 host_ifc_buf = NULL;
4300 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004301 host_ifconf->ifc_buf = host_ifc_buf;
4302
Peter Maydell49ca6f32016-06-06 19:58:14 +01004303 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004304 if (!is_error(ret)) {
4305 /* convert host ifc_len to target ifc_len */
4306
4307 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4308 target_ifc_len = nb_ifreq * target_ifreq_size;
4309 host_ifconf->ifc_len = target_ifc_len;
4310
4311 /* restore target ifc_buf */
4312
4313 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4314
4315 /* copy struct ifconf to target user */
4316
4317 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4318 if (!argptr)
4319 return -TARGET_EFAULT;
4320 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4321 unlock_user(argptr, arg, target_size);
4322
Kan Li22e4a2672018-10-24 20:13:03 +00004323 if (target_ifc_buf != 0) {
4324 /* copy ifreq[] to target user */
4325 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4326 for (i = 0; i < nb_ifreq ; i++) {
4327 thunk_convert(argptr + i * target_ifreq_size,
4328 host_ifc_buf + i * sizeof(struct ifreq),
4329 ifreq_arg_type, THUNK_TARGET);
4330 }
4331 unlock_user(argptr, target_ifc_buf, target_ifc_len);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004332 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004333 }
4334
4335 if (free_buf) {
4336 free(host_ifconf);
4337 }
4338
4339 return ret;
4340}
4341
Cortland Tölvaa1333672018-10-08 09:35:21 -07004342#if defined(CONFIG_USBFS)
4343#if HOST_LONG_BITS > 64
4344#error USBDEVFS thunks do not support >64 bit hosts yet.
4345#endif
4346struct live_urb {
4347 uint64_t target_urb_adr;
4348 uint64_t target_buf_adr;
4349 char *target_buf_ptr;
4350 struct usbdevfs_urb host_urb;
4351};
4352
4353static GHashTable *usbdevfs_urb_hashtable(void)
4354{
4355 static GHashTable *urb_hashtable;
4356
4357 if (!urb_hashtable) {
4358 urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
4359 }
4360 return urb_hashtable;
4361}
4362
4363static void urb_hashtable_insert(struct live_urb *urb)
4364{
4365 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4366 g_hash_table_insert(urb_hashtable, urb, urb);
4367}
4368
4369static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
4370{
4371 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4372 return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
4373}
4374
4375static void urb_hashtable_remove(struct live_urb *urb)
4376{
4377 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4378 g_hash_table_remove(urb_hashtable, urb);
4379}
4380
4381static abi_long
4382do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
4383 int fd, int cmd, abi_long arg)
4384{
4385 const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
4386 const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
4387 struct live_urb *lurb;
4388 void *argptr;
4389 uint64_t hurb;
4390 int target_size;
4391 uintptr_t target_urb_adr;
4392 abi_long ret;
4393
4394 target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
4395
4396 memset(buf_temp, 0, sizeof(uint64_t));
4397 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
4398 if (is_error(ret)) {
4399 return ret;
4400 }
4401
4402 memcpy(&hurb, buf_temp, sizeof(uint64_t));
4403 lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
4404 if (!lurb->target_urb_adr) {
4405 return -TARGET_EFAULT;
4406 }
4407 urb_hashtable_remove(lurb);
4408 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
4409 lurb->host_urb.buffer_length);
4410 lurb->target_buf_ptr = NULL;
4411
4412 /* restore the guest buffer pointer */
4413 lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
4414
4415 /* update the guest urb struct */
4416 argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
4417 if (!argptr) {
4418 g_free(lurb);
4419 return -TARGET_EFAULT;
4420 }
4421 thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
4422 unlock_user(argptr, lurb->target_urb_adr, target_size);
4423
4424 target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
4425 /* write back the urb handle */
4426 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4427 if (!argptr) {
4428 g_free(lurb);
4429 return -TARGET_EFAULT;
4430 }
4431
4432 /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
4433 target_urb_adr = lurb->target_urb_adr;
4434 thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
4435 unlock_user(argptr, arg, target_size);
4436
4437 g_free(lurb);
4438 return ret;
4439}
4440
4441static abi_long
4442do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
4443 uint8_t *buf_temp __attribute__((unused)),
4444 int fd, int cmd, abi_long arg)
4445{
4446 struct live_urb *lurb;
4447
4448 /* map target address back to host URB with metadata. */
4449 lurb = urb_hashtable_lookup(arg);
4450 if (!lurb) {
4451 return -TARGET_EFAULT;
4452 }
4453 return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
4454}
4455
4456static abi_long
4457do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
4458 int fd, int cmd, abi_long arg)
4459{
4460 const argtype *arg_type = ie->arg_type;
4461 int target_size;
4462 abi_long ret;
4463 void *argptr;
4464 int rw_dir;
4465 struct live_urb *lurb;
4466
4467 /*
4468 * each submitted URB needs to map to a unique ID for the
4469 * kernel, and that unique ID needs to be a pointer to
4470 * host memory. hence, we need to malloc for each URB.
4471 * isochronous transfers have a variable length struct.
4472 */
4473 arg_type++;
4474 target_size = thunk_type_size(arg_type, THUNK_TARGET);
4475
4476 /* construct host copy of urb and metadata */
4477 lurb = g_try_malloc0(sizeof(struct live_urb));
4478 if (!lurb) {
4479 return -TARGET_ENOMEM;
4480 }
4481
4482 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4483 if (!argptr) {
4484 g_free(lurb);
4485 return -TARGET_EFAULT;
4486 }
4487 thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
4488 unlock_user(argptr, arg, 0);
4489
4490 lurb->target_urb_adr = arg;
4491 lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
4492
4493 /* buffer space used depends on endpoint type so lock the entire buffer */
4494 /* control type urbs should check the buffer contents for true direction */
4495 rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
4496 lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
4497 lurb->host_urb.buffer_length, 1);
4498 if (lurb->target_buf_ptr == NULL) {
4499 g_free(lurb);
4500 return -TARGET_EFAULT;
4501 }
4502
4503 /* update buffer pointer in host copy */
4504 lurb->host_urb.buffer = lurb->target_buf_ptr;
4505
4506 ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
4507 if (is_error(ret)) {
4508 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
4509 g_free(lurb);
4510 } else {
4511 urb_hashtable_insert(lurb);
4512 }
4513
4514 return ret;
4515}
4516#endif /* CONFIG_USBFS */
4517
Alexander Graf56e904e2012-01-31 18:42:06 +01004518static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004519 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004520{
4521 void *argptr;
4522 struct dm_ioctl *host_dm;
4523 abi_long guest_data;
4524 uint32_t guest_data_size;
4525 int target_size;
4526 const argtype *arg_type = ie->arg_type;
4527 abi_long ret;
4528 void *big_buf = NULL;
4529 char *host_data;
4530
4531 arg_type++;
4532 target_size = thunk_type_size(arg_type, 0);
4533 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4534 if (!argptr) {
4535 ret = -TARGET_EFAULT;
4536 goto out;
4537 }
4538 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4539 unlock_user(argptr, arg, 0);
4540
4541 /* buf_temp is too small, so fetch things into a bigger buffer */
4542 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4543 memcpy(big_buf, buf_temp, target_size);
4544 buf_temp = big_buf;
4545 host_dm = big_buf;
4546
4547 guest_data = arg + host_dm->data_start;
4548 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01004549 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01004550 goto out;
4551 }
4552 guest_data_size = host_dm->data_size - host_dm->data_start;
4553 host_data = (char*)host_dm + host_dm->data_start;
4554
4555 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01004556 if (!argptr) {
4557 ret = -TARGET_EFAULT;
4558 goto out;
4559 }
4560
Alexander Graf56e904e2012-01-31 18:42:06 +01004561 switch (ie->host_cmd) {
4562 case DM_REMOVE_ALL:
4563 case DM_LIST_DEVICES:
4564 case DM_DEV_CREATE:
4565 case DM_DEV_REMOVE:
4566 case DM_DEV_SUSPEND:
4567 case DM_DEV_STATUS:
4568 case DM_DEV_WAIT:
4569 case DM_TABLE_STATUS:
4570 case DM_TABLE_CLEAR:
4571 case DM_TABLE_DEPS:
4572 case DM_LIST_VERSIONS:
4573 /* no input data */
4574 break;
4575 case DM_DEV_RENAME:
4576 case DM_DEV_SET_GEOMETRY:
4577 /* data contains only strings */
4578 memcpy(host_data, argptr, guest_data_size);
4579 break;
4580 case DM_TARGET_MSG:
4581 memcpy(host_data, argptr, guest_data_size);
4582 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4583 break;
4584 case DM_TABLE_LOAD:
4585 {
4586 void *gspec = argptr;
4587 void *cur_data = host_data;
4588 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4589 int spec_size = thunk_type_size(arg_type, 0);
4590 int i;
4591
4592 for (i = 0; i < host_dm->target_count; i++) {
4593 struct dm_target_spec *spec = cur_data;
4594 uint32_t next;
4595 int slen;
4596
4597 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4598 slen = strlen((char*)gspec + spec_size) + 1;
4599 next = spec->next;
4600 spec->next = sizeof(*spec) + slen;
4601 strcpy((char*)&spec[1], gspec + spec_size);
4602 gspec += next;
4603 cur_data += spec->next;
4604 }
4605 break;
4606 }
4607 default:
4608 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004609 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004610 goto out;
4611 }
4612 unlock_user(argptr, guest_data, 0);
4613
Peter Maydell49ca6f32016-06-06 19:58:14 +01004614 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01004615 if (!is_error(ret)) {
4616 guest_data = arg + host_dm->data_start;
4617 guest_data_size = host_dm->data_size - host_dm->data_start;
4618 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4619 switch (ie->host_cmd) {
4620 case DM_REMOVE_ALL:
4621 case DM_DEV_CREATE:
4622 case DM_DEV_REMOVE:
4623 case DM_DEV_RENAME:
4624 case DM_DEV_SUSPEND:
4625 case DM_DEV_STATUS:
4626 case DM_TABLE_LOAD:
4627 case DM_TABLE_CLEAR:
4628 case DM_TARGET_MSG:
4629 case DM_DEV_SET_GEOMETRY:
4630 /* no return data */
4631 break;
4632 case DM_LIST_DEVICES:
4633 {
4634 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4635 uint32_t remaining_data = guest_data_size;
4636 void *cur_data = argptr;
4637 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4638 int nl_size = 12; /* can't use thunk_size due to alignment */
4639
4640 while (1) {
4641 uint32_t next = nl->next;
4642 if (next) {
4643 nl->next = nl_size + (strlen(nl->name) + 1);
4644 }
4645 if (remaining_data < nl->next) {
4646 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4647 break;
4648 }
4649 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4650 strcpy(cur_data + nl_size, nl->name);
4651 cur_data += nl->next;
4652 remaining_data -= nl->next;
4653 if (!next) {
4654 break;
4655 }
4656 nl = (void*)nl + next;
4657 }
4658 break;
4659 }
4660 case DM_DEV_WAIT:
4661 case DM_TABLE_STATUS:
4662 {
4663 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4664 void *cur_data = argptr;
4665 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4666 int spec_size = thunk_type_size(arg_type, 0);
4667 int i;
4668
4669 for (i = 0; i < host_dm->target_count; i++) {
4670 uint32_t next = spec->next;
4671 int slen = strlen((char*)&spec[1]) + 1;
4672 spec->next = (cur_data - argptr) + spec_size + slen;
4673 if (guest_data_size < spec->next) {
4674 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4675 break;
4676 }
4677 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4678 strcpy(cur_data + spec_size, (char*)&spec[1]);
4679 cur_data = argptr + spec->next;
4680 spec = (void*)host_dm + host_dm->data_start + next;
4681 }
4682 break;
4683 }
4684 case DM_TABLE_DEPS:
4685 {
4686 void *hdata = (void*)host_dm + host_dm->data_start;
4687 int count = *(uint32_t*)hdata;
4688 uint64_t *hdev = hdata + 8;
4689 uint64_t *gdev = argptr + 8;
4690 int i;
4691
4692 *(uint32_t*)argptr = tswap32(count);
4693 for (i = 0; i < count; i++) {
4694 *gdev = tswap64(*hdev);
4695 gdev++;
4696 hdev++;
4697 }
4698 break;
4699 }
4700 case DM_LIST_VERSIONS:
4701 {
4702 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4703 uint32_t remaining_data = guest_data_size;
4704 void *cur_data = argptr;
4705 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4706 int vers_size = thunk_type_size(arg_type, 0);
4707
4708 while (1) {
4709 uint32_t next = vers->next;
4710 if (next) {
4711 vers->next = vers_size + (strlen(vers->name) + 1);
4712 }
4713 if (remaining_data < vers->next) {
4714 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4715 break;
4716 }
4717 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4718 strcpy(cur_data + vers_size, vers->name);
4719 cur_data += vers->next;
4720 remaining_data -= vers->next;
4721 if (!next) {
4722 break;
4723 }
4724 vers = (void*)vers + next;
4725 }
4726 break;
4727 }
4728 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004729 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004730 ret = -TARGET_EINVAL;
4731 goto out;
4732 }
4733 unlock_user(argptr, guest_data, guest_data_size);
4734
4735 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4736 if (!argptr) {
4737 ret = -TARGET_EFAULT;
4738 goto out;
4739 }
4740 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4741 unlock_user(argptr, arg, target_size);
4742 }
4743out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004744 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004745 return ret;
4746}
4747
Alexander Grafa59b5e32014-08-22 13:15:50 +02004748static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004749 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004750{
4751 void *argptr;
4752 int target_size;
4753 const argtype *arg_type = ie->arg_type;
4754 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4755 abi_long ret;
4756
4757 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4758 struct blkpg_partition host_part;
4759
4760 /* Read and convert blkpg */
4761 arg_type++;
4762 target_size = thunk_type_size(arg_type, 0);
4763 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4764 if (!argptr) {
4765 ret = -TARGET_EFAULT;
4766 goto out;
4767 }
4768 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4769 unlock_user(argptr, arg, 0);
4770
4771 switch (host_blkpg->op) {
4772 case BLKPG_ADD_PARTITION:
4773 case BLKPG_DEL_PARTITION:
4774 /* payload is struct blkpg_partition */
4775 break;
4776 default:
4777 /* Unknown opcode */
4778 ret = -TARGET_EINVAL;
4779 goto out;
4780 }
4781
4782 /* Read and convert blkpg->data */
4783 arg = (abi_long)(uintptr_t)host_blkpg->data;
4784 target_size = thunk_type_size(part_arg_type, 0);
4785 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4786 if (!argptr) {
4787 ret = -TARGET_EFAULT;
4788 goto out;
4789 }
4790 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4791 unlock_user(argptr, arg, 0);
4792
4793 /* Swizzle the data pointer to our local copy and call! */
4794 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01004795 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02004796
4797out:
4798 return ret;
4799}
4800
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004801static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004802 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004803{
4804 const argtype *arg_type = ie->arg_type;
4805 const StructEntry *se;
4806 const argtype *field_types;
4807 const int *dst_offsets, *src_offsets;
4808 int target_size;
4809 void *argptr;
Marc-André Lureaub78c5222019-03-05 16:15:00 +01004810 abi_ulong *target_rt_dev_ptr = NULL;
4811 unsigned long *host_rt_dev_ptr = NULL;
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004812 abi_long ret;
4813 int i;
4814
4815 assert(ie->access == IOC_W);
4816 assert(*arg_type == TYPE_PTR);
4817 arg_type++;
4818 assert(*arg_type == TYPE_STRUCT);
4819 target_size = thunk_type_size(arg_type, 0);
4820 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4821 if (!argptr) {
4822 return -TARGET_EFAULT;
4823 }
4824 arg_type++;
4825 assert(*arg_type == (int)STRUCT_rtentry);
4826 se = struct_entries + *arg_type++;
4827 assert(se->convert[0] == NULL);
4828 /* convert struct here to be able to catch rt_dev string */
4829 field_types = se->field_types;
4830 dst_offsets = se->field_offsets[THUNK_HOST];
4831 src_offsets = se->field_offsets[THUNK_TARGET];
4832 for (i = 0; i < se->nb_fields; i++) {
4833 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4834 assert(*field_types == TYPE_PTRVOID);
4835 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4836 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4837 if (*target_rt_dev_ptr != 0) {
4838 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4839 tswapal(*target_rt_dev_ptr));
4840 if (!*host_rt_dev_ptr) {
4841 unlock_user(argptr, arg, 0);
4842 return -TARGET_EFAULT;
4843 }
4844 } else {
4845 *host_rt_dev_ptr = 0;
4846 }
4847 field_types++;
4848 continue;
4849 }
4850 field_types = thunk_convert(buf_temp + dst_offsets[i],
4851 argptr + src_offsets[i],
4852 field_types, THUNK_HOST);
4853 }
4854 unlock_user(argptr, arg, 0);
4855
Peter Maydell49ca6f32016-06-06 19:58:14 +01004856 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Marc-André Lureaub78c5222019-03-05 16:15:00 +01004857
4858 assert(host_rt_dev_ptr != NULL);
4859 assert(target_rt_dev_ptr != NULL);
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004860 if (*host_rt_dev_ptr != 0) {
4861 unlock_user((void *)*host_rt_dev_ptr,
4862 *target_rt_dev_ptr, 0);
4863 }
4864 return ret;
4865}
4866
Paul Burtonca56f5b2014-06-22 11:25:47 +01004867static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004868 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004869{
4870 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004871 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01004872}
4873
Andreas Schwab2b74f622018-01-29 11:47:06 +01004874#ifdef TIOCGPTPEER
4875static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
4876 int fd, int cmd, abi_long arg)
4877{
4878 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
4879 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
4880}
4881#endif
4882
blueswir19f106a72008-10-05 10:52:52 +00004883static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004884#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004885 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4886#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4887 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01004888#define IOCTL_IGNORE(cmd) \
4889 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00004890#include "ioctls.h"
4891 { 0, 0, },
4892};
4893
pbrook53a59602006-03-25 19:31:22 +00004894/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004895/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004896static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004897{
4898 const IOCTLEntry *ie;
4899 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004900 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004901 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004902 int target_size;
4903 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004904
4905 ie = ioctl_entries;
4906 for(;;) {
4907 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004908 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004909 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004910 }
4911 if (ie->target_cmd == cmd)
4912 break;
4913 ie++;
4914 }
4915 arg_type = ie->arg_type;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004916 if (ie->do_ioctl) {
4917 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01004918 } else if (!ie->host_cmd) {
4919 /* Some architectures define BSD ioctls in their headers
4920 that are not implemented in Linux. */
4921 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004922 }
4923
bellard31e31b82003-02-18 22:55:36 +00004924 switch(arg_type[0]) {
4925 case TYPE_NULL:
4926 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01004927 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00004928 break;
4929 case TYPE_PTRVOID:
4930 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004931 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00004932 break;
4933 case TYPE_PTR:
4934 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004935 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004936 switch(ie->access) {
4937 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01004938 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004939 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004940 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4941 if (!argptr)
4942 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004943 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4944 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004945 }
4946 break;
4947 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004948 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4949 if (!argptr)
4950 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004951 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4952 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004953 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004954 break;
4955 default:
4956 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004957 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4958 if (!argptr)
4959 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004960 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4961 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01004962 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00004963 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004964 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4965 if (!argptr)
4966 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004967 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4968 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004969 }
4970 break;
4971 }
4972 break;
4973 default:
j_mayer32407102007-09-26 23:01:49 +00004974 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4975 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004976 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004977 break;
4978 }
4979 return ret;
4980}
4981
blueswir1b39bc502008-10-05 10:51:10 +00004982static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004983 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4984 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4985 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4986 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4987 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4988 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4989 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4990 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4991 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4992 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4993 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4994 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4995 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4996 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4997 { 0, 0, 0, 0 }
4998};
4999
blueswir1b39bc502008-10-05 10:51:10 +00005000static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005001 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5002 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5003 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5004 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5005 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5006 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5007 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5008 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5009 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5010 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5011 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5012 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5013 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5014 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5015 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5016 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5017 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5018 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5019 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5020 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5021 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5022 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5023 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5024 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5025 { 0, 0, 0, 0 }
5026};
5027
blueswir1b39bc502008-10-05 10:51:10 +00005028static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005029 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5030 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5031 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5032 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5033 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5034 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5035 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5036 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5037 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5038 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5039 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5040 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5041 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5042 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5043 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5044 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5045 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5046 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5047 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5048 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5049 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5050 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5051 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5052 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5053 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5054 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5055 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5056 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5057 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5058 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5059 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5060 { 0, 0, 0, 0 }
5061};
5062
blueswir1b39bc502008-10-05 10:51:10 +00005063static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005064 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5065 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5066 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5067 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5068 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5069 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5070 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5071 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5072 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5073 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5074 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5075 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5076 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5077 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5078 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5079 { 0, 0, 0, 0 }
5080};
5081
5082static void target_to_host_termios (void *dst, const void *src)
5083{
5084 struct host_termios *host = dst;
5085 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005086
ths5fafdf22007-09-16 21:08:06 +00005087 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005088 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005089 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005090 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005091 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005092 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005093 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005094 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5095 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005096
Arnaud Patard44607122009-04-21 17:39:08 +03005097 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005098 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5099 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005100 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005101 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005102 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005103 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005104 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005105 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005106 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005107 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5108 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005109 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5110 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5111 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5112 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5113 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005114 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005115}
ths3b46e622007-09-17 08:09:54 +00005116
bellard31e31b82003-02-18 22:55:36 +00005117static void host_to_target_termios (void *dst, const void *src)
5118{
5119 struct target_termios *target = dst;
5120 const struct host_termios *host = src;
5121
ths5fafdf22007-09-16 21:08:06 +00005122 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005123 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005124 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005125 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005126 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005127 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005128 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005129 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5130 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005131
Arnaud Patard44607122009-04-21 17:39:08 +03005132 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005133 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5134 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5135 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5136 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5137 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5138 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5139 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5140 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5141 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5142 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5143 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5144 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5145 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5146 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5147 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5148 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5149 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5150}
5151
blueswir18e853dc2008-10-05 10:49:32 +00005152static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005153 .convert = { host_to_target_termios, target_to_host_termios },
5154 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5155 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5156};
5157
bellard5286db72003-06-05 00:57:30 +00005158static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005159 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5160 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5161 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5162 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5163 MAP_ANONYMOUS, MAP_ANONYMOUS },
5164 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5165 MAP_GROWSDOWN, MAP_GROWSDOWN },
5166 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5167 MAP_DENYWRITE, MAP_DENYWRITE },
5168 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5169 MAP_EXECUTABLE, MAP_EXECUTABLE },
5170 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
5171 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
5172 MAP_NORESERVE, MAP_NORESERVE },
5173 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
5174 /* MAP_STACK had been ignored by the kernel for quite some time.
5175 Recognize it for the target insofar as we do not want to pass
5176 it through to the host. */
5177 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
5178 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00005179};
5180
bellard2ab83ea2003-06-15 19:56:46 +00005181#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005182
5183/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005184static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005185
bellard03acab62007-11-11 14:57:14 +00005186static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005187{
5188 int size;
pbrook53a59602006-03-25 19:31:22 +00005189 void *p;
bellard6dbad632003-03-16 18:05:05 +00005190
5191 if (!ldt_table)
5192 return 0;
5193 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5194 if (size > bytecount)
5195 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005196 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5197 if (!p)
bellard03acab62007-11-11 14:57:14 +00005198 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005199 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005200 memcpy(p, ldt_table, size);
5201 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005202 return size;
5203}
5204
5205/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005206static abi_long write_ldt(CPUX86State *env,
5207 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005208{
5209 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005210 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005211 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005212 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005213 uint32_t *lp, entry_1, entry_2;
5214
5215 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005216 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005217 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005218 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005219 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005220 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005221 ldt_info.limit = tswap32(target_ldt_info->limit);
5222 ldt_info.flags = tswap32(target_ldt_info->flags);
5223 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005224
bellard6dbad632003-03-16 18:05:05 +00005225 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005226 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005227 seg_32bit = ldt_info.flags & 1;
5228 contents = (ldt_info.flags >> 1) & 3;
5229 read_exec_only = (ldt_info.flags >> 3) & 1;
5230 limit_in_pages = (ldt_info.flags >> 4) & 1;
5231 seg_not_present = (ldt_info.flags >> 5) & 1;
5232 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005233#ifdef TARGET_ABI32
5234 lm = 0;
5235#else
5236 lm = (ldt_info.flags >> 7) & 1;
5237#endif
bellard6dbad632003-03-16 18:05:05 +00005238 if (contents == 3) {
5239 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005240 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005241 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005242 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005243 }
5244 /* allocate the LDT */
5245 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005246 env->ldt.base = target_mmap(0,
5247 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5248 PROT_READ|PROT_WRITE,
5249 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5250 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005251 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005252 memset(g2h(env->ldt.base), 0,
5253 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005254 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005255 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005256 }
5257
5258 /* NOTE: same code as Linux kernel */
5259 /* Allow LDTs to be cleared by the user. */
5260 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5261 if (oldmode ||
5262 (contents == 0 &&
5263 read_exec_only == 1 &&
5264 seg_32bit == 0 &&
5265 limit_in_pages == 0 &&
5266 seg_not_present == 1 &&
5267 useable == 0 )) {
5268 entry_1 = 0;
5269 entry_2 = 0;
5270 goto install;
5271 }
5272 }
ths3b46e622007-09-17 08:09:54 +00005273
bellard6dbad632003-03-16 18:05:05 +00005274 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5275 (ldt_info.limit & 0x0ffff);
5276 entry_2 = (ldt_info.base_addr & 0xff000000) |
5277 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5278 (ldt_info.limit & 0xf0000) |
5279 ((read_exec_only ^ 1) << 9) |
5280 (contents << 10) |
5281 ((seg_not_present ^ 1) << 15) |
5282 (seg_32bit << 22) |
5283 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005284 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005285 0x7000;
5286 if (!oldmode)
5287 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005288
bellard6dbad632003-03-16 18:05:05 +00005289 /* Install the new entry ... */
5290install:
5291 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5292 lp[0] = tswap32(entry_1);
5293 lp[1] = tswap32(entry_2);
5294 return 0;
5295}
5296
5297/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005298static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5299 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005300{
bellard03acab62007-11-11 14:57:14 +00005301 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005302
bellard6dbad632003-03-16 18:05:05 +00005303 switch (func) {
5304 case 0:
5305 ret = read_ldt(ptr, bytecount);
5306 break;
5307 case 1:
5308 ret = write_ldt(env, ptr, bytecount, 1);
5309 break;
5310 case 0x11:
5311 ret = write_ldt(env, ptr, bytecount, 0);
5312 break;
bellard03acab62007-11-11 14:57:14 +00005313 default:
5314 ret = -TARGET_ENOSYS;
5315 break;
bellard6dbad632003-03-16 18:05:05 +00005316 }
5317 return ret;
5318}
bellard1b6b0292003-03-22 17:31:38 +00005319
blueswir14583f582008-08-24 10:35:55 +00005320#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005321abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005322{
5323 uint64_t *gdt_table = g2h(env->gdt.base);
5324 struct target_modify_ldt_ldt_s ldt_info;
5325 struct target_modify_ldt_ldt_s *target_ldt_info;
5326 int seg_32bit, contents, read_exec_only, limit_in_pages;
5327 int seg_not_present, useable, lm;
5328 uint32_t *lp, entry_1, entry_2;
5329 int i;
5330
5331 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5332 if (!target_ldt_info)
5333 return -TARGET_EFAULT;
5334 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005335 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005336 ldt_info.limit = tswap32(target_ldt_info->limit);
5337 ldt_info.flags = tswap32(target_ldt_info->flags);
5338 if (ldt_info.entry_number == -1) {
5339 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5340 if (gdt_table[i] == 0) {
5341 ldt_info.entry_number = i;
5342 target_ldt_info->entry_number = tswap32(i);
5343 break;
5344 }
5345 }
5346 }
5347 unlock_user_struct(target_ldt_info, ptr, 1);
5348
5349 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5350 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5351 return -TARGET_EINVAL;
5352 seg_32bit = ldt_info.flags & 1;
5353 contents = (ldt_info.flags >> 1) & 3;
5354 read_exec_only = (ldt_info.flags >> 3) & 1;
5355 limit_in_pages = (ldt_info.flags >> 4) & 1;
5356 seg_not_present = (ldt_info.flags >> 5) & 1;
5357 useable = (ldt_info.flags >> 6) & 1;
5358#ifdef TARGET_ABI32
5359 lm = 0;
5360#else
5361 lm = (ldt_info.flags >> 7) & 1;
5362#endif
5363
5364 if (contents == 3) {
5365 if (seg_not_present == 0)
5366 return -TARGET_EINVAL;
5367 }
5368
5369 /* NOTE: same code as Linux kernel */
5370 /* Allow LDTs to be cleared by the user. */
5371 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5372 if ((contents == 0 &&
5373 read_exec_only == 1 &&
5374 seg_32bit == 0 &&
5375 limit_in_pages == 0 &&
5376 seg_not_present == 1 &&
5377 useable == 0 )) {
5378 entry_1 = 0;
5379 entry_2 = 0;
5380 goto install;
5381 }
5382 }
5383
5384 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5385 (ldt_info.limit & 0x0ffff);
5386 entry_2 = (ldt_info.base_addr & 0xff000000) |
5387 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5388 (ldt_info.limit & 0xf0000) |
5389 ((read_exec_only ^ 1) << 9) |
5390 (contents << 10) |
5391 ((seg_not_present ^ 1) << 15) |
5392 (seg_32bit << 22) |
5393 (limit_in_pages << 23) |
5394 (useable << 20) |
5395 (lm << 21) |
5396 0x7000;
5397
5398 /* Install the new entry ... */
5399install:
5400 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5401 lp[0] = tswap32(entry_1);
5402 lp[1] = tswap32(entry_2);
5403 return 0;
5404}
5405
blueswir18fcd3692008-08-17 20:26:25 +00005406static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005407{
5408 struct target_modify_ldt_ldt_s *target_ldt_info;
5409 uint64_t *gdt_table = g2h(env->gdt.base);
5410 uint32_t base_addr, limit, flags;
5411 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5412 int seg_not_present, useable, lm;
5413 uint32_t *lp, entry_1, entry_2;
5414
5415 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5416 if (!target_ldt_info)
5417 return -TARGET_EFAULT;
5418 idx = tswap32(target_ldt_info->entry_number);
5419 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5420 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5421 unlock_user_struct(target_ldt_info, ptr, 1);
5422 return -TARGET_EINVAL;
5423 }
5424 lp = (uint32_t *)(gdt_table + idx);
5425 entry_1 = tswap32(lp[0]);
5426 entry_2 = tswap32(lp[1]);
5427
5428 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5429 contents = (entry_2 >> 10) & 3;
5430 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5431 seg_32bit = (entry_2 >> 22) & 1;
5432 limit_in_pages = (entry_2 >> 23) & 1;
5433 useable = (entry_2 >> 20) & 1;
5434#ifdef TARGET_ABI32
5435 lm = 0;
5436#else
5437 lm = (entry_2 >> 21) & 1;
5438#endif
5439 flags = (seg_32bit << 0) | (contents << 1) |
5440 (read_exec_only << 3) | (limit_in_pages << 4) |
5441 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5442 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5443 base_addr = (entry_1 >> 16) |
5444 (entry_2 & 0xff000000) |
5445 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005446 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005447 target_ldt_info->limit = tswap32(limit);
5448 target_ldt_info->flags = tswap32(flags);
5449 unlock_user_struct(target_ldt_info, ptr, 1);
5450 return 0;
5451}
blueswir14583f582008-08-24 10:35:55 +00005452#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005453
bellardd2fd1af2007-11-14 18:08:56 +00005454#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005455abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005456{
Juan Quintela1add8692011-06-16 17:37:09 +01005457 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005458 abi_ulong val;
5459 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005460
bellardd2fd1af2007-11-14 18:08:56 +00005461 switch(code) {
5462 case TARGET_ARCH_SET_GS:
5463 case TARGET_ARCH_SET_FS:
5464 if (code == TARGET_ARCH_SET_GS)
5465 idx = R_GS;
5466 else
5467 idx = R_FS;
5468 cpu_x86_load_seg(env, idx, 0);
5469 env->segs[idx].base = addr;
5470 break;
5471 case TARGET_ARCH_GET_GS:
5472 case TARGET_ARCH_GET_FS:
5473 if (code == TARGET_ARCH_GET_GS)
5474 idx = R_GS;
5475 else
5476 idx = R_FS;
5477 val = env->segs[idx].base;
5478 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005479 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005480 break;
5481 default:
5482 ret = -TARGET_EINVAL;
5483 break;
5484 }
Juan Quintela1add8692011-06-16 17:37:09 +01005485 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005486}
5487#endif
5488
bellard2ab83ea2003-06-15 19:56:46 +00005489#endif /* defined(TARGET_I386) */
5490
Riku Voipio05098a92011-03-04 15:27:29 +02005491#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005492
pbrookd865bab2008-06-07 22:12:17 +00005493
5494static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5495typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005496 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005497 pthread_mutex_t mutex;
5498 pthread_cond_t cond;
5499 pthread_t thread;
5500 uint32_t tid;
5501 abi_ulong child_tidptr;
5502 abi_ulong parent_tidptr;
5503 sigset_t sigmask;
5504} new_thread_info;
5505
5506static void *clone_func(void *arg)
5507{
5508 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005509 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005510 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005511 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005512
Emilio G. Cota70903762015-08-23 20:23:41 -04005513 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04005514 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005515 env = info->env;
Richard Henderson29a0af62019-03-22 16:07:18 -07005516 cpu = env_cpu(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005517 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005518 ts = (TaskState *)cpu->opaque;
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00005519 info->tid = sys_gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005520 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005521 if (info->child_tidptr)
5522 put_user_u32(info->tid, info->child_tidptr);
5523 if (info->parent_tidptr)
5524 put_user_u32(info->tid, info->parent_tidptr);
Richard Henderson5ebdd772019-03-14 13:10:53 -07005525 qemu_guest_random_seed_thread_part2(cpu->random_seed);
pbrookd865bab2008-06-07 22:12:17 +00005526 /* Enable signals. */
5527 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5528 /* Signal to the parent that we're ready. */
5529 pthread_mutex_lock(&info->mutex);
5530 pthread_cond_broadcast(&info->cond);
5531 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04005532 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00005533 pthread_mutex_lock(&clone_lock);
5534 pthread_mutex_unlock(&clone_lock);
5535 cpu_loop(env);
5536 /* never exits */
5537 return NULL;
5538}
bellard1b6b0292003-03-22 17:31:38 +00005539
ths0da46a62007-10-20 20:23:07 +00005540/* do_fork() Must return host values and target errnos (unlike most
5541 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005542static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005543 abi_ulong parent_tidptr, target_ulong newtls,
5544 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005545{
Richard Henderson29a0af62019-03-22 16:07:18 -07005546 CPUState *cpu = env_cpu(env);
bellard1b6b0292003-03-22 17:31:38 +00005547 int ret;
bellard5cd43932003-03-29 16:54:36 +00005548 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005549 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005550 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005551 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005552
Peter Maydell5ea2fc82016-08-02 18:41:27 +01005553 flags &= ~CLONE_IGNORED_FLAGS;
5554
balrog436d1242008-09-21 02:39:45 +00005555 /* Emulate vfork() with fork() */
5556 if (flags & CLONE_VFORK)
5557 flags &= ~(CLONE_VFORK | CLONE_VM);
5558
bellard1b6b0292003-03-22 17:31:38 +00005559 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005560 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005561 new_thread_info info;
5562 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005563
Peter Maydell5ea2fc82016-08-02 18:41:27 +01005564 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
5565 (flags & CLONE_INVALID_THREAD_FLAGS)) {
5566 return -TARGET_EINVAL;
5567 }
5568
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005569 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005570 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07005571
5572 /* Grab a mutex so that thread setup appears atomic. */
5573 pthread_mutex_lock(&clone_lock);
5574
bellard1b6b0292003-03-22 17:31:38 +00005575 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005576 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005577 /* Init regs that differ from the parent. */
5578 cpu_clone_regs(new_env, newsp);
Richard Henderson29a0af62019-03-22 16:07:18 -07005579 new_cpu = env_cpu(new_env);
Andreas Färber0429a972013-08-26 18:14:44 +02005580 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005581 ts->bprm = parent_ts->bprm;
5582 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005583 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005584
Peter Maydell7cfbd382016-08-02 18:41:26 +01005585 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00005586 ts->child_tidptr = child_tidptr;
5587 }
5588
Peter Maydell7cfbd382016-08-02 18:41:26 +01005589 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00005590 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01005591 }
pbrookd865bab2008-06-07 22:12:17 +00005592
pbrookd865bab2008-06-07 22:12:17 +00005593 memset(&info, 0, sizeof(info));
5594 pthread_mutex_init(&info.mutex, NULL);
5595 pthread_mutex_lock(&info.mutex);
5596 pthread_cond_init(&info.cond, NULL);
5597 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01005598 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00005599 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01005600 }
5601 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00005602 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01005603 }
pbrookd865bab2008-06-07 22:12:17 +00005604
5605 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005606 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5607 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005608 /* It is not safe to deliver signals until the child has finished
5609 initializing, so temporarily block all signals. */
5610 sigfillset(&sigmask);
5611 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
Richard Henderson5ebdd772019-03-14 13:10:53 -07005612 cpu->random_seed = qemu_guest_random_seed_thread_part1();
pbrookd865bab2008-06-07 22:12:17 +00005613
Alex Bennéeb67cb682016-10-05 11:13:04 -07005614 /* If this is our first additional thread, we need to ensure we
5615 * generate code for parallel execution and flush old translations.
5616 */
5617 if (!parallel_cpus) {
5618 parallel_cpus = true;
5619 tb_flush(cpu);
5620 }
5621
pbrookd865bab2008-06-07 22:12:17 +00005622 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005623 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005624
5625 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5626 pthread_attr_destroy(&attr);
5627 if (ret == 0) {
5628 /* Wait for the child to initialize. */
5629 pthread_cond_wait(&info.cond, &info.mutex);
5630 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00005631 } else {
5632 ret = -1;
5633 }
5634 pthread_mutex_unlock(&info.mutex);
5635 pthread_cond_destroy(&info.cond);
5636 pthread_mutex_destroy(&info.mutex);
5637 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005638 } else {
5639 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01005640 if (flags & CLONE_INVALID_FORK_FLAGS) {
5641 return -TARGET_EINVAL;
5642 }
5643
5644 /* We can't support custom termination signals */
5645 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005646 return -TARGET_EINVAL;
5647 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005648
5649 if (block_signals()) {
5650 return -TARGET_ERESTARTSYS;
5651 }
5652
pbrookd865bab2008-06-07 22:12:17 +00005653 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005654 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005655 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005656 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00005657 cpu_clone_regs(env, newsp);
5658 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005659 /* There is a race condition here. The parent process could
5660 theoretically read the TID in the child process before the child
5661 tid is set. This would require using either ptrace
5662 (not implemented) or having *_tidptr to point at a shared memory
5663 mapping. We can't repeat the spinlock hack used above because
5664 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005665 if (flags & CLONE_CHILD_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00005666 put_user_u32(sys_gettid(), child_tidptr);
pbrookd865bab2008-06-07 22:12:17 +00005667 if (flags & CLONE_PARENT_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00005668 put_user_u32(sys_gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005669 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005670 if (flags & CLONE_SETTLS)
5671 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005672 if (flags & CLONE_CHILD_CLEARTID)
5673 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005674 } else {
5675 fork_end(0);
5676 }
bellard1b6b0292003-03-22 17:31:38 +00005677 }
5678 return ret;
5679}
5680
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005681/* warning : doesn't handle linux specific flags... */
5682static int target_to_host_fcntl_cmd(int cmd)
5683{
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005684 int ret;
5685
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005686 switch(cmd) {
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005687 case TARGET_F_DUPFD:
5688 case TARGET_F_GETFD:
5689 case TARGET_F_SETFD:
5690 case TARGET_F_GETFL:
5691 case TARGET_F_SETFL:
5692 ret = cmd;
5693 break;
5694 case TARGET_F_GETLK:
5695 ret = F_GETLK64;
5696 break;
5697 case TARGET_F_SETLK:
5698 ret = F_SETLK64;
5699 break;
5700 case TARGET_F_SETLKW:
5701 ret = F_SETLKW64;
5702 break;
5703 case TARGET_F_GETOWN:
5704 ret = F_GETOWN;
5705 break;
5706 case TARGET_F_SETOWN:
5707 ret = F_SETOWN;
5708 break;
5709 case TARGET_F_GETSIG:
5710 ret = F_GETSIG;
5711 break;
5712 case TARGET_F_SETSIG:
5713 ret = F_SETSIG;
5714 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005715#if TARGET_ABI_BITS == 32
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005716 case TARGET_F_GETLK64:
5717 ret = F_GETLK64;
5718 break;
5719 case TARGET_F_SETLK64:
5720 ret = F_SETLK64;
5721 break;
5722 case TARGET_F_SETLKW64:
5723 ret = F_SETLKW64;
5724 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005725#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005726 case TARGET_F_SETLEASE:
5727 ret = F_SETLEASE;
5728 break;
5729 case TARGET_F_GETLEASE:
5730 ret = F_GETLEASE;
5731 break;
malcfbd5de92009-09-06 06:31:59 +04005732#ifdef F_DUPFD_CLOEXEC
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005733 case TARGET_F_DUPFD_CLOEXEC:
5734 ret = F_DUPFD_CLOEXEC;
5735 break;
malcfbd5de92009-09-06 06:31:59 +04005736#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005737 case TARGET_F_NOTIFY:
5738 ret = F_NOTIFY;
5739 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005740#ifdef F_GETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005741 case TARGET_F_GETOWN_EX:
5742 ret = F_GETOWN_EX;
5743 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005744#endif
5745#ifdef F_SETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005746 case TARGET_F_SETOWN_EX:
5747 ret = F_SETOWN_EX;
5748 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005749#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01005750#ifdef F_SETPIPE_SZ
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005751 case TARGET_F_SETPIPE_SZ:
5752 ret = F_SETPIPE_SZ;
5753 break;
5754 case TARGET_F_GETPIPE_SZ:
5755 ret = F_GETPIPE_SZ;
5756 break;
Peter Maydellddf31aa2016-06-30 17:33:49 +01005757#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005758 default:
5759 ret = -TARGET_EINVAL;
5760 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005761 }
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05005762
5763#if defined(__powerpc64__)
5764 /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
5765 * is not supported by kernel. The glibc fcntl call actually adjusts
5766 * them to 5, 6 and 7 before making the syscall(). Since we make the
5767 * syscall directly, adjust to what is supported by the kernel.
5768 */
5769 if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
5770 ret -= F_GETLK64 - 5;
5771 }
5772#endif
5773
5774 return ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005775}
5776
Laurent Vivierae68ad92018-05-10 01:11:21 +02005777#define FLOCK_TRANSTBL \
5778 switch (type) { \
5779 TRANSTBL_CONVERT(F_RDLCK); \
5780 TRANSTBL_CONVERT(F_WRLCK); \
5781 TRANSTBL_CONVERT(F_UNLCK); \
5782 TRANSTBL_CONVERT(F_EXLCK); \
5783 TRANSTBL_CONVERT(F_SHLCK); \
5784 }
5785
5786static int target_to_host_flock(int type)
5787{
5788#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
5789 FLOCK_TRANSTBL
5790#undef TRANSTBL_CONVERT
5791 return -TARGET_EINVAL;
5792}
5793
5794static int host_to_target_flock(int type)
5795{
5796#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
5797 FLOCK_TRANSTBL
5798#undef TRANSTBL_CONVERT
5799 /* if we don't know how to convert the value coming
5800 * from the host we copy to the target field as-is
5801 */
5802 return type;
5803}
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005804
Peter Maydell213d3e92016-06-13 11:22:05 +01005805static inline abi_long copy_from_user_flock(struct flock64 *fl,
5806 abi_ulong target_flock_addr)
5807{
5808 struct target_flock *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02005809 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005810
5811 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5812 return -TARGET_EFAULT;
5813 }
5814
5815 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02005816 l_type = target_to_host_flock(l_type);
5817 if (l_type < 0) {
5818 return l_type;
5819 }
5820 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005821 __get_user(fl->l_whence, &target_fl->l_whence);
5822 __get_user(fl->l_start, &target_fl->l_start);
5823 __get_user(fl->l_len, &target_fl->l_len);
5824 __get_user(fl->l_pid, &target_fl->l_pid);
5825 unlock_user_struct(target_fl, target_flock_addr, 0);
5826 return 0;
5827}
5828
5829static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
5830 const struct flock64 *fl)
5831{
5832 struct target_flock *target_fl;
5833 short l_type;
5834
5835 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5836 return -TARGET_EFAULT;
5837 }
5838
Laurent Vivierae68ad92018-05-10 01:11:21 +02005839 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01005840 __put_user(l_type, &target_fl->l_type);
5841 __put_user(fl->l_whence, &target_fl->l_whence);
5842 __put_user(fl->l_start, &target_fl->l_start);
5843 __put_user(fl->l_len, &target_fl->l_len);
5844 __put_user(fl->l_pid, &target_fl->l_pid);
5845 unlock_user_struct(target_fl, target_flock_addr, 1);
5846 return 0;
5847}
5848
5849typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
5850typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
5851
5852#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
Laurent Vivier7f254c52018-05-02 23:57:30 +02005853static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01005854 abi_ulong target_flock_addr)
5855{
Laurent Vivier7f254c52018-05-02 23:57:30 +02005856 struct target_oabi_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02005857 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005858
5859 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5860 return -TARGET_EFAULT;
5861 }
5862
5863 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02005864 l_type = target_to_host_flock(l_type);
5865 if (l_type < 0) {
5866 return l_type;
5867 }
5868 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005869 __get_user(fl->l_whence, &target_fl->l_whence);
5870 __get_user(fl->l_start, &target_fl->l_start);
5871 __get_user(fl->l_len, &target_fl->l_len);
5872 __get_user(fl->l_pid, &target_fl->l_pid);
5873 unlock_user_struct(target_fl, target_flock_addr, 0);
5874 return 0;
5875}
5876
Laurent Vivier7f254c52018-05-02 23:57:30 +02005877static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
Peter Maydell213d3e92016-06-13 11:22:05 +01005878 const struct flock64 *fl)
5879{
Laurent Vivier7f254c52018-05-02 23:57:30 +02005880 struct target_oabi_flock64 *target_fl;
Peter Maydell213d3e92016-06-13 11:22:05 +01005881 short l_type;
5882
5883 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5884 return -TARGET_EFAULT;
5885 }
5886
Laurent Vivierae68ad92018-05-10 01:11:21 +02005887 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01005888 __put_user(l_type, &target_fl->l_type);
5889 __put_user(fl->l_whence, &target_fl->l_whence);
5890 __put_user(fl->l_start, &target_fl->l_start);
5891 __put_user(fl->l_len, &target_fl->l_len);
5892 __put_user(fl->l_pid, &target_fl->l_pid);
5893 unlock_user_struct(target_fl, target_flock_addr, 1);
5894 return 0;
5895}
5896#endif
5897
5898static inline abi_long copy_from_user_flock64(struct flock64 *fl,
5899 abi_ulong target_flock_addr)
5900{
5901 struct target_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02005902 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005903
5904 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
5905 return -TARGET_EFAULT;
5906 }
5907
5908 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02005909 l_type = target_to_host_flock(l_type);
5910 if (l_type < 0) {
5911 return l_type;
5912 }
5913 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01005914 __get_user(fl->l_whence, &target_fl->l_whence);
5915 __get_user(fl->l_start, &target_fl->l_start);
5916 __get_user(fl->l_len, &target_fl->l_len);
5917 __get_user(fl->l_pid, &target_fl->l_pid);
5918 unlock_user_struct(target_fl, target_flock_addr, 0);
5919 return 0;
5920}
5921
5922static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
5923 const struct flock64 *fl)
5924{
5925 struct target_flock64 *target_fl;
5926 short l_type;
5927
5928 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
5929 return -TARGET_EFAULT;
5930 }
5931
Laurent Vivierae68ad92018-05-10 01:11:21 +02005932 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01005933 __put_user(l_type, &target_fl->l_type);
5934 __put_user(fl->l_whence, &target_fl->l_whence);
5935 __put_user(fl->l_start, &target_fl->l_start);
5936 __put_user(fl->l_len, &target_fl->l_len);
5937 __put_user(fl->l_pid, &target_fl->l_pid);
5938 unlock_user_struct(target_fl, target_flock_addr, 1);
5939 return 0;
5940}
5941
blueswir1992f48a2007-10-14 16:27:31 +00005942static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005943{
ths43f238d2007-01-05 20:55:49 +00005944 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005945#ifdef F_GETOWN_EX
5946 struct f_owner_ex fox;
5947 struct target_f_owner_ex *target_fox;
5948#endif
blueswir1992f48a2007-10-14 16:27:31 +00005949 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005950 int host_cmd = target_to_host_fcntl_cmd(cmd);
5951
5952 if (host_cmd == -TARGET_EINVAL)
5953 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005954
bellard7775e9e2003-05-14 22:46:48 +00005955 switch(cmd) {
5956 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01005957 ret = copy_from_user_flock(&fl64, arg);
5958 if (ret) {
5959 return ret;
5960 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005961 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005962 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005963 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00005964 }
5965 break;
ths3b46e622007-09-17 08:09:54 +00005966
bellard7775e9e2003-05-14 22:46:48 +00005967 case TARGET_F_SETLK:
5968 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01005969 ret = copy_from_user_flock(&fl64, arg);
5970 if (ret) {
5971 return ret;
5972 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005973 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005974 break;
ths3b46e622007-09-17 08:09:54 +00005975
bellard7775e9e2003-05-14 22:46:48 +00005976 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005977 ret = copy_from_user_flock64(&fl64, arg);
5978 if (ret) {
5979 return ret;
5980 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005981 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005982 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01005983 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00005984 }
bellard9ee1fa22007-11-11 15:11:19 +00005985 break;
bellard7775e9e2003-05-14 22:46:48 +00005986 case TARGET_F_SETLK64:
5987 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01005988 ret = copy_from_user_flock64(&fl64, arg);
5989 if (ret) {
5990 return ret;
5991 }
Peter Maydell435da5e2016-06-13 11:22:05 +01005992 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005993 break;
5994
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005995 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01005996 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005997 if (ret >= 0) {
5998 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5999 }
bellardffa65c32004-01-04 23:57:22 +00006000 break;
6001
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006002 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006003 ret = get_errno(safe_fcntl(fd, host_cmd,
6004 target_to_host_bitmask(arg,
6005 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006006 break;
6007
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006008#ifdef F_GETOWN_EX
6009 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006010 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006011 if (ret >= 0) {
6012 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6013 return -TARGET_EFAULT;
6014 target_fox->type = tswap32(fox.type);
6015 target_fox->pid = tswap32(fox.pid);
6016 unlock_user_struct(target_fox, arg, 1);
6017 }
6018 break;
6019#endif
6020
6021#ifdef F_SETOWN_EX
6022 case TARGET_F_SETOWN_EX:
6023 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6024 return -TARGET_EFAULT;
6025 fox.type = tswap32(target_fox->type);
6026 fox.pid = tswap32(target_fox->pid);
6027 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006028 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006029 break;
6030#endif
6031
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006032 case TARGET_F_SETOWN:
6033 case TARGET_F_GETOWN:
6034 case TARGET_F_SETSIG:
6035 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006036 case TARGET_F_SETLEASE:
6037 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006038 case TARGET_F_SETPIPE_SZ:
6039 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006040 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006041 break;
6042
bellard7775e9e2003-05-14 22:46:48 +00006043 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006044 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006045 break;
6046 }
6047 return ret;
6048}
6049
bellard67867302003-11-23 17:05:30 +00006050#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006051
bellard67867302003-11-23 17:05:30 +00006052static inline int high2lowuid(int uid)
6053{
6054 if (uid > 65535)
6055 return 65534;
6056 else
6057 return uid;
6058}
6059
6060static inline int high2lowgid(int gid)
6061{
6062 if (gid > 65535)
6063 return 65534;
6064 else
6065 return gid;
6066}
6067
6068static inline int low2highuid(int uid)
6069{
6070 if ((int16_t)uid == -1)
6071 return -1;
6072 else
6073 return uid;
6074}
6075
6076static inline int low2highgid(int gid)
6077{
6078 if ((int16_t)gid == -1)
6079 return -1;
6080 else
6081 return gid;
6082}
Riku Voipio0c866a72011-04-18 15:23:06 +03006083static inline int tswapid(int id)
6084{
6085 return tswap16(id);
6086}
Peter Maydell76ca3102014-03-02 19:36:41 +00006087
6088#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6089
Riku Voipio0c866a72011-04-18 15:23:06 +03006090#else /* !USE_UID16 */
6091static inline int high2lowuid(int uid)
6092{
6093 return uid;
6094}
6095static inline int high2lowgid(int gid)
6096{
6097 return gid;
6098}
6099static inline int low2highuid(int uid)
6100{
6101 return uid;
6102}
6103static inline int low2highgid(int gid)
6104{
6105 return gid;
6106}
6107static inline int tswapid(int id)
6108{
6109 return tswap32(id);
6110}
Peter Maydell76ca3102014-03-02 19:36:41 +00006111
6112#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6113
bellard67867302003-11-23 17:05:30 +00006114#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006115
Peter Maydellfd6f7792016-03-01 16:33:02 +00006116/* We must do direct syscalls for setting UID/GID, because we want to
6117 * implement the Linux system call semantics of "change only for this thread",
6118 * not the libc/POSIX semantics of "change for all threads in process".
6119 * (See http://ewontfix.com/17/ for more details.)
6120 * We use the 32-bit version of the syscalls if present; if it is not
6121 * then either the host architecture supports 32-bit UIDs natively with
6122 * the standard syscall, or the 16-bit UID is the best we can do.
6123 */
6124#ifdef __NR_setuid32
6125#define __NR_sys_setuid __NR_setuid32
6126#else
6127#define __NR_sys_setuid __NR_setuid
6128#endif
6129#ifdef __NR_setgid32
6130#define __NR_sys_setgid __NR_setgid32
6131#else
6132#define __NR_sys_setgid __NR_setgid
6133#endif
6134#ifdef __NR_setresuid32
6135#define __NR_sys_setresuid __NR_setresuid32
6136#else
6137#define __NR_sys_setresuid __NR_setresuid
6138#endif
6139#ifdef __NR_setresgid32
6140#define __NR_sys_setresgid __NR_setresgid32
6141#else
6142#define __NR_sys_setresgid __NR_setresgid
6143#endif
6144
6145_syscall1(int, sys_setuid, uid_t, uid)
6146_syscall1(int, sys_setgid, gid_t, gid)
6147_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6148_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6149
bellard31e31b82003-02-18 22:55:36 +00006150void syscall_init(void)
6151{
bellard2ab83ea2003-06-15 19:56:46 +00006152 IOCTLEntry *ie;
6153 const argtype *arg_type;
6154 int size;
thsb92c47c2007-11-01 00:07:38 +00006155 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006156
Alexander Graf8be656b2015-05-06 23:47:32 +02006157 thunk_init(STRUCT_MAX);
6158
Blue Swirl001faf32009-05-13 17:53:17 +00006159#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006160#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006161#include "syscall_types.h"
6162#undef STRUCT
6163#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006164
Peter Maydelldd6e9572012-07-23 08:07:22 +00006165 /* Build target_to_host_errno_table[] table from
6166 * host_to_target_errno_table[]. */
6167 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6168 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6169 }
6170
bellard2ab83ea2003-06-15 19:56:46 +00006171 /* we patch the ioctl size if necessary. We rely on the fact that
6172 no ioctl has all the bits at '1' in the size field */
6173 ie = ioctl_entries;
6174 while (ie->target_cmd != 0) {
6175 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6176 TARGET_IOC_SIZEMASK) {
6177 arg_type = ie->arg_type;
6178 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006179 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006180 ie->target_cmd);
6181 exit(1);
6182 }
6183 arg_type++;
6184 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006185 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006186 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6187 (size << TARGET_IOC_SIZESHIFT);
6188 }
thsb92c47c2007-11-01 00:07:38 +00006189
bellard2ab83ea2003-06-15 19:56:46 +00006190 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006191#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6192 (defined(__x86_64__) && defined(TARGET_X86_64))
6193 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6194 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6195 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006196 }
6197#endif
6198 ie++;
6199 }
bellard31e31b82003-02-18 22:55:36 +00006200}
bellardc573ff62004-01-04 15:51:36 +00006201
blueswir1992f48a2007-10-14 16:27:31 +00006202#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006203static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6204{
thsaf325d32008-06-10 15:29:15 +00006205#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006206 return ((uint64_t)word0 << 32) | word1;
6207#else
6208 return ((uint64_t)word1 << 32) | word0;
6209#endif
6210}
blueswir1992f48a2007-10-14 16:27:31 +00006211#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006212static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6213{
6214 return word0;
6215}
blueswir1992f48a2007-10-14 16:27:31 +00006216#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006217
6218#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006219static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6220 abi_long arg2,
6221 abi_long arg3,
6222 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006223{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006224 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006225 arg2 = arg3;
6226 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006227 }
pbrookce4defa2006-02-09 16:49:55 +00006228 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6229}
6230#endif
6231
6232#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006233static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6234 abi_long arg2,
6235 abi_long arg3,
6236 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006237{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006238 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006239 arg2 = arg3;
6240 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006241 }
pbrookce4defa2006-02-09 16:49:55 +00006242 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6243}
6244#endif
6245
bellard579a97f2007-11-11 14:26:47 +00006246static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6247 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006248{
6249 struct target_timespec *target_ts;
6250
bellard579a97f2007-11-11 14:26:47 +00006251 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6252 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006253 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6254 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006255 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006256 return 0;
pbrook53a59602006-03-25 19:31:22 +00006257}
6258
bellard579a97f2007-11-11 14:26:47 +00006259static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6260 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006261{
6262 struct target_timespec *target_ts;
6263
bellard579a97f2007-11-11 14:26:47 +00006264 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6265 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006266 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6267 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006268 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006269 return 0;
pbrook53a59602006-03-25 19:31:22 +00006270}
6271
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006272static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6273 abi_ulong target_addr)
6274{
6275 struct target_itimerspec *target_itspec;
6276
6277 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6278 return -TARGET_EFAULT;
6279 }
6280
6281 host_itspec->it_interval.tv_sec =
6282 tswapal(target_itspec->it_interval.tv_sec);
6283 host_itspec->it_interval.tv_nsec =
6284 tswapal(target_itspec->it_interval.tv_nsec);
6285 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6286 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6287
6288 unlock_user_struct(target_itspec, target_addr, 1);
6289 return 0;
6290}
6291
6292static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6293 struct itimerspec *host_its)
6294{
6295 struct target_itimerspec *target_itspec;
6296
6297 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6298 return -TARGET_EFAULT;
6299 }
6300
6301 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6302 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6303
6304 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6305 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6306
6307 unlock_user_struct(target_itspec, target_addr, 0);
6308 return 0;
6309}
6310
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02006311static inline abi_long target_to_host_timex(struct timex *host_tx,
6312 abi_long target_addr)
6313{
6314 struct target_timex *target_tx;
6315
6316 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
6317 return -TARGET_EFAULT;
6318 }
6319
6320 __get_user(host_tx->modes, &target_tx->modes);
6321 __get_user(host_tx->offset, &target_tx->offset);
6322 __get_user(host_tx->freq, &target_tx->freq);
6323 __get_user(host_tx->maxerror, &target_tx->maxerror);
6324 __get_user(host_tx->esterror, &target_tx->esterror);
6325 __get_user(host_tx->status, &target_tx->status);
6326 __get_user(host_tx->constant, &target_tx->constant);
6327 __get_user(host_tx->precision, &target_tx->precision);
6328 __get_user(host_tx->tolerance, &target_tx->tolerance);
6329 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6330 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
6331 __get_user(host_tx->tick, &target_tx->tick);
6332 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
6333 __get_user(host_tx->jitter, &target_tx->jitter);
6334 __get_user(host_tx->shift, &target_tx->shift);
6335 __get_user(host_tx->stabil, &target_tx->stabil);
6336 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
6337 __get_user(host_tx->calcnt, &target_tx->calcnt);
6338 __get_user(host_tx->errcnt, &target_tx->errcnt);
6339 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
6340 __get_user(host_tx->tai, &target_tx->tai);
6341
6342 unlock_user_struct(target_tx, target_addr, 0);
6343 return 0;
6344}
6345
6346static inline abi_long host_to_target_timex(abi_long target_addr,
6347 struct timex *host_tx)
6348{
6349 struct target_timex *target_tx;
6350
6351 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
6352 return -TARGET_EFAULT;
6353 }
6354
6355 __put_user(host_tx->modes, &target_tx->modes);
6356 __put_user(host_tx->offset, &target_tx->offset);
6357 __put_user(host_tx->freq, &target_tx->freq);
6358 __put_user(host_tx->maxerror, &target_tx->maxerror);
6359 __put_user(host_tx->esterror, &target_tx->esterror);
6360 __put_user(host_tx->status, &target_tx->status);
6361 __put_user(host_tx->constant, &target_tx->constant);
6362 __put_user(host_tx->precision, &target_tx->precision);
6363 __put_user(host_tx->tolerance, &target_tx->tolerance);
6364 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6365 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
6366 __put_user(host_tx->tick, &target_tx->tick);
6367 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
6368 __put_user(host_tx->jitter, &target_tx->jitter);
6369 __put_user(host_tx->shift, &target_tx->shift);
6370 __put_user(host_tx->stabil, &target_tx->stabil);
6371 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
6372 __put_user(host_tx->calcnt, &target_tx->calcnt);
6373 __put_user(host_tx->errcnt, &target_tx->errcnt);
6374 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
6375 __put_user(host_tx->tai, &target_tx->tai);
6376
6377 unlock_user_struct(target_tx, target_addr, 1);
6378 return 0;
6379}
6380
6381
Peter Maydellc0659762014-08-09 15:42:32 +01006382static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6383 abi_ulong target_addr)
6384{
6385 struct target_sigevent *target_sevp;
6386
6387 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6388 return -TARGET_EFAULT;
6389 }
6390
6391 /* This union is awkward on 64 bit systems because it has a 32 bit
6392 * integer and a pointer in it; we follow the conversion approach
6393 * used for handling sigval types in signal.c so the guest should get
6394 * the correct value back even if we did a 64 bit byteswap and it's
6395 * using the 32 bit integer.
6396 */
6397 host_sevp->sigev_value.sival_ptr =
6398 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6399 host_sevp->sigev_signo =
6400 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6401 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6402 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6403
6404 unlock_user_struct(target_sevp, target_addr, 1);
6405 return 0;
6406}
6407
Tom Musta6f6a4032014-08-12 13:53:42 -05006408#if defined(TARGET_NR_mlockall)
6409static inline int target_to_host_mlockall_arg(int arg)
6410{
6411 int result = 0;
6412
6413 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6414 result |= MCL_CURRENT;
6415 }
6416 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6417 result |= MCL_FUTURE;
6418 }
6419 return result;
6420}
6421#endif
6422
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02006423#if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \
6424 defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \
6425 defined(TARGET_NR_newfstatat))
balrog6a24a772008-09-20 02:23:36 +00006426static inline abi_long host_to_target_stat64(void *cpu_env,
6427 abi_ulong target_addr,
6428 struct stat *host_st)
6429{
Alexander Graf09701192013-09-03 20:12:15 +01006430#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006431 if (((CPUARMState *)cpu_env)->eabi) {
6432 struct target_eabi_stat64 *target_st;
6433
6434 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6435 return -TARGET_EFAULT;
6436 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6437 __put_user(host_st->st_dev, &target_st->st_dev);
6438 __put_user(host_st->st_ino, &target_st->st_ino);
6439#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6440 __put_user(host_st->st_ino, &target_st->__st_ino);
6441#endif
6442 __put_user(host_st->st_mode, &target_st->st_mode);
6443 __put_user(host_st->st_nlink, &target_st->st_nlink);
6444 __put_user(host_st->st_uid, &target_st->st_uid);
6445 __put_user(host_st->st_gid, &target_st->st_gid);
6446 __put_user(host_st->st_rdev, &target_st->st_rdev);
6447 __put_user(host_st->st_size, &target_st->st_size);
6448 __put_user(host_st->st_blksize, &target_st->st_blksize);
6449 __put_user(host_st->st_blocks, &target_st->st_blocks);
6450 __put_user(host_st->st_atime, &target_st->target_st_atime);
6451 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6452 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08006453#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
6454 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
6455 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
6456 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
6457#endif
balrog6a24a772008-09-20 02:23:36 +00006458 unlock_user_struct(target_st, target_addr, 1);
6459 } else
6460#endif
6461 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006462#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006463 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006464#else
6465 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006466#endif
balrog6a24a772008-09-20 02:23:36 +00006467
6468 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6469 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006470 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006471 __put_user(host_st->st_dev, &target_st->st_dev);
6472 __put_user(host_st->st_ino, &target_st->st_ino);
6473#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6474 __put_user(host_st->st_ino, &target_st->__st_ino);
6475#endif
6476 __put_user(host_st->st_mode, &target_st->st_mode);
6477 __put_user(host_st->st_nlink, &target_st->st_nlink);
6478 __put_user(host_st->st_uid, &target_st->st_uid);
6479 __put_user(host_st->st_gid, &target_st->st_gid);
6480 __put_user(host_st->st_rdev, &target_st->st_rdev);
6481 /* XXX: better use of kernel struct */
6482 __put_user(host_st->st_size, &target_st->st_size);
6483 __put_user(host_st->st_blksize, &target_st->st_blksize);
6484 __put_user(host_st->st_blocks, &target_st->st_blocks);
6485 __put_user(host_st->st_atime, &target_st->target_st_atime);
6486 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6487 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08006488#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
6489 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
6490 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
6491 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
6492#endif
balrog6a24a772008-09-20 02:23:36 +00006493 unlock_user_struct(target_st, target_addr, 1);
6494 }
6495
6496 return 0;
6497}
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02006498#endif
balrog6a24a772008-09-20 02:23:36 +00006499
pbrookbd0c5662008-05-29 14:34:11 +00006500/* ??? Using host futex calls even when target atomic operations
6501 are not really atomic probably breaks things. However implementing
6502 futexes locally would make futexes shared between multiple processes
6503 tricky. However they're probably useless because guest atomic
6504 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006505static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6506 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006507{
6508 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006509 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006510
6511 /* ??? We assume FUTEX_* constants are the same on both host
6512 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006513#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006514 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006515#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006516 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006517#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006518 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006519 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006520 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006521 if (timeout) {
6522 pts = &ts;
6523 target_to_host_timespec(pts, timeout);
6524 } else {
6525 pts = NULL;
6526 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006527 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006528 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006529 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006530 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006531 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006532 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006533 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006534 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006535 case FUTEX_WAKE_OP:
6536 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6537 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6538 But the prototype takes a `struct timespec *'; insert casts
6539 to satisfy the compiler. We do not need to tswap TIMEOUT
6540 since it's not compared to guest memory. */
6541 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006542 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6543 g2h(uaddr2),
6544 (base_op == FUTEX_CMP_REQUEUE
6545 ? tswap32(val3)
6546 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006547 default:
6548 return -TARGET_ENOSYS;
6549 }
6550}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006551#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6552static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6553 abi_long handle, abi_long mount_id,
6554 abi_long flags)
6555{
6556 struct file_handle *target_fh;
6557 struct file_handle *fh;
6558 int mid = 0;
6559 abi_long ret;
6560 char *name;
6561 unsigned int size, total_size;
6562
6563 if (get_user_s32(size, handle)) {
6564 return -TARGET_EFAULT;
6565 }
6566
6567 name = lock_user_string(pathname);
6568 if (!name) {
6569 return -TARGET_EFAULT;
6570 }
6571
6572 total_size = sizeof(struct file_handle) + size;
6573 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6574 if (!target_fh) {
6575 unlock_user(name, pathname, 0);
6576 return -TARGET_EFAULT;
6577 }
6578
6579 fh = g_malloc0(total_size);
6580 fh->handle_bytes = size;
6581
6582 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6583 unlock_user(name, pathname, 0);
6584
6585 /* man name_to_handle_at(2):
6586 * Other than the use of the handle_bytes field, the caller should treat
6587 * the file_handle structure as an opaque data type
6588 */
6589
6590 memcpy(target_fh, fh, total_size);
6591 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6592 target_fh->handle_type = tswap32(fh->handle_type);
6593 g_free(fh);
6594 unlock_user(target_fh, handle, total_size);
6595
6596 if (put_user_s32(mid, mount_id)) {
6597 return -TARGET_EFAULT;
6598 }
6599
6600 return ret;
6601
6602}
6603#endif
6604
6605#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6606static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6607 abi_long flags)
6608{
6609 struct file_handle *target_fh;
6610 struct file_handle *fh;
6611 unsigned int size, total_size;
6612 abi_long ret;
6613
6614 if (get_user_s32(size, handle)) {
6615 return -TARGET_EFAULT;
6616 }
6617
6618 total_size = sizeof(struct file_handle) + size;
6619 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6620 if (!target_fh) {
6621 return -TARGET_EFAULT;
6622 }
6623
Thomas Huthe9d49d52015-10-09 17:56:38 +02006624 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006625 fh->handle_bytes = size;
6626 fh->handle_type = tswap32(target_fh->handle_type);
6627
6628 ret = get_errno(open_by_handle_at(mount_fd, fh,
6629 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6630
6631 g_free(fh);
6632
6633 unlock_user(target_fh, handle, total_size);
6634
6635 return ret;
6636}
6637#endif
pbrookbd0c5662008-05-29 14:34:11 +00006638
Laurent Viviere36800c2015-10-02 14:48:09 +02006639#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6640
Laurent Viviere36800c2015-10-02 14:48:09 +02006641static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6642{
6643 int host_flags;
6644 target_sigset_t *target_mask;
6645 sigset_t host_mask;
6646 abi_long ret;
6647
6648 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6649 return -TARGET_EINVAL;
6650 }
6651 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6652 return -TARGET_EFAULT;
6653 }
6654
6655 target_to_host_sigset(&host_mask, target_mask);
6656
6657 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6658
6659 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6660 if (ret >= 0) {
6661 fd_trans_register(ret, &target_signalfd_trans);
6662 }
6663
6664 unlock_user_struct(target_mask, mask, 0);
6665
6666 return ret;
6667}
6668#endif
6669
pbrook1d9d8b52009-04-16 15:17:02 +00006670/* Map host to target signal numbers for the wait family of syscalls.
6671 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006672int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006673{
6674 if (WIFSIGNALED(status)) {
6675 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6676 }
6677 if (WIFSTOPPED(status)) {
6678 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6679 | (status & 0xff);
6680 }
6681 return status;
6682}
6683
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006684static int open_self_cmdline(void *cpu_env, int fd)
6685{
Richard Henderson29a0af62019-03-22 16:07:18 -07006686 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Schwab58de8b92017-03-20 12:31:55 +01006687 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
6688 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006689
Andreas Schwab58de8b92017-03-20 12:31:55 +01006690 for (i = 0; i < bprm->argc; i++) {
6691 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006692
Andreas Schwab58de8b92017-03-20 12:31:55 +01006693 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006694 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006695 }
6696 }
6697
Andreas Schwab58de8b92017-03-20 12:31:55 +01006698 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006699}
6700
Alexander Graf36c08d42011-11-02 20:23:24 +01006701static int open_self_maps(void *cpu_env, int fd)
6702{
Richard Henderson29a0af62019-03-22 16:07:18 -07006703 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02006704 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006705 FILE *fp;
6706 char *line = NULL;
6707 size_t len = 0;
6708 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006709
Alexander Graf1a49ef22012-05-01 16:30:28 +01006710 fp = fopen("/proc/self/maps", "r");
6711 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006712 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006713 }
6714
6715 while ((read = getline(&line, &len, fp)) != -1) {
6716 int fields, dev_maj, dev_min, inode;
6717 uint64_t min, max, offset;
6718 char flag_r, flag_w, flag_x, flag_p;
6719 char path[512] = "";
6720 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6721 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6722 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6723
6724 if ((fields < 10) || (fields > 11)) {
6725 continue;
6726 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006727 if (h2g_valid(min)) {
6728 int flags = page_get_flags(h2g(min));
Max Filippovebf9a362018-03-07 13:50:10 -08006729 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006730 if (page_check_range(h2g(min), max - min, flags) == -1) {
6731 continue;
6732 }
6733 if (h2g(min) == ts->info->stack_limit) {
6734 pstrcpy(path, sizeof(path), " [stack]");
6735 }
Laurent Vivier3e23de12018-08-14 19:12:17 +02006736 dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
Christophe Lyone24fed42013-04-02 14:03:38 +02006737 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006738 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006739 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006740 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006741 }
6742 }
6743
6744 free(line);
6745 fclose(fp);
6746
Alexander Graf36c08d42011-11-02 20:23:24 +01006747 return 0;
6748}
6749
Alexander Graf480b8e72011-11-02 20:23:25 +01006750static int open_self_stat(void *cpu_env, int fd)
6751{
Richard Henderson29a0af62019-03-22 16:07:18 -07006752 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02006753 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006754 abi_ulong start_stack = ts->info->start_stack;
6755 int i;
6756
6757 for (i = 0; i < 44; i++) {
6758 char buf[128];
6759 int len;
6760 uint64_t val = 0;
6761
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006762 if (i == 0) {
6763 /* pid */
6764 val = getpid();
6765 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6766 } else if (i == 1) {
6767 /* app name */
6768 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6769 } else if (i == 27) {
6770 /* stack bottom */
6771 val = start_stack;
6772 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6773 } else {
6774 /* for the rest, there is MasterCard */
6775 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006776 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006777
Alexander Graf480b8e72011-11-02 20:23:25 +01006778 len = strlen(buf);
6779 if (write(fd, buf, len) != len) {
6780 return -1;
6781 }
6782 }
6783
6784 return 0;
6785}
6786
Alexander Graf257450e2011-11-02 20:23:26 +01006787static int open_self_auxv(void *cpu_env, int fd)
6788{
Richard Henderson29a0af62019-03-22 16:07:18 -07006789 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02006790 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006791 abi_ulong auxv = ts->info->saved_auxv;
6792 abi_ulong len = ts->info->auxv_len;
6793 char *ptr;
6794
6795 /*
6796 * Auxiliary vector is stored in target process stack.
6797 * read in whole auxv vector and copy it to file
6798 */
6799 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6800 if (ptr != NULL) {
6801 while (len > 0) {
6802 ssize_t r;
6803 r = write(fd, ptr, len);
6804 if (r <= 0) {
6805 break;
6806 }
6807 len -= r;
6808 ptr += r;
6809 }
6810 lseek(fd, 0, SEEK_SET);
6811 unlock_user(ptr, auxv, len);
6812 }
6813
6814 return 0;
6815}
6816
Andreas Schwab463d8e72013-07-02 14:04:12 +01006817static int is_proc_myself(const char *filename, const char *entry)
6818{
6819 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6820 filename += strlen("/proc/");
6821 if (!strncmp(filename, "self/", strlen("self/"))) {
6822 filename += strlen("self/");
6823 } else if (*filename >= '1' && *filename <= '9') {
6824 char myself[80];
6825 snprintf(myself, sizeof(myself), "%d/", getpid());
6826 if (!strncmp(filename, myself, strlen(myself))) {
6827 filename += strlen(myself);
6828 } else {
6829 return 0;
6830 }
6831 } else {
6832 return 0;
6833 }
6834 if (!strcmp(filename, entry)) {
6835 return 1;
6836 }
6837 }
6838 return 0;
6839}
6840
Laurent Vivierfff69382019-05-17 15:31:48 +02006841#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \
Laurent Vivier4ab67132019-05-17 15:31:49 +02006842 defined(TARGET_SPARC) || defined(TARGET_M68K)
Laurent Vivierde6b9932013-08-30 01:46:40 +02006843static int is_proc(const char *filename, const char *entry)
6844{
6845 return strcmp(filename, entry) == 0;
6846}
Laurent Vivierfff69382019-05-17 15:31:48 +02006847#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02006848
Laurent Vivierfff69382019-05-17 15:31:48 +02006849#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
Laurent Vivierde6b9932013-08-30 01:46:40 +02006850static int open_net_route(void *cpu_env, int fd)
6851{
6852 FILE *fp;
6853 char *line = NULL;
6854 size_t len = 0;
6855 ssize_t read;
6856
6857 fp = fopen("/proc/net/route", "r");
6858 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006859 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006860 }
6861
6862 /* read header */
6863
6864 read = getline(&line, &len, fp);
6865 dprintf(fd, "%s", line);
6866
6867 /* read routes */
6868
6869 while ((read = getline(&line, &len, fp)) != -1) {
6870 char iface[16];
6871 uint32_t dest, gw, mask;
6872 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
Peter Maydell9d0bd0c2019-02-05 17:42:07 +00006873 int fields;
6874
6875 fields = sscanf(line,
6876 "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6877 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6878 &mask, &mtu, &window, &irtt);
6879 if (fields != 11) {
6880 continue;
6881 }
Laurent Vivierde6b9932013-08-30 01:46:40 +02006882 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6883 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6884 metric, tswap32(mask), mtu, window, irtt);
6885 }
6886
6887 free(line);
6888 fclose(fp);
6889
6890 return 0;
6891}
6892#endif
6893
Laurent Vivierfff69382019-05-17 15:31:48 +02006894#if defined(TARGET_SPARC)
6895static int open_cpuinfo(void *cpu_env, int fd)
6896{
6897 dprintf(fd, "type\t\t: sun4u\n");
6898 return 0;
6899}
6900#endif
6901
Laurent Vivier4ab67132019-05-17 15:31:49 +02006902#if defined(TARGET_M68K)
6903static int open_hardware(void *cpu_env, int fd)
6904{
6905 dprintf(fd, "Model:\t\tqemu-m68k\n");
6906 return 0;
6907}
6908#endif
6909
Riku Voipio0b2effd2014-08-06 10:36:37 +03006910static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006911{
6912 struct fake_open {
6913 const char *filename;
6914 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006915 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006916 };
6917 const struct fake_open *fake_open;
6918 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006919 { "maps", open_self_maps, is_proc_myself },
6920 { "stat", open_self_stat, is_proc_myself },
6921 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006922 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006923#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6924 { "/proc/net/route", open_net_route, is_proc },
6925#endif
Laurent Vivierfff69382019-05-17 15:31:48 +02006926#if defined(TARGET_SPARC)
6927 { "/proc/cpuinfo", open_cpuinfo, is_proc },
6928#endif
Laurent Vivier4ab67132019-05-17 15:31:49 +02006929#if defined(TARGET_M68K)
6930 { "/proc/hardware", open_hardware, is_proc },
6931#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02006932 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006933 };
6934
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006935 if (is_proc_myself(pathname, "exe")) {
6936 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006937 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006938 }
6939
Alexander Graf3be14d02011-11-02 20:23:23 +01006940 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006941 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006942 break;
6943 }
6944 }
6945
6946 if (fake_open->filename) {
6947 const char *tmpdir;
6948 char filename[PATH_MAX];
6949 int fd, r;
6950
6951 /* create temporary file to map stat to */
6952 tmpdir = getenv("TMPDIR");
6953 if (!tmpdir)
6954 tmpdir = "/tmp";
6955 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6956 fd = mkstemp(filename);
6957 if (fd < 0) {
6958 return fd;
6959 }
6960 unlink(filename);
6961
6962 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006963 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006964 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006965 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006966 return r;
6967 }
6968 lseek(fd, 0, SEEK_SET);
6969
6970 return fd;
6971 }
6972
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006973 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006974}
6975
Alexander Grafaecc8862014-11-10 21:33:03 +01006976#define TIMER_MAGIC 0x0caf0000
6977#define TIMER_MAGIC_MASK 0xffff0000
6978
6979/* Convert QEMU provided timer ID back to internal 16bit index format */
6980static target_timer_t get_timer_id(abi_long arg)
6981{
6982 target_timer_t timerid = arg;
6983
6984 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6985 return -TARGET_EINVAL;
6986 }
6987
6988 timerid &= 0xffff;
6989
6990 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6991 return -TARGET_EINVAL;
6992 }
6993
6994 return timerid;
6995}
6996
Samuel Thibault2e0a8712018-01-09 21:16:43 +01006997static int target_to_host_cpu_mask(unsigned long *host_mask,
6998 size_t host_size,
6999 abi_ulong target_addr,
7000 size_t target_size)
7001{
7002 unsigned target_bits = sizeof(abi_ulong) * 8;
7003 unsigned host_bits = sizeof(*host_mask) * 8;
7004 abi_ulong *target_mask;
7005 unsigned i, j;
7006
7007 assert(host_size >= target_size);
7008
7009 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7010 if (!target_mask) {
7011 return -TARGET_EFAULT;
7012 }
7013 memset(host_mask, 0, host_size);
7014
7015 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7016 unsigned bit = i * target_bits;
7017 abi_ulong val;
7018
7019 __get_user(val, &target_mask[i]);
7020 for (j = 0; j < target_bits; j++, bit++) {
7021 if (val & (1UL << j)) {
7022 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7023 }
7024 }
7025 }
7026
7027 unlock_user(target_mask, target_addr, 0);
7028 return 0;
7029}
7030
7031static int host_to_target_cpu_mask(const unsigned long *host_mask,
7032 size_t host_size,
7033 abi_ulong target_addr,
7034 size_t target_size)
7035{
7036 unsigned target_bits = sizeof(abi_ulong) * 8;
7037 unsigned host_bits = sizeof(*host_mask) * 8;
7038 abi_ulong *target_mask;
7039 unsigned i, j;
7040
7041 assert(host_size >= target_size);
7042
7043 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7044 if (!target_mask) {
7045 return -TARGET_EFAULT;
7046 }
7047
7048 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7049 unsigned bit = i * target_bits;
7050 abi_ulong val = 0;
7051
7052 for (j = 0; j < target_bits; j++, bit++) {
7053 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7054 val |= 1UL << j;
7055 }
7056 }
7057 __put_user(val, &target_mask[i]);
7058 }
7059
7060 unlock_user(target_mask, target_addr, target_size);
7061 return 0;
7062}
7063
Richard Hendersondc1ce182018-08-18 12:01:04 -07007064/* This is an internal helper for do_syscall so that it is easier
7065 * to have a single return point, so that actions, such as logging
7066 * of syscall results, can be performed.
7067 * All errnos that do_syscall() returns must be -TARGET_<errcode>.
7068 */
7069static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
7070 abi_long arg2, abi_long arg3, abi_long arg4,
7071 abi_long arg5, abi_long arg6, abi_long arg7,
7072 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007073{
Richard Henderson29a0af62019-03-22 16:07:18 -07007074 CPUState *cpu = env_cpu(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007075 abi_long ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007076#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
7077 || defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
7078 || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
bellard31e31b82003-02-18 22:55:36 +00007079 struct stat st;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007080#endif
7081#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
7082 || defined(TARGET_NR_fstatfs)
bellard56c8f682005-11-28 22:28:41 +00007083 struct statfs stfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007084#endif
pbrook53a59602006-03-25 19:31:22 +00007085 void *p;
ths3b46e622007-09-17 08:09:54 +00007086
bellard31e31b82003-02-18 22:55:36 +00007087 switch(num) {
7088 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007089 /* In old applications this may be used to implement _exit(2).
7090 However in threaded applictions it is used for thread termination,
7091 and _exit_group is used for application termination.
7092 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007093
7094 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007095 return -TARGET_ERESTARTSYS;
Timothy E Baldwina0995882016-05-27 15:51:56 +01007096 }
7097
Alex Bennéedd1f6342016-09-30 22:31:01 +01007098 cpu_list_lock();
7099
Andreas Färberbdc44642013-06-24 23:50:24 +02007100 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007101 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007102
Andreas Färber9b056fc2013-06-24 23:53:10 +02007103 /* Remove the CPU from the list. */
Emilio G. Cota068a5ea2018-08-19 05:13:35 -04007104 QTAILQ_REMOVE_RCU(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007105
Andreas Färber9b056fc2013-06-24 23:53:10 +02007106 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007107
Andreas Färber0429a972013-08-26 18:14:44 +02007108 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007109 if (ts->child_tidptr) {
7110 put_user_u32(0, ts->child_tidptr);
7111 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7112 NULL, NULL, 0);
7113 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007114 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007115 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007116 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007117 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007118 pthread_exit(NULL);
7119 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007120
7121 cpu_list_unlock();
Alex Bennée708b6a62018-06-22 17:09:10 +01007122 preexit_cleanup(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007123 _exit(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007124 return 0; /* avoid warning */
bellard31e31b82003-02-18 22:55:36 +00007125 case TARGET_NR_read:
Andreas Schwabba584f12019-03-05 17:45:05 +01007126 if (arg2 == 0 && arg3 == 0) {
7127 return get_errno(safe_read(arg1, 0, 0));
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007128 } else {
aurel3238d840e2009-01-30 19:48:17 +00007129 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007130 return -TARGET_EFAULT;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007131 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007132 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007133 fd_trans_host_to_target_data(arg1)) {
7134 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007135 }
aurel3238d840e2009-01-30 19:48:17 +00007136 unlock_user(p, arg2, ret);
7137 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007138 return ret;
bellard31e31b82003-02-18 22:55:36 +00007139 case TARGET_NR_write:
Tony Garnock-Jones58cfa6c2018-09-08 19:22:05 +01007140 if (arg2 == 0 && arg3 == 0) {
7141 return get_errno(safe_write(arg1, 0, 0));
7142 }
bellard579a97f2007-11-11 14:26:47 +00007143 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007144 return -TARGET_EFAULT;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01007145 if (fd_trans_target_to_host_data(arg1)) {
7146 void *copy = g_malloc(arg3);
7147 memcpy(copy, p, arg3);
7148 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
7149 if (ret >= 0) {
7150 ret = get_errno(safe_write(arg1, copy, ret));
7151 }
7152 g_free(copy);
7153 } else {
7154 ret = get_errno(safe_write(arg1, p, arg3));
7155 }
pbrook53a59602006-03-25 19:31:22 +00007156 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007157 return ret;
7158
Chen Gang704eff62015-08-21 05:37:33 +08007159#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007160 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007161 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007162 return -TARGET_EFAULT;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007163 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7164 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7165 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007166 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007167 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007168 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007169#endif
ths82424832007-09-24 09:21:55 +00007170 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007171 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007172 return -TARGET_EFAULT;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007173 ret = get_errno(do_openat(cpu_env, arg1, p,
7174 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7175 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007176 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007177 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007178 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007179#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7180 case TARGET_NR_name_to_handle_at:
7181 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007182 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007183#endif
7184#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7185 case TARGET_NR_open_by_handle_at:
7186 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007187 fd_trans_unregister(ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007188 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007189#endif
bellard31e31b82003-02-18 22:55:36 +00007190 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007191 fd_trans_unregister(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007192 return get_errno(close(arg1));
7193
bellard31e31b82003-02-18 22:55:36 +00007194 case TARGET_NR_brk:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007195 return do_brk(arg1);
Chen Gang704eff62015-08-21 05:37:33 +08007196#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007197 case TARGET_NR_fork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007198 return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
Chen Gang704eff62015-08-21 05:37:33 +08007199#endif
thse5febef2007-04-01 18:31:35 +00007200#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007201 case TARGET_NR_waitpid:
7202 {
pbrook53a59602006-03-25 19:31:22 +00007203 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007204 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007205 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007206 && put_user_s32(host_to_target_waitstatus(status), arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007207 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00007208 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007209 return ret;
thse5febef2007-04-01 18:31:35 +00007210#endif
pbrookf0cbb612008-05-30 18:20:05 +00007211#ifdef TARGET_NR_waitid
7212 case TARGET_NR_waitid:
7213 {
7214 siginfo_t info;
7215 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007216 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007217 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007218 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007219 return -TARGET_EFAULT;
pbrookf0cbb612008-05-30 18:20:05 +00007220 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007221 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007222 }
7223 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007224 return ret;
pbrookf0cbb612008-05-30 18:20:05 +00007225#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007226#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007227 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007228 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007229 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007230 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007231 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007232 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007233 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00007234#endif
Chen Gang704eff62015-08-21 05:37:33 +08007235#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007236 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007237 {
7238 void * p2;
7239 p = lock_user_string(arg1);
7240 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007241 if (!p || !p2)
7242 ret = -TARGET_EFAULT;
7243 else
7244 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007245 unlock_user(p2, arg2, 0);
7246 unlock_user(p, arg1, 0);
7247 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007248 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007249#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007250#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007251 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007252 {
7253 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007254 if (!arg2 || !arg4)
Richard Henderson2852aaf2018-08-18 12:01:06 -07007255 return -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007256 p = lock_user_string(arg2);
7257 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007258 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007259 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007260 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007261 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007262 unlock_user(p, arg2, 0);
7263 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007264 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007265 return ret;
ths64f0ce42007-09-24 09:25:06 +00007266#endif
Chen Gang704eff62015-08-21 05:37:33 +08007267#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007268 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007269 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007270 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007271 ret = get_errno(unlink(p));
7272 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007273 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007274#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007275#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007276 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007277 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007278 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007279 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007280 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007281 return ret;
balrogb7d35e62007-12-12 00:40:24 +00007282#endif
bellard31e31b82003-02-18 22:55:36 +00007283 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007284 {
7285 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007286 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007287 abi_ulong gp;
7288 abi_ulong guest_argp;
7289 abi_ulong guest_envp;
7290 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007291 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007292 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007293
bellardf7341ff2003-03-30 21:00:25 +00007294 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007295 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007296 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007297 if (get_user_ual(addr, gp))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007298 return -TARGET_EFAULT;
ths03aa1972007-12-02 06:28:08 +00007299 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007300 break;
bellard7854b052003-03-29 17:22:23 +00007301 argc++;
bellard2f619692007-11-16 10:46:05 +00007302 }
bellardf7341ff2003-03-30 21:00:25 +00007303 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007304 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007305 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007306 if (get_user_ual(addr, gp))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007307 return -TARGET_EFAULT;
ths03aa1972007-12-02 06:28:08 +00007308 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007309 break;
bellard7854b052003-03-29 17:22:23 +00007310 envc++;
bellard2f619692007-11-16 10:46:05 +00007311 }
bellard7854b052003-03-29 17:22:23 +00007312
Prasad J Panditb936cb52017-03-07 12:51:47 +05307313 argp = g_new0(char *, argc + 1);
7314 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00007315
pbrookda94d262008-05-30 18:24:00 +00007316 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007317 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007318 if (get_user_ual(addr, gp))
7319 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007320 if (!addr)
7321 break;
bellard2f619692007-11-16 10:46:05 +00007322 if (!(*q = lock_user_string(addr)))
7323 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007324 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007325 }
bellardf7341ff2003-03-30 21:00:25 +00007326 *q = NULL;
7327
pbrookda94d262008-05-30 18:24:00 +00007328 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007329 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007330 if (get_user_ual(addr, gp))
7331 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007332 if (!addr)
7333 break;
bellard2f619692007-11-16 10:46:05 +00007334 if (!(*q = lock_user_string(addr)))
7335 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007336 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007337 }
bellardf7341ff2003-03-30 21:00:25 +00007338 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007339
bellard2f619692007-11-16 10:46:05 +00007340 if (!(p = lock_user_string(arg1)))
7341 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007342 /* Although execve() is not an interruptible syscall it is
7343 * a special case where we must use the safe_syscall wrapper:
7344 * if we allow a signal to happen before we make the host
7345 * syscall then we will 'lose' it, because at the point of
7346 * execve the process leaves QEMU's control. So we use the
7347 * safe syscall wrapper to ensure that we either take the
7348 * signal as a guest signal, or else it does not happen
7349 * before the execve completes and makes it the other
7350 * program's problem.
7351 */
7352 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007353 unlock_user(p, arg1, 0);
7354
bellard2f619692007-11-16 10:46:05 +00007355 goto execve_end;
7356
7357 execve_efault:
7358 ret = -TARGET_EFAULT;
7359
7360 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007361 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007362 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007363 if (get_user_ual(addr, gp)
7364 || !addr)
7365 break;
pbrook53a59602006-03-25 19:31:22 +00007366 unlock_user(*q, addr, 0);
7367 }
7368 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007369 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007370 if (get_user_ual(addr, gp)
7371 || !addr)
7372 break;
pbrook53a59602006-03-25 19:31:22 +00007373 unlock_user(*q, addr, 0);
7374 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05307375
7376 g_free(argp);
7377 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00007378 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007379 return ret;
bellard31e31b82003-02-18 22:55:36 +00007380 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007381 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007382 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007383 ret = get_errno(chdir(p));
7384 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007385 return ret;
bellarda315a142005-01-30 22:59:18 +00007386#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007387 case TARGET_NR_time:
7388 {
pbrook53a59602006-03-25 19:31:22 +00007389 time_t host_time;
7390 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007391 if (!is_error(ret)
7392 && arg1
7393 && put_user_sal(host_time, arg1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007394 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00007395 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007396 return ret;
bellarda315a142005-01-30 22:59:18 +00007397#endif
Chen Gang704eff62015-08-21 05:37:33 +08007398#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007399 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007400 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007401 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007402 ret = get_errno(mknod(p, arg2, arg3));
7403 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007404 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007405#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007406#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007407 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007408 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007409 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007410 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007411 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007412 return ret;
ths75ac37a2007-09-24 09:23:05 +00007413#endif
Chen Gang704eff62015-08-21 05:37:33 +08007414#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007415 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007416 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007417 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007418 ret = get_errno(chmod(p, arg2));
7419 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007420 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007421#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007422#ifdef TARGET_NR_lseek
bellard31e31b82003-02-18 22:55:36 +00007423 case TARGET_NR_lseek:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007424 return get_errno(lseek(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007425#endif
Richard Henderson92317332010-05-03 10:07:53 -07007426#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7427 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007428 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007429 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007430 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07007431#endif
7432#ifdef TARGET_NR_getpid
7433 case TARGET_NR_getpid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007434 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07007435#endif
bellard31e31b82003-02-18 22:55:36 +00007436 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007437 {
7438 /* need to look at the data field */
7439 void *p2, *p3;
7440
7441 if (arg1) {
7442 p = lock_user_string(arg1);
7443 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07007444 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01007445 }
7446 } else {
7447 p = NULL;
7448 }
7449
7450 p2 = lock_user_string(arg2);
7451 if (!p2) {
7452 if (arg1) {
7453 unlock_user(p, arg1, 0);
7454 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07007455 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01007456 }
7457
7458 if (arg3) {
7459 p3 = lock_user_string(arg3);
7460 if (!p3) {
7461 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007462 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007463 }
7464 unlock_user(p2, arg2, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07007465 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01007466 }
7467 } else {
7468 p3 = NULL;
7469 }
7470
7471 /* FIXME - arg5 should be locked, but it isn't clear how to
7472 * do that since it's not guaranteed to be a NULL-terminated
7473 * string.
7474 */
7475 if (!arg5) {
7476 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7477 } else {
7478 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7479 }
7480 ret = get_errno(ret);
7481
7482 if (arg1) {
7483 unlock_user(p, arg1, 0);
7484 }
7485 unlock_user(p2, arg2, 0);
7486 if (arg3) {
7487 unlock_user(p3, arg3, 0);
7488 }
7489 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007490 return ret;
thse5febef2007-04-01 18:31:35 +00007491#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007492 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007493 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007494 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007495 ret = get_errno(umount(p));
7496 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007497 return ret;
thse5febef2007-04-01 18:31:35 +00007498#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007499#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007500 case TARGET_NR_stime:
7501 {
pbrook53a59602006-03-25 19:31:22 +00007502 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007503 if (get_user_sal(host_time, arg1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007504 return -TARGET_EFAULT;
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007505 return get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007506 }
j_mayer7a3148a2007-04-05 07:13:51 +00007507#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007508#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007509 case TARGET_NR_alarm:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007510 return alarm(arg1);
j_mayer7a3148a2007-04-05 07:13:51 +00007511#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007512#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007513 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007514 if (!block_signals()) {
7515 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7516 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007517 return -TARGET_EINTR;
j_mayer7a3148a2007-04-05 07:13:51 +00007518#endif
thse5febef2007-04-01 18:31:35 +00007519#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007520 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007521 {
pbrook53a59602006-03-25 19:31:22 +00007522 struct utimbuf tbuf, *host_tbuf;
7523 struct target_utimbuf *target_tbuf;
7524 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007525 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007526 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007527 tbuf.actime = tswapal(target_tbuf->actime);
7528 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007529 unlock_user_struct(target_tbuf, arg2, 0);
7530 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007531 } else {
pbrook53a59602006-03-25 19:31:22 +00007532 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007533 }
bellard579a97f2007-11-11 14:26:47 +00007534 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007535 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007536 ret = get_errno(utime(p, host_tbuf));
7537 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007538 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007539 return ret;
thse5febef2007-04-01 18:31:35 +00007540#endif
Chen Gang704eff62015-08-21 05:37:33 +08007541#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007542 case TARGET_NR_utimes:
7543 {
bellard978a66f2004-12-06 22:58:05 +00007544 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007545 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007546 if (copy_from_user_timeval(&tv[0], arg2)
7547 || copy_from_user_timeval(&tv[1],
7548 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007549 return -TARGET_EFAULT;
bellard978a66f2004-12-06 22:58:05 +00007550 tvp = tv;
7551 } else {
7552 tvp = NULL;
7553 }
bellard579a97f2007-11-11 14:26:47 +00007554 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007555 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007556 ret = get_errno(utimes(p, tvp));
7557 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007558 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007559 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007560#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007561#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007562 case TARGET_NR_futimesat:
7563 {
7564 struct timeval *tvp, tv[2];
7565 if (arg3) {
7566 if (copy_from_user_timeval(&tv[0], arg3)
7567 || copy_from_user_timeval(&tv[1],
7568 arg3 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007569 return -TARGET_EFAULT;
balrogac8a6552008-09-20 02:25:39 +00007570 tvp = tv;
7571 } else {
7572 tvp = NULL;
7573 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07007574 if (!(p = lock_user_string(arg2))) {
7575 return -TARGET_EFAULT;
7576 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01007577 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007578 unlock_user(p, arg2, 0);
7579 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007580 return ret;
balrogac8a6552008-09-20 02:25:39 +00007581#endif
Chen Gang704eff62015-08-21 05:37:33 +08007582#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007583 case TARGET_NR_access:
Richard Henderson2852aaf2018-08-18 12:01:06 -07007584 if (!(p = lock_user_string(arg1))) {
7585 return -TARGET_EFAULT;
7586 }
Ulrich Hecht719f9082009-07-03 17:09:29 +02007587 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007588 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007589 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007590#endif
ths92a34c12007-09-24 09:27:49 +00007591#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7592 case TARGET_NR_faccessat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07007593 if (!(p = lock_user_string(arg2))) {
7594 return -TARGET_EFAULT;
7595 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01007596 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007597 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007598 return ret;
ths92a34c12007-09-24 09:27:49 +00007599#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007600#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007601 case TARGET_NR_nice:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007602 return get_errno(nice(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00007603#endif
bellard31e31b82003-02-18 22:55:36 +00007604 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007605 sync();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007606 return 0;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02007607#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
7608 case TARGET_NR_syncfs:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007609 return get_errno(syncfs(arg1));
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02007610#endif
bellard31e31b82003-02-18 22:55:36 +00007611 case TARGET_NR_kill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007612 return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
Chen Gang704eff62015-08-21 05:37:33 +08007613#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007614 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007615 {
7616 void *p2;
7617 p = lock_user_string(arg1);
7618 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007619 if (!p || !p2)
7620 ret = -TARGET_EFAULT;
7621 else
7622 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007623 unlock_user(p2, arg2, 0);
7624 unlock_user(p, arg1, 0);
7625 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007626 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007627#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007628#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007629 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007630 {
bellard579a97f2007-11-11 14:26:47 +00007631 void *p2;
ths722183f2007-09-24 09:24:37 +00007632 p = lock_user_string(arg2);
7633 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007634 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007635 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007636 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007637 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007638 unlock_user(p2, arg4, 0);
7639 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007640 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007641 return ret;
ths722183f2007-09-24 09:24:37 +00007642#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01007643#if defined(TARGET_NR_renameat2)
7644 case TARGET_NR_renameat2:
7645 {
7646 void *p2;
7647 p = lock_user_string(arg2);
7648 p2 = lock_user_string(arg4);
7649 if (!p || !p2) {
7650 ret = -TARGET_EFAULT;
7651 } else {
7652 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
7653 }
7654 unlock_user(p2, arg4, 0);
7655 unlock_user(p, arg2, 0);
7656 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007657 return ret;
Andreas Schwab95d03072018-01-23 11:53:31 +01007658#endif
Chen Gang704eff62015-08-21 05:37:33 +08007659#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007660 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007661 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007662 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007663 ret = get_errno(mkdir(p, arg2));
7664 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007665 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007666#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007667#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007668 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007669 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007670 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007671 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007672 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007673 return ret;
ths4472ad02007-09-24 09:22:32 +00007674#endif
Chen Gang704eff62015-08-21 05:37:33 +08007675#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007676 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007677 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007678 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007679 ret = get_errno(rmdir(p));
7680 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007681 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007682#endif
bellard31e31b82003-02-18 22:55:36 +00007683 case TARGET_NR_dup:
7684 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007685 if (ret >= 0) {
7686 fd_trans_dup(arg1, ret);
7687 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007688 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007689#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007690 case TARGET_NR_pipe:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007691 return do_pipe(cpu_env, arg1, 0, 0);
Chen Gang704eff62015-08-21 05:37:33 +08007692#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007693#ifdef TARGET_NR_pipe2
7694 case TARGET_NR_pipe2:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007695 return do_pipe(cpu_env, arg1,
7696 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007697#endif
bellard31e31b82003-02-18 22:55:36 +00007698 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007699 {
pbrook53a59602006-03-25 19:31:22 +00007700 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007701 struct tms tms;
7702 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007703 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007704 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7705 if (!tmsp)
Richard Henderson2852aaf2018-08-18 12:01:06 -07007706 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007707 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7708 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7709 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7710 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007711 }
bellardc596ed12003-07-13 17:32:31 +00007712 if (!is_error(ret))
7713 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007714 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007715 return ret;
bellard31e31b82003-02-18 22:55:36 +00007716 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007717 if (arg1 == 0) {
7718 ret = get_errno(acct(NULL));
7719 } else {
Richard Henderson2852aaf2018-08-18 12:01:06 -07007720 if (!(p = lock_user_string(arg1))) {
7721 return -TARGET_EFAULT;
7722 }
aurel3238d840e2009-01-30 19:48:17 +00007723 ret = get_errno(acct(path(p)));
7724 unlock_user(p, arg1, 0);
7725 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007726 return ret;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007727#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007728 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007729 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007730 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007731 ret = get_errno(umount2(p, arg2));
7732 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007733 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00007734#endif
bellard31e31b82003-02-18 22:55:36 +00007735 case TARGET_NR_ioctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007736 return do_ioctl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13007737#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00007738 case TARGET_NR_fcntl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007739 return do_fcntl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13007740#endif
bellard31e31b82003-02-18 22:55:36 +00007741 case TARGET_NR_setpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007742 return get_errno(setpgid(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007743 case TARGET_NR_umask:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007744 return get_errno(umask(arg1));
bellard31e31b82003-02-18 22:55:36 +00007745 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007746 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007747 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007748 ret = get_errno(chroot(p));
7749 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007750 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007751#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007752 case TARGET_NR_dup2:
7753 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007754 if (ret >= 0) {
7755 fd_trans_dup(arg1, arg2);
7756 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007757 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08007758#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007759#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7760 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00007761 {
7762 int host_flags;
7763
7764 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
7765 return -EINVAL;
7766 }
7767 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
7768 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02007769 if (ret >= 0) {
7770 fd_trans_dup(arg1, arg2);
7771 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007772 return ret;
Peter Maydell10fa9932017-12-15 15:18:00 +00007773 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007774#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007775#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007776 case TARGET_NR_getppid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007777 return get_errno(getppid());
j_mayer7a3148a2007-04-05 07:13:51 +00007778#endif
Chen Gang704eff62015-08-21 05:37:33 +08007779#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007780 case TARGET_NR_getpgrp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007781 return get_errno(getpgrp());
Chen Gang704eff62015-08-21 05:37:33 +08007782#endif
bellard31e31b82003-02-18 22:55:36 +00007783 case TARGET_NR_setsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007784 return get_errno(setsid());
thse5febef2007-04-01 18:31:35 +00007785#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007786 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007787 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007788#if defined(TARGET_ALPHA)
7789 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007790 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007791 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007792 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007793 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00007794 act._sa_handler = old_act->_sa_handler;
7795 target_siginitset(&act.sa_mask, old_act->sa_mask);
7796 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007797 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007798 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007799 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007800 }
7801 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007802 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007803 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007804 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00007805 old_act->_sa_handler = oact._sa_handler;
7806 old_act->sa_mask = oact.sa_mask.sig[0];
7807 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007808 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007809 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007810#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007811 struct target_sigaction act, oact, *pact, *old_act;
7812
7813 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007814 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007815 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00007816 act._sa_handler = old_act->_sa_handler;
7817 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7818 act.sa_flags = old_act->sa_flags;
7819 unlock_user_struct(old_act, arg2, 0);
7820 pact = &act;
7821 } else {
7822 pact = NULL;
7823 }
7824
7825 ret = get_errno(do_sigaction(arg1, pact, &oact));
7826
7827 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007828 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007829 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00007830 old_act->_sa_handler = oact._sa_handler;
7831 old_act->sa_flags = oact.sa_flags;
7832 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7833 old_act->sa_mask.sig[1] = 0;
7834 old_act->sa_mask.sig[2] = 0;
7835 old_act->sa_mask.sig[3] = 0;
7836 unlock_user_struct(old_act, arg3, 1);
7837 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007838#else
7839 struct target_old_sigaction *old_act;
7840 struct target_sigaction act, oact, *pact;
7841 if (arg2) {
7842 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007843 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007844 act._sa_handler = old_act->_sa_handler;
7845 target_siginitset(&act.sa_mask, old_act->sa_mask);
7846 act.sa_flags = old_act->sa_flags;
7847 act.sa_restorer = old_act->sa_restorer;
Laurent Vivier5de154e2018-04-02 12:24:52 +02007848#ifdef TARGET_ARCH_HAS_KA_RESTORER
7849 act.ka_restorer = 0;
7850#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08007851 unlock_user_struct(old_act, arg2, 0);
7852 pact = &act;
7853 } else {
7854 pact = NULL;
7855 }
7856 ret = get_errno(do_sigaction(arg1, pact, &oact));
7857 if (!is_error(ret) && arg3) {
7858 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007859 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007860 old_act->_sa_handler = oact._sa_handler;
7861 old_act->sa_mask = oact.sa_mask.sig[0];
7862 old_act->sa_flags = oact.sa_flags;
7863 old_act->sa_restorer = oact.sa_restorer;
7864 unlock_user_struct(old_act, arg3, 1);
7865 }
ths388bb212007-05-13 13:58:00 +00007866#endif
bellard31e31b82003-02-18 22:55:36 +00007867 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007868 return ret;
thse5febef2007-04-01 18:31:35 +00007869#endif
bellard66fb9762003-03-23 01:06:05 +00007870 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007871 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007872#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00007873 /* For Alpha and SPARC this is a 5 argument syscall, with
7874 * a 'restorer' parameter which must be copied into the
7875 * sa_restorer field of the sigaction struct.
7876 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
7877 * and arg5 is the sigsetsize.
7878 * Alpha also has a separate rt_sigaction struct that it uses
7879 * here; SPARC uses the usual sigaction struct.
7880 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08007881 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00007882 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01007883
7884 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007885 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01007886 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007887 if (arg2) {
7888 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007889 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007890 act._sa_handler = rt_act->_sa_handler;
7891 act.sa_mask = rt_act->sa_mask;
7892 act.sa_flags = rt_act->sa_flags;
7893 act.sa_restorer = arg5;
7894 unlock_user_struct(rt_act, arg2, 0);
7895 pact = &act;
7896 }
7897 ret = get_errno(do_sigaction(arg1, pact, &oact));
7898 if (!is_error(ret) && arg3) {
7899 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07007900 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007901 rt_act->_sa_handler = oact._sa_handler;
7902 rt_act->sa_mask = oact.sa_mask;
7903 rt_act->sa_flags = oact.sa_flags;
7904 unlock_user_struct(rt_act, arg3, 1);
7905 }
7906#else
Peter Maydell78bfef72017-11-06 18:33:26 +00007907#ifdef TARGET_SPARC
7908 target_ulong restorer = arg4;
7909 target_ulong sigsetsize = arg5;
7910#else
7911 target_ulong sigsetsize = arg4;
7912#endif
pbrook53a59602006-03-25 19:31:22 +00007913 struct target_sigaction *act;
7914 struct target_sigaction *oact;
7915
Peter Maydell78bfef72017-11-06 18:33:26 +00007916 if (sigsetsize != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007917 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01007918 }
bellard579a97f2007-11-11 14:26:47 +00007919 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00007920 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07007921 return -TARGET_EFAULT;
Peter Maydell78bfef72017-11-06 18:33:26 +00007922 }
Laurent Vivier5de154e2018-04-02 12:24:52 +02007923#ifdef TARGET_ARCH_HAS_KA_RESTORER
7924 act->ka_restorer = restorer;
Peter Maydell78bfef72017-11-06 18:33:26 +00007925#endif
7926 } else {
pbrook53a59602006-03-25 19:31:22 +00007927 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00007928 }
bellard579a97f2007-11-11 14:26:47 +00007929 if (arg3) {
7930 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7931 ret = -TARGET_EFAULT;
7932 goto rt_sigaction_fail;
7933 }
7934 } else
pbrook53a59602006-03-25 19:31:22 +00007935 oact = NULL;
7936 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007937 rt_sigaction_fail:
7938 if (act)
pbrook53a59602006-03-25 19:31:22 +00007939 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007940 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007941 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007942#endif
pbrook53a59602006-03-25 19:31:22 +00007943 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007944 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00007945#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007946 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007947 {
7948 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007949 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007950 ret = do_sigprocmask(0, NULL, &cur_set);
7951 if (!ret) {
7952 host_to_target_old_sigset(&target_set, &cur_set);
7953 ret = target_set;
7954 }
bellard66fb9762003-03-23 01:06:05 +00007955 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007956 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00007957#endif
7958#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007959 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007960 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02007961 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00007962 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00007963 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007964 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7965 if (!ret) {
7966 host_to_target_old_sigset(&target_set, &oset);
7967 ret = target_set;
7968 }
bellard66fb9762003-03-23 01:06:05 +00007969 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07007970 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00007971#endif
thse5febef2007-04-01 18:31:35 +00007972#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007973 case TARGET_NR_sigprocmask:
7974 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007975#if defined(TARGET_ALPHA)
7976 sigset_t set, oldset;
7977 abi_ulong mask;
7978 int how;
7979
7980 switch (arg1) {
7981 case TARGET_SIG_BLOCK:
7982 how = SIG_BLOCK;
7983 break;
7984 case TARGET_SIG_UNBLOCK:
7985 how = SIG_UNBLOCK;
7986 break;
7987 case TARGET_SIG_SETMASK:
7988 how = SIG_SETMASK;
7989 break;
7990 default:
Richard Henderson259841c2018-08-18 12:01:09 -07007991 return -TARGET_EINVAL;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007992 }
7993 mask = arg2;
7994 target_to_host_old_sigset(&set, &mask);
7995
Peter Maydell3d3efba2016-05-27 15:51:49 +01007996 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007997 if (!is_error(ret)) {
7998 host_to_target_old_sigset(&mask, &oldset);
7999 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008000 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008001 }
8002#else
bellard66fb9762003-03-23 01:06:05 +00008003 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008004 int how;
ths3b46e622007-09-17 08:09:54 +00008005
pbrook53a59602006-03-25 19:31:22 +00008006 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008007 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008008 case TARGET_SIG_BLOCK:
8009 how = SIG_BLOCK;
8010 break;
8011 case TARGET_SIG_UNBLOCK:
8012 how = SIG_UNBLOCK;
8013 break;
8014 case TARGET_SIG_SETMASK:
8015 how = SIG_SETMASK;
8016 break;
8017 default:
Richard Henderson259841c2018-08-18 12:01:09 -07008018 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008019 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008020 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008021 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008022 target_to_host_old_sigset(&set, p);
8023 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008024 set_ptr = &set;
8025 } else {
8026 how = 0;
8027 set_ptr = NULL;
8028 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008029 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008030 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008031 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008032 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008033 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008034 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008035 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008036#endif
bellard66fb9762003-03-23 01:06:05 +00008037 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008038 return ret;
thse5febef2007-04-01 18:31:35 +00008039#endif
bellard66fb9762003-03-23 01:06:05 +00008040 case TARGET_NR_rt_sigprocmask:
8041 {
8042 int how = arg1;
8043 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008044
Peter Maydellc8157012016-06-30 14:23:24 +01008045 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008046 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01008047 }
8048
pbrook53a59602006-03-25 19:31:22 +00008049 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008050 switch(how) {
8051 case TARGET_SIG_BLOCK:
8052 how = SIG_BLOCK;
8053 break;
8054 case TARGET_SIG_UNBLOCK:
8055 how = SIG_UNBLOCK;
8056 break;
8057 case TARGET_SIG_SETMASK:
8058 how = SIG_SETMASK;
8059 break;
8060 default:
Richard Henderson259841c2018-08-18 12:01:09 -07008061 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008062 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008063 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008064 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008065 target_to_host_sigset(&set, p);
8066 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008067 set_ptr = &set;
8068 } else {
8069 how = 0;
8070 set_ptr = NULL;
8071 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008072 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008073 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008074 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008075 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008076 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008077 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008078 }
8079 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008080 return ret;
thse5febef2007-04-01 18:31:35 +00008081#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008082 case TARGET_NR_sigpending:
8083 {
8084 sigset_t set;
8085 ret = get_errno(sigpending(&set));
8086 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008087 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008088 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008089 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008090 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008091 }
8092 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008093 return ret;
thse5febef2007-04-01 18:31:35 +00008094#endif
bellard66fb9762003-03-23 01:06:05 +00008095 case TARGET_NR_rt_sigpending:
8096 {
8097 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008098
8099 /* Yes, this check is >, not != like most. We follow the kernel's
8100 * logic and it does it like this because it implements
8101 * NR_sigpending through the same code path, and in that case
8102 * the old_sigset_t is smaller in size.
8103 */
8104 if (arg2 > sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008105 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01008106 }
8107
bellard66fb9762003-03-23 01:06:05 +00008108 ret = get_errno(sigpending(&set));
8109 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008110 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008111 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008112 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008113 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008114 }
8115 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008116 return ret;
thse5febef2007-04-01 18:31:35 +00008117#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008118 case TARGET_NR_sigsuspend:
8119 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008120 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008121#if defined(TARGET_ALPHA)
8122 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008123 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008124#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008125 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008126 return -TARGET_EFAULT;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008127 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008128 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008129#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008130 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8131 SIGSET_T_SIZE));
8132 if (ret != -TARGET_ERESTARTSYS) {
8133 ts->in_sigsuspend = 1;
8134 }
bellard66fb9762003-03-23 01:06:05 +00008135 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008136 return ret;
thse5febef2007-04-01 18:31:35 +00008137#endif
bellard66fb9762003-03-23 01:06:05 +00008138 case TARGET_NR_rt_sigsuspend:
8139 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008140 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008141
8142 if (arg2 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008143 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01008144 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008145 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008146 return -TARGET_EFAULT;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008147 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008148 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008149 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8150 SIGSET_T_SIZE));
8151 if (ret != -TARGET_ERESTARTSYS) {
8152 ts->in_sigsuspend = 1;
8153 }
bellard66fb9762003-03-23 01:06:05 +00008154 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008155 return ret;
bellard66fb9762003-03-23 01:06:05 +00008156 case TARGET_NR_rt_sigtimedwait:
8157 {
bellard66fb9762003-03-23 01:06:05 +00008158 sigset_t set;
8159 struct timespec uts, *puts;
8160 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008161
Peter Maydellc8157012016-06-30 14:23:24 +01008162 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008163 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01008164 }
8165
Anthony Liguoric227f092009-10-01 16:12:16 -05008166 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008167 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008168 target_to_host_sigset(&set, p);
8169 unlock_user(p, arg1, 0);
8170 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008171 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008172 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008173 } else {
8174 puts = NULL;
8175 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008176 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8177 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008178 if (!is_error(ret)) {
8179 if (arg2) {
8180 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8181 0);
8182 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008183 return -TARGET_EFAULT;
Petar Jovanovic974a1962014-03-03 15:07:41 +01008184 }
8185 host_to_target_siginfo(p, &uinfo);
8186 unlock_user(p, arg2, sizeof(target_siginfo_t));
8187 }
8188 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008189 }
8190 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008191 return ret;
bellard66fb9762003-03-23 01:06:05 +00008192 case TARGET_NR_rt_sigqueueinfo:
8193 {
8194 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01008195
8196 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
8197 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008198 return -TARGET_EFAULT;
Peter Maydell4debae62016-06-20 15:50:36 +01008199 }
pbrook53a59602006-03-25 19:31:22 +00008200 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02008201 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00008202 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
8203 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008204 return ret;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02008205 case TARGET_NR_rt_tgsigqueueinfo:
8206 {
8207 siginfo_t uinfo;
8208
8209 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
8210 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008211 return -TARGET_EFAULT;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02008212 }
8213 target_to_host_siginfo(&uinfo, p);
8214 unlock_user(p, arg4, 0);
8215 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
8216 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008217 return ret;
thse5febef2007-04-01 18:31:35 +00008218#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00008219 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008220 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008221 return -TARGET_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008222 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008223 return do_sigreturn(cpu_env);
thse5febef2007-04-01 18:31:35 +00008224#endif
bellard66fb9762003-03-23 01:06:05 +00008225 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008226 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008227 return -TARGET_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008228 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008229 return do_rt_sigreturn(cpu_env);
bellard31e31b82003-02-18 22:55:36 +00008230 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00008231 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008232 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008233 ret = get_errno(sethostname(p, arg2));
8234 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008235 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008236#ifdef TARGET_NR_setrlimit
bellard31e31b82003-02-18 22:55:36 +00008237 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00008238 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008239 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008240 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008241 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00008242 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008243 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008244 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
8245 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008246 unlock_user_struct(target_rlim, arg2, 0);
Max Filippov5dfa88f2018-09-17 11:13:14 -07008247 /*
8248 * If we just passed through resource limit settings for memory then
8249 * they would also apply to QEMU's own allocations, and QEMU will
8250 * crash or hang or die if its allocations fail. Ideally we would
8251 * track the guest allocations in QEMU and apply the limits ourselves.
8252 * For now, just tell the guest the call succeeded but don't actually
8253 * limit anything.
8254 */
8255 if (resource != RLIMIT_AS &&
8256 resource != RLIMIT_DATA &&
8257 resource != RLIMIT_STACK) {
8258 return get_errno(setrlimit(resource, &rlim));
8259 } else {
8260 return 0;
8261 }
bellard9de5e442003-03-23 16:49:39 +00008262 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008263#endif
8264#ifdef TARGET_NR_getrlimit
bellard31e31b82003-02-18 22:55:36 +00008265 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00008266 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008267 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008268 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008269 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008270
bellard9de5e442003-03-23 16:49:39 +00008271 ret = get_errno(getrlimit(resource, &rlim));
8272 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008273 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008274 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008275 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8276 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008277 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008278 }
8279 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008280 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008281#endif
bellard31e31b82003-02-18 22:55:36 +00008282 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008283 {
8284 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008285 ret = get_errno(getrusage(arg1, &rusage));
8286 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008287 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008288 }
8289 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008290 return ret;
bellard31e31b82003-02-18 22:55:36 +00008291 case TARGET_NR_gettimeofday:
8292 {
bellard31e31b82003-02-18 22:55:36 +00008293 struct timeval tv;
8294 ret = get_errno(gettimeofday(&tv, NULL));
8295 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008296 if (copy_to_user_timeval(arg1, &tv))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008297 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00008298 }
8299 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008300 return ret;
bellard31e31b82003-02-18 22:55:36 +00008301 case TARGET_NR_settimeofday:
8302 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008303 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008304 struct timezone tz, *ptz = NULL;
8305
Paul Burtonb67d8032014-06-22 11:25:41 +01008306 if (arg1) {
8307 if (copy_from_user_timeval(&tv, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008308 return -TARGET_EFAULT;
Paul Burtonb67d8032014-06-22 11:25:41 +01008309 }
8310 ptv = &tv;
8311 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008312
8313 if (arg2) {
8314 if (copy_from_user_timezone(&tz, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008315 return -TARGET_EFAULT;
Paul Burtonef4467e2014-06-22 11:25:40 +01008316 }
8317 ptz = &tz;
8318 }
8319
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008320 return get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008321 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008322#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008323 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02008324#if defined(TARGET_WANT_NI_OLD_SELECT)
8325 /* some architectures used to have old_select here
8326 * but now ENOSYS it.
8327 */
8328 ret = -TARGET_ENOSYS;
8329#elif defined(TARGET_WANT_OLD_SYS_SELECT)
8330 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008331#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02008332 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008333#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008334 return ret;
bellard048f6b42005-11-26 18:47:20 +00008335#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008336#ifdef TARGET_NR_pselect6
8337 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008338 {
8339 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8340 fd_set rfds, wfds, efds;
8341 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8342 struct timespec ts, *ts_ptr;
8343
8344 /*
8345 * The 6th arg is actually two args smashed together,
8346 * so we cannot use the C library.
8347 */
8348 sigset_t set;
8349 struct {
8350 sigset_t *set;
8351 size_t size;
8352 } sig, *sig_ptr;
8353
8354 abi_ulong arg_sigset, arg_sigsize, *arg7;
8355 target_sigset_t *target_sigset;
8356
8357 n = arg1;
8358 rfd_addr = arg2;
8359 wfd_addr = arg3;
8360 efd_addr = arg4;
8361 ts_addr = arg5;
8362
8363 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8364 if (ret) {
Richard Henderson259841c2018-08-18 12:01:09 -07008365 return ret;
Mike Frysinger055e0902011-06-03 17:01:49 -04008366 }
8367 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8368 if (ret) {
Richard Henderson259841c2018-08-18 12:01:09 -07008369 return ret;
Mike Frysinger055e0902011-06-03 17:01:49 -04008370 }
8371 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8372 if (ret) {
Richard Henderson259841c2018-08-18 12:01:09 -07008373 return ret;
Mike Frysinger055e0902011-06-03 17:01:49 -04008374 }
8375
8376 /*
8377 * This takes a timespec, and not a timeval, so we cannot
8378 * use the do_select() helper ...
8379 */
8380 if (ts_addr) {
8381 if (target_to_host_timespec(&ts, ts_addr)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008382 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008383 }
8384 ts_ptr = &ts;
8385 } else {
8386 ts_ptr = NULL;
8387 }
8388
8389 /* Extract the two packed args for the sigset */
8390 if (arg6) {
8391 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008392 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008393
8394 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8395 if (!arg7) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008396 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008397 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008398 arg_sigset = tswapal(arg7[0]);
8399 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008400 unlock_user(arg7, arg6, 0);
8401
8402 if (arg_sigset) {
8403 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008404 if (arg_sigsize != sizeof(*target_sigset)) {
8405 /* Like the kernel, we enforce correct size sigsets */
Richard Henderson259841c2018-08-18 12:01:09 -07008406 return -TARGET_EINVAL;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008407 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008408 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8409 sizeof(*target_sigset), 1);
8410 if (!target_sigset) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008411 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008412 }
8413 target_to_host_sigset(&set, target_sigset);
8414 unlock_user(target_sigset, arg_sigset, 0);
8415 } else {
8416 sig.set = NULL;
8417 }
8418 } else {
8419 sig_ptr = NULL;
8420 }
8421
Peter Maydell6df9d382016-05-12 18:47:51 +01008422 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8423 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008424
8425 if (!is_error(ret)) {
8426 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008427 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008428 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008429 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008430 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008431 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008432
8433 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008434 return -TARGET_EFAULT;
Mike Frysinger055e0902011-06-03 17:01:49 -04008435 }
8436 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008437 return ret;
Riku Voipio9e423822010-05-07 12:28:05 +00008438#endif
Chen Gang704eff62015-08-21 05:37:33 +08008439#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008440 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008441 {
8442 void *p2;
8443 p = lock_user_string(arg1);
8444 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008445 if (!p || !p2)
8446 ret = -TARGET_EFAULT;
8447 else
8448 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008449 unlock_user(p2, arg2, 0);
8450 unlock_user(p, arg1, 0);
8451 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008452 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008453#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008454#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008455 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008456 {
bellard579a97f2007-11-11 14:26:47 +00008457 void *p2;
thsf0b62432007-09-24 09:25:40 +00008458 p = lock_user_string(arg1);
8459 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008460 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008461 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008462 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008463 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008464 unlock_user(p2, arg3, 0);
8465 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008466 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008467 return ret;
thsf0b62432007-09-24 09:25:40 +00008468#endif
Chen Gang704eff62015-08-21 05:37:33 +08008469#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008470 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008471 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008472 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008473 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008474 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008475 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008476 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008477 } else if (!arg3) {
8478 /* Short circuit this for the magic exe check. */
8479 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008480 } else if (is_proc_myself((const char *)p, "exe")) {
8481 char real[PATH_MAX], *temp;
8482 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008483 /* Return value is # of bytes that we wrote to the buffer. */
8484 if (temp == NULL) {
8485 ret = get_errno(-1);
8486 } else {
8487 /* Don't worry about sign mismatch as earlier mapping
8488 * logic would have thrown a bad address error. */
8489 ret = MIN(strlen(real), arg3);
8490 /* We cannot NUL terminate the string. */
8491 memcpy(p2, real, ret);
8492 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008493 } else {
8494 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008495 }
pbrook53a59602006-03-25 19:31:22 +00008496 unlock_user(p2, arg2, ret);
8497 unlock_user(p, arg1, 0);
8498 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008499 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008500#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008501#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008502 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008503 {
bellard579a97f2007-11-11 14:26:47 +00008504 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008505 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008506 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008507 if (!p || !p2) {
8508 ret = -TARGET_EFAULT;
8509 } else if (is_proc_myself((const char *)p, "exe")) {
8510 char real[PATH_MAX], *temp;
8511 temp = realpath(exec_path, real);
8512 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8513 snprintf((char *)p2, arg4, "%s", real);
8514 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008515 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008516 }
bellard579a97f2007-11-11 14:26:47 +00008517 unlock_user(p2, arg3, ret);
8518 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008519 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008520 return ret;
ths5e0ccb12007-09-24 09:26:10 +00008521#endif
thse5febef2007-04-01 18:31:35 +00008522#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008523 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008524 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008525 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008526 ret = get_errno(swapon(p, arg2));
8527 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008528 return ret;
thse5febef2007-04-01 18:31:35 +00008529#endif
bellard31e31b82003-02-18 22:55:36 +00008530 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008531 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8532 /* arg4 must be ignored in all other cases */
8533 p = lock_user_string(arg4);
8534 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008535 return -TARGET_EFAULT;
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008536 }
8537 ret = get_errno(reboot(arg1, arg2, arg3, p));
8538 unlock_user(p, arg4, 0);
8539 } else {
8540 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8541 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008542 return ret;
thse5febef2007-04-01 18:31:35 +00008543#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008544 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008545#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8546 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008547 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8548 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008549 {
blueswir1992f48a2007-10-14 16:27:31 +00008550 abi_ulong *v;
8551 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008552 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008553 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008554 v1 = tswapal(v[0]);
8555 v2 = tswapal(v[1]);
8556 v3 = tswapal(v[2]);
8557 v4 = tswapal(v[3]);
8558 v5 = tswapal(v[4]);
8559 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008560 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008561 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008562 target_to_host_bitmask(v4, mmap_flags_tbl),
8563 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008564 }
bellard31e31b82003-02-18 22:55:36 +00008565#else
ths5fafdf22007-09-16 21:08:06 +00008566 ret = get_errno(target_mmap(arg1, arg2, arg3,
8567 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008568 arg5,
8569 arg6));
bellard31e31b82003-02-18 22:55:36 +00008570#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008571 return ret;
thse5febef2007-04-01 18:31:35 +00008572#endif
bellarda315a142005-01-30 22:59:18 +00008573#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008574 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008575#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008576#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008577#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008578 ret = target_mmap(arg1, arg2, arg3,
8579 target_to_host_bitmask(arg4, mmap_flags_tbl),
8580 arg5, arg6 << MMAP_SHIFT);
8581 return get_errno(ret);
bellarda315a142005-01-30 22:59:18 +00008582#endif
bellard31e31b82003-02-18 22:55:36 +00008583 case TARGET_NR_munmap:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008584 return get_errno(target_munmap(arg1, arg2));
bellard9de5e442003-03-23 16:49:39 +00008585 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008586 {
Andreas Färber0429a972013-08-26 18:14:44 +02008587 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008588 /* Special hack to detect libc making the stack executable. */
8589 if ((arg3 & PROT_GROWSDOWN)
8590 && arg1 >= ts->info->stack_limit
8591 && arg1 <= ts->info->start_stack) {
8592 arg3 &= ~PROT_GROWSDOWN;
8593 arg2 = arg2 + arg1 - ts->info->stack_limit;
8594 arg1 = ts->info->stack_limit;
8595 }
8596 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008597 return get_errno(target_mprotect(arg1, arg2, arg3));
thse5febef2007-04-01 18:31:35 +00008598#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008599 case TARGET_NR_mremap:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008600 return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
thse5febef2007-04-01 18:31:35 +00008601#endif
pbrook53a59602006-03-25 19:31:22 +00008602 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008603#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008604 case TARGET_NR_msync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008605 return get_errno(msync(g2h(arg1), arg2, arg3));
thse5febef2007-04-01 18:31:35 +00008606#endif
8607#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008608 case TARGET_NR_mlock:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008609 return get_errno(mlock(g2h(arg1), arg2));
thse5febef2007-04-01 18:31:35 +00008610#endif
8611#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008612 case TARGET_NR_munlock:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008613 return get_errno(munlock(g2h(arg1), arg2));
thse5febef2007-04-01 18:31:35 +00008614#endif
8615#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008616 case TARGET_NR_mlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008617 return get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
thse5febef2007-04-01 18:31:35 +00008618#endif
8619#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008620 case TARGET_NR_munlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008621 return get_errno(munlockall());
thse5febef2007-04-01 18:31:35 +00008622#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008623#ifdef TARGET_NR_truncate
bellard31e31b82003-02-18 22:55:36 +00008624 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008625 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008626 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008627 ret = get_errno(truncate(p, arg2));
8628 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008629 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008630#endif
8631#ifdef TARGET_NR_ftruncate
bellard31e31b82003-02-18 22:55:36 +00008632 case TARGET_NR_ftruncate:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008633 return get_errno(ftruncate(arg1, arg2));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008634#endif
bellard31e31b82003-02-18 22:55:36 +00008635 case TARGET_NR_fchmod:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008636 return get_errno(fchmod(arg1, arg2));
Peter Maydellc0d472b2013-06-12 16:20:21 +01008637#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008638 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008639 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008640 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008641 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008642 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008643 return ret;
ths814d7972007-09-24 09:26:51 +00008644#endif
bellard31e31b82003-02-18 22:55:36 +00008645 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008646 /* Note that negative values are valid for getpriority, so we must
8647 differentiate based on errno settings. */
8648 errno = 0;
8649 ret = getpriority(arg1, arg2);
8650 if (ret == -1 && errno != 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008651 return -host_to_target_errno(errno);
Richard Henderson95c09822012-06-07 15:14:50 -07008652 }
8653#ifdef TARGET_ALPHA
8654 /* Return value is the unbiased priority. Signal no error. */
8655 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8656#else
8657 /* Return value is a biased priority to avoid negative numbers. */
8658 ret = 20 - ret;
8659#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008660 return ret;
bellard31e31b82003-02-18 22:55:36 +00008661 case TARGET_NR_setpriority:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008662 return get_errno(setpriority(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008663#ifdef TARGET_NR_statfs
bellard31e31b82003-02-18 22:55:36 +00008664 case TARGET_NR_statfs:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008665 if (!(p = lock_user_string(arg1))) {
8666 return -TARGET_EFAULT;
8667 }
pbrook53a59602006-03-25 19:31:22 +00008668 ret = get_errno(statfs(path(p), &stfs));
8669 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008670 convert_statfs:
8671 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008672 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008673
bellard579a97f2007-11-11 14:26:47 +00008674 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008675 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008676 __put_user(stfs.f_type, &target_stfs->f_type);
8677 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8678 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8679 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8680 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8681 __put_user(stfs.f_files, &target_stfs->f_files);
8682 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8683 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8684 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8685 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008686 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05008687#ifdef _STATFS_F_FLAGS
8688 __put_user(stfs.f_flags, &target_stfs->f_flags);
8689#else
8690 __put_user(0, &target_stfs->f_flags);
8691#endif
Alexander Graf229d3372012-09-19 04:39:53 +02008692 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008693 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008694 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008695 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008696#endif
8697#ifdef TARGET_NR_fstatfs
bellard31e31b82003-02-18 22:55:36 +00008698 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008699 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008700 goto convert_statfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008701#endif
bellard56c8f682005-11-28 22:28:41 +00008702#ifdef TARGET_NR_statfs64
8703 case TARGET_NR_statfs64:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008704 if (!(p = lock_user_string(arg1))) {
8705 return -TARGET_EFAULT;
8706 }
pbrook53a59602006-03-25 19:31:22 +00008707 ret = get_errno(statfs(path(p), &stfs));
8708 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008709 convert_statfs64:
8710 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008711 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008712
bellard579a97f2007-11-11 14:26:47 +00008713 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008714 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008715 __put_user(stfs.f_type, &target_stfs->f_type);
8716 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8717 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8718 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8719 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8720 __put_user(stfs.f_files, &target_stfs->f_files);
8721 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8722 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8723 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8724 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008725 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8726 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008727 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008728 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008729 return ret;
bellard56c8f682005-11-28 22:28:41 +00008730 case TARGET_NR_fstatfs64:
8731 ret = get_errno(fstatfs(arg1, &stfs));
8732 goto convert_statfs64;
8733#endif
thse5febef2007-04-01 18:31:35 +00008734#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008735 case TARGET_NR_socketcall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008736 return do_socketcall(arg1, arg2);
thse5febef2007-04-01 18:31:35 +00008737#endif
bellard3532fa72006-06-24 15:06:03 +00008738#ifdef TARGET_NR_accept
8739 case TARGET_NR_accept:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008740 return do_accept4(arg1, arg2, arg3, 0);
Peter Maydella94b4982013-02-08 04:35:04 +00008741#endif
8742#ifdef TARGET_NR_accept4
8743 case TARGET_NR_accept4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008744 return do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008745#endif
8746#ifdef TARGET_NR_bind
8747 case TARGET_NR_bind:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008748 return do_bind(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008749#endif
8750#ifdef TARGET_NR_connect
8751 case TARGET_NR_connect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008752 return do_connect(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008753#endif
8754#ifdef TARGET_NR_getpeername
8755 case TARGET_NR_getpeername:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008756 return do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008757#endif
8758#ifdef TARGET_NR_getsockname
8759 case TARGET_NR_getsockname:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008760 return do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008761#endif
8762#ifdef TARGET_NR_getsockopt
8763 case TARGET_NR_getsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008764 return do_getsockopt(arg1, arg2, arg3, arg4, arg5);
bellard3532fa72006-06-24 15:06:03 +00008765#endif
8766#ifdef TARGET_NR_listen
8767 case TARGET_NR_listen:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008768 return get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008769#endif
8770#ifdef TARGET_NR_recv
8771 case TARGET_NR_recv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008772 return do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008773#endif
8774#ifdef TARGET_NR_recvfrom
8775 case TARGET_NR_recvfrom:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008776 return do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008777#endif
8778#ifdef TARGET_NR_recvmsg
8779 case TARGET_NR_recvmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008780 return do_sendrecvmsg(arg1, arg2, arg3, 0);
bellard3532fa72006-06-24 15:06:03 +00008781#endif
8782#ifdef TARGET_NR_send
8783 case TARGET_NR_send:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008784 return do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008785#endif
8786#ifdef TARGET_NR_sendmsg
8787 case TARGET_NR_sendmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008788 return do_sendrecvmsg(arg1, arg2, arg3, 1);
bellard3532fa72006-06-24 15:06:03 +00008789#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008790#ifdef TARGET_NR_sendmmsg
8791 case TARGET_NR_sendmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008792 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
Alexander Graff19e00d2014-03-02 19:36:42 +00008793 case TARGET_NR_recvmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008794 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
Alexander Graff19e00d2014-03-02 19:36:42 +00008795#endif
bellard3532fa72006-06-24 15:06:03 +00008796#ifdef TARGET_NR_sendto
8797 case TARGET_NR_sendto:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008798 return do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008799#endif
8800#ifdef TARGET_NR_shutdown
8801 case TARGET_NR_shutdown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008802 return get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008803#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008804#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8805 case TARGET_NR_getrandom:
8806 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8807 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008808 return -TARGET_EFAULT;
Laurent Vivierf894efd2016-02-21 10:56:23 +01008809 }
8810 ret = get_errno(getrandom(p, arg2, arg3));
8811 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008812 return ret;
Laurent Vivierf894efd2016-02-21 10:56:23 +01008813#endif
bellard3532fa72006-06-24 15:06:03 +00008814#ifdef TARGET_NR_socket
8815 case TARGET_NR_socket:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008816 return do_socket(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008817#endif
8818#ifdef TARGET_NR_socketpair
8819 case TARGET_NR_socketpair:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008820 return do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008821#endif
8822#ifdef TARGET_NR_setsockopt
8823 case TARGET_NR_setsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008824 return do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
bellard3532fa72006-06-24 15:06:03 +00008825#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008826#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00008827 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008828 {
8829 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00008830
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008831 switch (arg1) {
8832 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
8833 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
8834 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
8835 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
8836 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
8837 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
8838 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
8839 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008840 return get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008841 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
8842 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
8843 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
8844 {
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008845 if (len < 0) {
Richard Henderson259841c2018-08-18 12:01:09 -07008846 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008847 }
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008848 if (len == 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008849 return 0;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008850 }
8851 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8852 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -07008853 return -TARGET_EFAULT;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008854 }
8855 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8856 unlock_user(p, arg2, arg3);
8857 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008858 return ret;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008859 default:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008860 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02008861 }
8862 }
8863 break;
8864#endif
bellard31e31b82003-02-18 22:55:36 +00008865 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008866 {
bellard66fb9762003-03-23 01:06:05 +00008867 struct itimerval value, ovalue, *pvalue;
8868
pbrook53a59602006-03-25 19:31:22 +00008869 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008870 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008871 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8872 || copy_from_user_timeval(&pvalue->it_value,
8873 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008874 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00008875 } else {
8876 pvalue = NULL;
8877 }
8878 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008879 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008880 if (copy_to_user_timeval(arg3,
8881 &ovalue.it_interval)
8882 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8883 &ovalue.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008884 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00008885 }
8886 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008887 return ret;
bellard31e31b82003-02-18 22:55:36 +00008888 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008889 {
bellard66fb9762003-03-23 01:06:05 +00008890 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008891
bellard66fb9762003-03-23 01:06:05 +00008892 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008893 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008894 if (copy_to_user_timeval(arg2,
8895 &value.it_interval)
8896 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8897 &value.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008898 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00008899 }
8900 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008901 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008902#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008903 case TARGET_NR_stat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008904 if (!(p = lock_user_string(arg1))) {
8905 return -TARGET_EFAULT;
8906 }
pbrook53a59602006-03-25 19:31:22 +00008907 ret = get_errno(stat(path(p), &st));
8908 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008909 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008910#endif
8911#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008912 case TARGET_NR_lstat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008913 if (!(p = lock_user_string(arg1))) {
8914 return -TARGET_EFAULT;
8915 }
pbrook53a59602006-03-25 19:31:22 +00008916 ret = get_errno(lstat(path(p), &st));
8917 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008918 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008919#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008920#ifdef TARGET_NR_fstat
bellard31e31b82003-02-18 22:55:36 +00008921 case TARGET_NR_fstat:
8922 {
8923 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008924#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008925 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008926#endif
bellard31e31b82003-02-18 22:55:36 +00008927 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008928 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008929
bellard579a97f2007-11-11 14:26:47 +00008930 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008931 return -TARGET_EFAULT;
Ulrich Hecht12727912009-07-24 19:10:32 +02008932 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008933 __put_user(st.st_dev, &target_st->st_dev);
8934 __put_user(st.st_ino, &target_st->st_ino);
8935 __put_user(st.st_mode, &target_st->st_mode);
8936 __put_user(st.st_uid, &target_st->st_uid);
8937 __put_user(st.st_gid, &target_st->st_gid);
8938 __put_user(st.st_nlink, &target_st->st_nlink);
8939 __put_user(st.st_rdev, &target_st->st_rdev);
8940 __put_user(st.st_size, &target_st->st_size);
8941 __put_user(st.st_blksize, &target_st->st_blksize);
8942 __put_user(st.st_blocks, &target_st->st_blocks);
8943 __put_user(st.st_atime, &target_st->target_st_atime);
8944 __put_user(st.st_mtime, &target_st->target_st_mtime);
8945 __put_user(st.st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08008946#if (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) && \
8947 defined(TARGET_STAT_HAVE_NSEC)
8948 __put_user(st.st_atim.tv_nsec,
8949 &target_st->target_st_atime_nsec);
8950 __put_user(st.st_mtim.tv_nsec,
8951 &target_st->target_st_mtime_nsec);
8952 __put_user(st.st_ctim.tv_nsec,
8953 &target_st->target_st_ctime_nsec);
8954#endif
pbrook53a59602006-03-25 19:31:22 +00008955 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008956 }
8957 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008958 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008959#endif
bellard31e31b82003-02-18 22:55:36 +00008960 case TARGET_NR_vhangup:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008961 return get_errno(vhangup());
bellard42ad6ae2005-01-03 22:48:11 +00008962#ifdef TARGET_NR_syscall
8963 case TARGET_NR_syscall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008964 return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8965 arg6, arg7, arg8, 0);
bellard42ad6ae2005-01-03 22:48:11 +00008966#endif
bellard31e31b82003-02-18 22:55:36 +00008967 case TARGET_NR_wait4:
8968 {
8969 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008970 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008971 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008972 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008973 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008974 if (target_rusage)
8975 rusage_ptr = &rusage;
8976 else
8977 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008978 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008979 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008980 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008981 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008982 if (put_user_s32(status, status_ptr))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008983 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00008984 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008985 if (target_rusage) {
8986 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8987 if (rusage_err) {
8988 ret = rusage_err;
8989 }
8990 }
bellard31e31b82003-02-18 22:55:36 +00008991 }
8992 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008993 return ret;
thse5febef2007-04-01 18:31:35 +00008994#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008995 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008996 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008997 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008998 ret = get_errno(swapoff(p));
8999 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009000 return ret;
thse5febef2007-04-01 18:31:35 +00009001#endif
bellard31e31b82003-02-18 22:55:36 +00009002 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009003 {
pbrook53a59602006-03-25 19:31:22 +00009004 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009005 struct sysinfo value;
9006 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009007 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009008 {
bellard579a97f2007-11-11 14:26:47 +00009009 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009010 return -TARGET_EFAULT;
bellarda5448a72004-06-19 16:59:03 +00009011 __put_user(value.uptime, &target_value->uptime);
9012 __put_user(value.loads[0], &target_value->loads[0]);
9013 __put_user(value.loads[1], &target_value->loads[1]);
9014 __put_user(value.loads[2], &target_value->loads[2]);
9015 __put_user(value.totalram, &target_value->totalram);
9016 __put_user(value.freeram, &target_value->freeram);
9017 __put_user(value.sharedram, &target_value->sharedram);
9018 __put_user(value.bufferram, &target_value->bufferram);
9019 __put_user(value.totalswap, &target_value->totalswap);
9020 __put_user(value.freeswap, &target_value->freeswap);
9021 __put_user(value.procs, &target_value->procs);
9022 __put_user(value.totalhigh, &target_value->totalhigh);
9023 __put_user(value.freehigh, &target_value->freehigh);
9024 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009025 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009026 }
9027 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009028 return ret;
thse5febef2007-04-01 18:31:35 +00009029#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009030 case TARGET_NR_ipc:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009031 return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
thse5febef2007-04-01 18:31:35 +00009032#endif
aurel32e5289082009-04-18 16:16:12 +00009033#ifdef TARGET_NR_semget
9034 case TARGET_NR_semget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009035 return get_errno(semget(arg1, arg2, arg3));
aurel32e5289082009-04-18 16:16:12 +00009036#endif
9037#ifdef TARGET_NR_semop
9038 case TARGET_NR_semop:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009039 return do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009040#endif
9041#ifdef TARGET_NR_semctl
9042 case TARGET_NR_semctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009043 return do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009044#endif
aurel32eeb438c2008-10-13 21:08:55 +00009045#ifdef TARGET_NR_msgctl
9046 case TARGET_NR_msgctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009047 return do_msgctl(arg1, arg2, arg3);
aurel32eeb438c2008-10-13 21:08:55 +00009048#endif
9049#ifdef TARGET_NR_msgget
9050 case TARGET_NR_msgget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009051 return get_errno(msgget(arg1, arg2));
aurel32eeb438c2008-10-13 21:08:55 +00009052#endif
9053#ifdef TARGET_NR_msgrcv
9054 case TARGET_NR_msgrcv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009055 return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
aurel32eeb438c2008-10-13 21:08:55 +00009056#endif
9057#ifdef TARGET_NR_msgsnd
9058 case TARGET_NR_msgsnd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009059 return do_msgsnd(arg1, arg2, arg3, arg4);
aurel32eeb438c2008-10-13 21:08:55 +00009060#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009061#ifdef TARGET_NR_shmget
9062 case TARGET_NR_shmget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009063 return get_errno(shmget(arg1, arg2, arg3));
Riku Voipio88a8c982009-04-03 10:42:00 +03009064#endif
9065#ifdef TARGET_NR_shmctl
9066 case TARGET_NR_shmctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009067 return do_shmctl(arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009068#endif
9069#ifdef TARGET_NR_shmat
9070 case TARGET_NR_shmat:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009071 return do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009072#endif
9073#ifdef TARGET_NR_shmdt
9074 case TARGET_NR_shmdt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009075 return do_shmdt(arg1);
Riku Voipio88a8c982009-04-03 10:42:00 +03009076#endif
bellard31e31b82003-02-18 22:55:36 +00009077 case TARGET_NR_fsync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009078 return get_errno(fsync(arg1));
bellard31e31b82003-02-18 22:55:36 +00009079 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009080 /* Linux manages to have three different orderings for its
9081 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9082 * match the kernel's CONFIG_CLONE_* settings.
9083 * Microblaze is further special in that it uses a sixth
9084 * implicit argument to clone for the TLS pointer.
9085 */
9086#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009087 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009088#elif defined(TARGET_CLONE_BACKWARDS)
9089 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9090#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009091 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009092#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009093 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009094#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009095 return ret;
bellardec86b0f2003-04-11 00:15:04 +00009096#ifdef __NR_exit_group
9097 /* new thread calls */
9098 case TARGET_NR_exit_group:
Alex Bennée708b6a62018-06-22 17:09:10 +01009099 preexit_cleanup(cpu_env, arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009100 return get_errno(exit_group(arg1));
bellardec86b0f2003-04-11 00:15:04 +00009101#endif
bellard31e31b82003-02-18 22:55:36 +00009102 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009103 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009104 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009105 ret = get_errno(setdomainname(p, arg2));
9106 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009107 return ret;
bellard31e31b82003-02-18 22:55:36 +00009108 case TARGET_NR_uname:
9109 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009110 {
9111 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009112
bellard579a97f2007-11-11 14:26:47 +00009113 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009114 return -TARGET_EFAULT;
bellard29e619b2004-09-13 21:41:04 +00009115 ret = get_errno(sys_uname(buf));
9116 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009117 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009118 emulated. */
Philippe Mathieu-Daudé871f95c2017-07-24 15:27:47 -03009119 g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
9120 sizeof(buf->machine));
pbrookc5937222006-05-14 11:30:38 +00009121 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009122 if (qemu_uname_release && *qemu_uname_release) {
9123 g_strlcpy(buf->release, qemu_uname_release,
9124 sizeof(buf->release));
9125 }
bellard29e619b2004-09-13 21:41:04 +00009126 }
pbrook53a59602006-03-25 19:31:22 +00009127 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009128 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009129 return ret;
bellard6dbad632003-03-16 18:05:05 +00009130#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009131 case TARGET_NR_modify_ldt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009132 return do_modify_ldt(cpu_env, arg1, arg2, arg3);
j_mayer84409dd2007-04-06 08:56:50 +00009133#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009134 case TARGET_NR_vm86:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009135 return do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009136#endif
j_mayer84409dd2007-04-06 08:56:50 +00009137#endif
bellard31e31b82003-02-18 22:55:36 +00009138 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02009139 {
9140 struct timex host_buf;
9141
9142 if (target_to_host_timex(&host_buf, arg1) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009143 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02009144 }
9145 ret = get_errno(adjtimex(&host_buf));
9146 if (!is_error(ret)) {
9147 if (host_to_target_timex(arg1, &host_buf) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009148 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02009149 }
9150 }
9151 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009152 return ret;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009153#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
9154 case TARGET_NR_clock_adjtime:
9155 {
9156 struct timex htx, *phtx = &htx;
9157
9158 if (target_to_host_timex(phtx, arg2) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009159 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009160 }
9161 ret = get_errno(clock_adjtime(arg1, phtx));
9162 if (!is_error(ret) && phtx) {
9163 if (host_to_target_timex(arg2, phtx) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009164 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009165 }
9166 }
9167 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009168 return ret;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009169#endif
bellard31e31b82003-02-18 22:55:36 +00009170 case TARGET_NR_getpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009171 return get_errno(getpgid(arg1));
bellard31e31b82003-02-18 22:55:36 +00009172 case TARGET_NR_fchdir:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009173 return get_errno(fchdir(arg1));
bellard31e31b82003-02-18 22:55:36 +00009174 case TARGET_NR_personality:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009175 return get_errno(personality(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00009176#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009177 case TARGET_NR__llseek:
9178 {
9179 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009180#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +01009181 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +00009182 if (res == -1) {
9183 ret = get_errno(res);
9184 } else {
9185 ret = 0;
9186 }
9187#else
bellard31e31b82003-02-18 22:55:36 +00009188 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00009189#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00009190 if ((ret == 0) && put_user_s64(res, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009191 return -TARGET_EFAULT;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009192 }
bellard31e31b82003-02-18 22:55:36 +00009193 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009194 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009195#endif
Chen Gang704eff62015-08-21 05:37:33 +08009196#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00009197 case TARGET_NR_getdents:
Peter Maydell2b3f64c2018-04-19 13:57:40 +01009198#ifdef EMULATE_GETDENTS_WITH_GETDENTS
Ulrich Hechtd83c8732009-07-24 19:10:28 +02009199#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00009200 {
pbrook53a59602006-03-25 19:31:22 +00009201 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00009202 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009203 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00009204
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309205 dirp = g_try_malloc(count);
9206 if (!dirp) {
Richard Henderson259841c2018-08-18 12:01:09 -07009207 return -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00009208 }
ths3b46e622007-09-17 08:09:54 +00009209
bellard4add45b2003-06-05 01:52:59 +00009210 ret = get_errno(sys_getdents(arg1, dirp, count));
9211 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009212 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00009213 struct target_dirent *tde;
9214 int len = ret;
9215 int reclen, treclen;
9216 int count1, tnamelen;
9217
9218 count1 = 0;
9219 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00009220 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009221 return -TARGET_EFAULT;
bellard4add45b2003-06-05 01:52:59 +00009222 tde = target_dirp;
9223 while (len > 0) {
9224 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009225 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
9226 assert(tnamelen >= 0);
9227 treclen = tnamelen + offsetof(struct target_dirent, d_name);
9228 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00009229 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009230 tde->d_ino = tswapal(de->d_ino);
9231 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009232 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009233 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009234 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009235 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009236 count1 += treclen;
9237 }
9238 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009239 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009240 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309241 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009242 }
9243#else
bellard31e31b82003-02-18 22:55:36 +00009244 {
aurel326556a832008-10-13 21:08:17 +00009245 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009246 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009247
bellard579a97f2007-11-11 14:26:47 +00009248 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009249 return -TARGET_EFAULT;
bellard72f03902003-02-18 23:33:18 +00009250 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009251 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009252 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00009253 int len = ret;
9254 int reclen;
9255 de = dirp;
9256 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009257 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009258 if (reclen > len)
9259 break;
bellard8083a3e2003-03-24 23:12:16 +00009260 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009261 tswapls(&de->d_ino);
9262 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009263 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009264 len -= reclen;
9265 }
9266 }
pbrook53a59602006-03-25 19:31:22 +00009267 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009268 }
bellard4add45b2003-06-05 01:52:59 +00009269#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009270#else
9271 /* Implement getdents in terms of getdents64 */
9272 {
9273 struct linux_dirent64 *dirp;
9274 abi_long count = arg3;
9275
9276 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9277 if (!dirp) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009278 return -TARGET_EFAULT;
Peter Maydell3307e232013-06-12 16:20:21 +01009279 }
9280 ret = get_errno(sys_getdents64(arg1, dirp, count));
9281 if (!is_error(ret)) {
9282 /* Convert the dirent64 structs to target dirent. We do this
9283 * in-place, since we can guarantee that a target_dirent is no
9284 * larger than a dirent64; however this means we have to be
9285 * careful to read everything before writing in the new format.
9286 */
9287 struct linux_dirent64 *de;
9288 struct target_dirent *tde;
9289 int len = ret;
9290 int tlen = 0;
9291
9292 de = dirp;
9293 tde = (struct target_dirent *)dirp;
9294 while (len > 0) {
9295 int namelen, treclen;
9296 int reclen = de->d_reclen;
9297 uint64_t ino = de->d_ino;
9298 int64_t off = de->d_off;
9299 uint8_t type = de->d_type;
9300
9301 namelen = strlen(de->d_name);
9302 treclen = offsetof(struct target_dirent, d_name)
9303 + namelen + 2;
9304 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9305
9306 memmove(tde->d_name, de->d_name, namelen + 1);
9307 tde->d_ino = tswapal(ino);
9308 tde->d_off = tswapal(off);
9309 tde->d_reclen = tswap16(treclen);
9310 /* The target_dirent type is in what was formerly a padding
9311 * byte at the end of the structure:
9312 */
9313 *(((char *)tde) + treclen - 1) = type;
9314
9315 de = (struct linux_dirent64 *)((char *)de + reclen);
9316 tde = (struct target_dirent *)((char *)tde + treclen);
9317 len -= reclen;
9318 tlen += treclen;
9319 }
9320 ret = tlen;
9321 }
9322 unlock_user(dirp, arg2, ret);
9323 }
9324#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009325 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009326#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009327#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009328 case TARGET_NR_getdents64:
9329 {
aurel326556a832008-10-13 21:08:17 +00009330 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009331 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009332 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009333 return -TARGET_EFAULT;
bellarddab2ed92003-03-22 15:23:14 +00009334 ret = get_errno(sys_getdents64(arg1, dirp, count));
9335 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009336 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009337 int len = ret;
9338 int reclen;
9339 de = dirp;
9340 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009341 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009342 if (reclen > len)
9343 break;
bellard8083a3e2003-03-24 23:12:16 +00009344 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009345 tswap64s((uint64_t *)&de->d_ino);
9346 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009347 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009348 len -= reclen;
9349 }
9350 }
pbrook53a59602006-03-25 19:31:22 +00009351 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009352 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009353 return ret;
bellarda541f292004-04-12 20:39:29 +00009354#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009355#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009356 case TARGET_NR__newselect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009357 return do_select(arg1, arg2, arg3, arg4, arg5);
thse5febef2007-04-01 18:31:35 +00009358#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009359#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9360# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009361 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009362# endif
9363# ifdef TARGET_NR_ppoll
9364 case TARGET_NR_ppoll:
9365# endif
bellard9de5e442003-03-23 16:49:39 +00009366 {
pbrook53a59602006-03-25 19:31:22 +00009367 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009368 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009369 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009370 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009371
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009372 pfd = NULL;
9373 target_pfd = NULL;
9374 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +01009375 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009376 return -TARGET_EINVAL;
Peter Maydellce9c1392016-07-18 16:30:36 +01009377 }
9378
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009379 target_pfd = lock_user(VERIFY_WRITE, arg1,
9380 sizeof(struct target_pollfd) * nfds, 1);
9381 if (!target_pfd) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009382 return -TARGET_EFAULT;
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009383 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009384
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009385 pfd = alloca(sizeof(struct pollfd) * nfds);
9386 for (i = 0; i < nfds; i++) {
9387 pfd[i].fd = tswap32(target_pfd[i].fd);
9388 pfd[i].events = tswap16(target_pfd[i].events);
9389 }
bellard9de5e442003-03-23 16:49:39 +00009390 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009391
Peter Maydella6130232016-06-06 19:58:10 +01009392 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009393# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009394 case TARGET_NR_ppoll:
9395 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009396 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9397 target_sigset_t *target_set;
9398 sigset_t _set, *set = &_set;
9399
9400 if (arg3) {
9401 if (target_to_host_timespec(timeout_ts, arg3)) {
9402 unlock_user(target_pfd, arg1, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07009403 return -TARGET_EFAULT;
Mike Frysingerd8035d42011-02-07 01:05:51 -05009404 }
9405 } else {
9406 timeout_ts = NULL;
9407 }
9408
9409 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +01009410 if (arg5 != sizeof(target_sigset_t)) {
9411 unlock_user(target_pfd, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009412 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009413 }
9414
Mike Frysingerd8035d42011-02-07 01:05:51 -05009415 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9416 if (!target_set) {
9417 unlock_user(target_pfd, arg1, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07009418 return -TARGET_EFAULT;
Mike Frysingerd8035d42011-02-07 01:05:51 -05009419 }
9420 target_to_host_sigset(set, target_set);
9421 } else {
9422 set = NULL;
9423 }
9424
Peter Maydella6130232016-06-06 19:58:10 +01009425 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
9426 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009427
9428 if (!is_error(ret) && arg3) {
9429 host_to_target_timespec(arg3, timeout_ts);
9430 }
9431 if (arg4) {
9432 unlock_user(target_set, arg4, 0);
9433 }
Peter Maydella6130232016-06-06 19:58:10 +01009434 break;
9435 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009436# endif
Peter Maydella6130232016-06-06 19:58:10 +01009437# ifdef TARGET_NR_poll
9438 case TARGET_NR_poll:
9439 {
9440 struct timespec ts, *pts;
9441
9442 if (arg3 >= 0) {
9443 /* Convert ms to secs, ns */
9444 ts.tv_sec = arg3 / 1000;
9445 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
9446 pts = &ts;
9447 } else {
9448 /* -ve poll() timeout means "infinite" */
9449 pts = NULL;
9450 }
9451 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
9452 break;
9453 }
9454# endif
9455 default:
9456 g_assert_not_reached();
9457 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009458
bellard9de5e442003-03-23 16:49:39 +00009459 if (!is_error(ret)) {
9460 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009461 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009462 }
9463 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009464 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009465 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009466 return ret;
thse5febef2007-04-01 18:31:35 +00009467#endif
bellard31e31b82003-02-18 22:55:36 +00009468 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009469 /* NOTE: the flock constant seems to be the same for every
9470 Linux platform */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009471 return get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009472 case TARGET_NR_readv:
9473 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009474 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9475 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009476 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009477 unlock_iovec(vec, arg2, arg3, 1);
9478 } else {
9479 ret = -host_to_target_errno(errno);
9480 }
bellard31e31b82003-02-18 22:55:36 +00009481 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009482 return ret;
bellard31e31b82003-02-18 22:55:36 +00009483 case TARGET_NR_writev:
9484 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009485 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9486 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009487 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009488 unlock_iovec(vec, arg2, arg3, 0);
9489 } else {
9490 ret = -host_to_target_errno(errno);
9491 }
bellard31e31b82003-02-18 22:55:36 +00009492 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009493 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +02009494#if defined(TARGET_NR_preadv)
9495 case TARGET_NR_preadv:
9496 {
9497 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9498 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -07009499 unsigned long low, high;
9500
9501 target_to_host_low_high(arg4, arg5, &low, &high);
9502 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +02009503 unlock_iovec(vec, arg2, arg3, 1);
9504 } else {
9505 ret = -host_to_target_errno(errno);
9506 }
9507 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009508 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +02009509#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +02009510#if defined(TARGET_NR_pwritev)
9511 case TARGET_NR_pwritev:
9512 {
9513 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9514 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -07009515 unsigned long low, high;
9516
9517 target_to_host_low_high(arg4, arg5, &low, &high);
9518 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +02009519 unlock_iovec(vec, arg2, arg3, 0);
9520 } else {
9521 ret = -host_to_target_errno(errno);
9522 }
9523 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009524 return ret;
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +02009525#endif
bellard31e31b82003-02-18 22:55:36 +00009526 case TARGET_NR_getsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009527 return get_errno(getsid(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00009528#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009529 case TARGET_NR_fdatasync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009530 return get_errno(fdatasync(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00009531#endif
Chen Gang704eff62015-08-21 05:37:33 +08009532#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009533 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009534 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009535 return value. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009536 return -TARGET_ENOTDIR;
Chen Gang704eff62015-08-21 05:37:33 +08009537#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009538 case TARGET_NR_sched_getaffinity:
9539 {
9540 unsigned int mask_size;
9541 unsigned long *mask;
9542
9543 /*
9544 * sched_getaffinity needs multiples of ulong, so need to take
9545 * care of mismatches between target ulong and host ulong sizes.
9546 */
9547 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009548 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -05009549 }
9550 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9551
9552 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +01009553 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -05009554 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9555
9556 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009557 if (ret > arg2) {
9558 /* More data returned than the caller's buffer will fit.
9559 * This only happens if sizeof(abi_long) < sizeof(long)
9560 * and the caller passed us a buffer holding an odd number
9561 * of abi_longs. If the host kernel is actually using the
9562 * extra 4 bytes then fail EINVAL; otherwise we can just
9563 * ignore them and only copy the interesting part.
9564 */
9565 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9566 if (numcpus > arg2 * 8) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009567 return -TARGET_EINVAL;
Peter Maydellbe3bd282014-05-15 14:40:23 +01009568 }
9569 ret = arg2;
9570 }
9571
Samuel Thibault5fdefcf2018-02-11 18:47:04 +01009572 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009573 return -TARGET_EFAULT;
Samuel Thibault5fdefcf2018-02-11 18:47:04 +01009574 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009575 }
9576 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009577 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -05009578 case TARGET_NR_sched_setaffinity:
9579 {
9580 unsigned int mask_size;
9581 unsigned long *mask;
9582
9583 /*
9584 * sched_setaffinity needs multiples of ulong, so need to take
9585 * care of mismatches between target ulong and host ulong sizes.
9586 */
9587 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009588 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -05009589 }
9590 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -05009591 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +01009592
9593 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
9594 if (ret) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009595 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -05009596 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009597
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009598 return get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
Mike Frysinger737de1d2011-02-07 01:05:55 -05009599 }
Samuel Thibaultb827c3e2018-01-12 09:14:35 +01009600 case TARGET_NR_getcpu:
9601 {
9602 unsigned cpu, node;
9603 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
9604 arg2 ? &node : NULL,
9605 NULL));
9606 if (is_error(ret)) {
Richard Henderson259841c2018-08-18 12:01:09 -07009607 return ret;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +01009608 }
9609 if (arg1 && put_user_u32(cpu, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009610 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +01009611 }
9612 if (arg2 && put_user_u32(node, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009613 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +01009614 }
9615 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009616 return ret;
bellard31e31b82003-02-18 22:55:36 +00009617 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009618 {
pbrook53a59602006-03-25 19:31:22 +00009619 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009620 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009621
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009622 if (arg2 == 0) {
9623 return -TARGET_EINVAL;
9624 }
bellard579a97f2007-11-11 14:26:47 +00009625 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009626 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +00009627 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009628 unlock_user_struct(target_schp, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009629 return get_errno(sched_setparam(arg1, &schp));
bellard5cd43932003-03-29 16:54:36 +00009630 }
bellard31e31b82003-02-18 22:55:36 +00009631 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009632 {
pbrook53a59602006-03-25 19:31:22 +00009633 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009634 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009635
9636 if (arg2 == 0) {
9637 return -TARGET_EINVAL;
9638 }
bellard5cd43932003-03-29 16:54:36 +00009639 ret = get_errno(sched_getparam(arg1, &schp));
9640 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009641 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009642 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +00009643 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009644 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009645 }
9646 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009647 return ret;
bellard31e31b82003-02-18 22:55:36 +00009648 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009649 {
pbrook53a59602006-03-25 19:31:22 +00009650 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009651 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009652 if (arg3 == 0) {
9653 return -TARGET_EINVAL;
9654 }
bellard579a97f2007-11-11 14:26:47 +00009655 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009656 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +00009657 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009658 unlock_user_struct(target_schp, arg3, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009659 return get_errno(sched_setscheduler(arg1, arg2, &schp));
bellard5cd43932003-03-29 16:54:36 +00009660 }
bellard31e31b82003-02-18 22:55:36 +00009661 case TARGET_NR_sched_getscheduler:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009662 return get_errno(sched_getscheduler(arg1));
bellard31e31b82003-02-18 22:55:36 +00009663 case TARGET_NR_sched_yield:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009664 return get_errno(sched_yield());
bellard31e31b82003-02-18 22:55:36 +00009665 case TARGET_NR_sched_get_priority_max:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009666 return get_errno(sched_get_priority_max(arg1));
bellard31e31b82003-02-18 22:55:36 +00009667 case TARGET_NR_sched_get_priority_min:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009668 return get_errno(sched_get_priority_min(arg1));
bellard31e31b82003-02-18 22:55:36 +00009669 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009670 {
bellard5cd43932003-03-29 16:54:36 +00009671 struct timespec ts;
9672 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9673 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009674 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009675 }
9676 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009677 return ret;
bellard31e31b82003-02-18 22:55:36 +00009678 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009679 {
bellard1b6b0292003-03-22 17:31:38 +00009680 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009681 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009682 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009683 if (is_error(ret) && arg2) {
9684 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009685 }
9686 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009687 return ret;
bellard31e31b82003-02-18 22:55:36 +00009688 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009689 switch (arg1) {
9690 case PR_GET_PDEATHSIG:
9691 {
9692 int deathsig;
9693 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9694 if (!is_error(ret) && arg2
9695 && put_user_ual(deathsig, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009696 return -TARGET_EFAULT;
thse5574482007-02-11 20:03:13 +00009697 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009698 return ret;
Peter Maydell1e6722f2012-02-03 14:48:03 +00009699 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009700#ifdef PR_GET_NAME
9701 case PR_GET_NAME:
9702 {
9703 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9704 if (!name) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009705 return -TARGET_EFAULT;
Peter Maydelldb9526b2012-02-03 14:48:03 +00009706 }
9707 ret = get_errno(prctl(arg1, (unsigned long)name,
9708 arg3, arg4, arg5));
9709 unlock_user(name, arg2, 16);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009710 return ret;
Peter Maydelldb9526b2012-02-03 14:48:03 +00009711 }
9712 case PR_SET_NAME:
9713 {
9714 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9715 if (!name) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009716 return -TARGET_EFAULT;
Peter Maydelldb9526b2012-02-03 14:48:03 +00009717 }
9718 ret = get_errno(prctl(arg1, (unsigned long)name,
9719 arg3, arg4, arg5));
9720 unlock_user(name, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009721 return ret;
Peter Maydelldb9526b2012-02-03 14:48:03 +00009722 }
9723#endif
Stefan Markovic5b702ff2018-10-12 12:57:35 +02009724#ifdef TARGET_MIPS
9725 case TARGET_PR_GET_FP_MODE:
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009726 {
9727 CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
9728 ret = 0;
9729 if (env->CP0_Status & (1 << CP0St_FR)) {
9730 ret |= TARGET_PR_FP_MODE_FR;
9731 }
9732 if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
9733 ret |= TARGET_PR_FP_MODE_FRE;
9734 }
9735 return ret;
9736 }
Stefan Markovic5b702ff2018-10-12 12:57:35 +02009737 case TARGET_PR_SET_FP_MODE:
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009738 {
9739 CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
9740 bool old_fr = env->CP0_Status & (1 << CP0St_FR);
Stefan Markovic6456c512018-11-14 14:37:08 +01009741 bool old_fre = env->CP0_Config5 & (1 << CP0C5_FRE);
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009742 bool new_fr = arg2 & TARGET_PR_FP_MODE_FR;
9743 bool new_fre = arg2 & TARGET_PR_FP_MODE_FRE;
9744
Stefan Markovic6456c512018-11-14 14:37:08 +01009745 const unsigned int known_bits = TARGET_PR_FP_MODE_FR |
9746 TARGET_PR_FP_MODE_FRE;
9747
9748 /* If nothing to change, return right away, successfully. */
9749 if (old_fr == new_fr && old_fre == new_fre) {
9750 return 0;
9751 }
9752 /* Check the value is valid */
9753 if (arg2 & ~known_bits) {
9754 return -TARGET_EOPNOTSUPP;
9755 }
9756 /* Setting FRE without FR is not supported. */
9757 if (new_fre && !new_fr) {
9758 return -TARGET_EOPNOTSUPP;
9759 }
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009760 if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) {
9761 /* FR1 is not supported */
9762 return -TARGET_EOPNOTSUPP;
9763 }
9764 if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64))
9765 && !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
9766 /* cannot set FR=0 */
9767 return -TARGET_EOPNOTSUPP;
9768 }
9769 if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) {
9770 /* Cannot set FRE=1 */
9771 return -TARGET_EOPNOTSUPP;
9772 }
9773
9774 int i;
9775 fpr_t *fpr = env->active_fpu.fpr;
9776 for (i = 0; i < 32 ; i += 2) {
9777 if (!old_fr && new_fr) {
9778 fpr[i].w[!FP_ENDIAN_IDX] = fpr[i + 1].w[FP_ENDIAN_IDX];
9779 } else if (old_fr && !new_fr) {
9780 fpr[i + 1].w[FP_ENDIAN_IDX] = fpr[i].w[!FP_ENDIAN_IDX];
9781 }
9782 }
9783
9784 if (new_fr) {
9785 env->CP0_Status |= (1 << CP0St_FR);
9786 env->hflags |= MIPS_HFLAG_F64;
9787 } else {
9788 env->CP0_Status &= ~(1 << CP0St_FR);
Stefan Markovic6456c512018-11-14 14:37:08 +01009789 env->hflags &= ~MIPS_HFLAG_F64;
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009790 }
9791 if (new_fre) {
9792 env->CP0_Config5 |= (1 << CP0C5_FRE);
9793 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
9794 env->hflags |= MIPS_HFLAG_FRE;
9795 }
9796 } else {
9797 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
Stefan Markovic6456c512018-11-14 14:37:08 +01009798 env->hflags &= ~MIPS_HFLAG_FRE;
Stefan Markovic64ea3d62018-10-26 13:17:43 +02009799 }
9800
9801 return 0;
9802 }
Stefan Markovic5b702ff2018-10-12 12:57:35 +02009803#endif /* MIPS */
Richard Henderson85fc7162018-03-09 17:09:43 +00009804#ifdef TARGET_AARCH64
9805 case TARGET_PR_SVE_SET_VL:
Richard Hendersonadf92ea2018-08-16 14:05:28 +01009806 /*
9807 * We cannot support either PR_SVE_SET_VL_ONEXEC or
9808 * PR_SVE_VL_INHERIT. Note the kernel definition
9809 * of sve_vl_valid allows for VQ=512, i.e. VL=8192,
9810 * even though the current architectural maximum is VQ=16.
9811 */
Richard Henderson85fc7162018-03-09 17:09:43 +00009812 ret = -TARGET_EINVAL;
Richard Henderson2fc0cc02019-03-22 17:41:14 -07009813 if (cpu_isar_feature(aa64_sve, env_archcpu(cpu_env))
Richard Hendersonadf92ea2018-08-16 14:05:28 +01009814 && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
Richard Henderson85fc7162018-03-09 17:09:43 +00009815 CPUARMState *env = cpu_env;
Richard Henderson2fc0cc02019-03-22 17:41:14 -07009816 ARMCPU *cpu = env_archcpu(env);
Richard Hendersonadf92ea2018-08-16 14:05:28 +01009817 uint32_t vq, old_vq;
9818
9819 old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
9820 vq = MAX(arg2 / 16, 1);
9821 vq = MIN(vq, cpu->sve_max_vq);
Richard Henderson85fc7162018-03-09 17:09:43 +00009822
9823 if (vq < old_vq) {
9824 aarch64_sve_narrow_vq(env, vq);
9825 }
9826 env->vfp.zcr_el[1] = vq - 1;
9827 ret = vq * 16;
9828 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009829 return ret;
Richard Henderson85fc7162018-03-09 17:09:43 +00009830 case TARGET_PR_SVE_GET_VL:
9831 ret = -TARGET_EINVAL;
Richard Hendersoncd208a12018-10-24 07:50:17 +01009832 {
Richard Henderson2fc0cc02019-03-22 17:41:14 -07009833 ARMCPU *cpu = env_archcpu(cpu_env);
Richard Hendersoncd208a12018-10-24 07:50:17 +01009834 if (cpu_isar_feature(aa64_sve, cpu)) {
9835 ret = ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
9836 }
Richard Henderson85fc7162018-03-09 17:09:43 +00009837 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009838 return ret;
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009839 case TARGET_PR_PAC_RESET_KEYS:
9840 {
9841 CPUARMState *env = cpu_env;
Richard Henderson2fc0cc02019-03-22 17:41:14 -07009842 ARMCPU *cpu = env_archcpu(env);
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009843
9844 if (arg3 || arg4 || arg5) {
9845 return -TARGET_EINVAL;
9846 }
9847 if (cpu_isar_feature(aa64_pauth, cpu)) {
9848 int all = (TARGET_PR_PAC_APIAKEY | TARGET_PR_PAC_APIBKEY |
9849 TARGET_PR_PAC_APDAKEY | TARGET_PR_PAC_APDBKEY |
9850 TARGET_PR_PAC_APGAKEY);
Richard Henderson51977e22019-03-12 19:22:20 -07009851 int ret = 0;
9852 Error *err = NULL;
9853
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009854 if (arg2 == 0) {
9855 arg2 = all;
9856 } else if (arg2 & ~all) {
9857 return -TARGET_EINVAL;
9858 }
9859 if (arg2 & TARGET_PR_PAC_APIAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -07009860 ret |= qemu_guest_getrandom(&env->keys.apia,
Richard Henderson51977e22019-03-12 19:22:20 -07009861 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009862 }
9863 if (arg2 & TARGET_PR_PAC_APIBKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -07009864 ret |= qemu_guest_getrandom(&env->keys.apib,
Richard Henderson51977e22019-03-12 19:22:20 -07009865 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009866 }
9867 if (arg2 & TARGET_PR_PAC_APDAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -07009868 ret |= qemu_guest_getrandom(&env->keys.apda,
Richard Henderson51977e22019-03-12 19:22:20 -07009869 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009870 }
9871 if (arg2 & TARGET_PR_PAC_APDBKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -07009872 ret |= qemu_guest_getrandom(&env->keys.apdb,
Richard Henderson51977e22019-03-12 19:22:20 -07009873 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009874 }
9875 if (arg2 & TARGET_PR_PAC_APGAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -07009876 ret |= qemu_guest_getrandom(&env->keys.apga,
Richard Henderson51977e22019-03-12 19:22:20 -07009877 sizeof(ARMPACKey), &err);
9878 }
9879 if (ret != 0) {
9880 /*
9881 * Some unknown failure in the crypto. The best
9882 * we can do is log it and fail the syscall.
9883 * The real syscall cannot fail this way.
9884 */
9885 qemu_log_mask(LOG_UNIMP,
9886 "PR_PAC_RESET_KEYS: Crypto failure: %s",
9887 error_get_pretty(err));
9888 error_free(err);
9889 return -TARGET_EIO;
Richard Hendersonbff63fb2019-02-05 16:52:39 +00009890 }
9891 return 0;
9892 }
9893 }
9894 return -TARGET_EINVAL;
Richard Henderson85fc7162018-03-09 17:09:43 +00009895#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +00009896 case PR_GET_SECCOMP:
9897 case PR_SET_SECCOMP:
9898 /* Disable seccomp to prevent the target disabling syscalls we
9899 * need. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009900 return -TARGET_EINVAL;
Peter Maydell1e6722f2012-02-03 14:48:03 +00009901 default:
9902 /* Most prctl options have no pointer arguments */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009903 return get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
Peter Maydell1e6722f2012-02-03 14:48:03 +00009904 }
ths39b9aae2007-02-11 18:36:44 +00009905 break;
bellardd2fd1af2007-11-14 18:08:56 +00009906#ifdef TARGET_NR_arch_prctl
9907 case TARGET_NR_arch_prctl:
9908#if defined(TARGET_I386) && !defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009909 return do_arch_prctl(cpu_env, arg1, arg2);
bellardd2fd1af2007-11-14 18:08:56 +00009910#else
Richard Henderson1a7b2b12018-08-18 12:01:08 -07009911#error unreachable
bellardd2fd1af2007-11-14 18:08:56 +00009912#endif
9913#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009914#ifdef TARGET_NR_pread64
9915 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +01009916 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +00009917 arg4 = arg5;
9918 arg5 = arg6;
9919 }
Peter Maydell2bd3f892019-01-08 18:49:00 +00009920 if (arg2 == 0 && arg3 == 0) {
9921 /* Special-case NULL buffer and zero length, which should succeed */
9922 p = 0;
9923 } else {
9924 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9925 if (!p) {
9926 return -TARGET_EFAULT;
9927 }
9928 }
aurel32f2c7ba12008-03-28 22:32:06 +00009929 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9930 unlock_user(p, arg2, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009931 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +00009932 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +01009933 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +00009934 arg4 = arg5;
9935 arg5 = arg6;
9936 }
Peter Maydell2bd3f892019-01-08 18:49:00 +00009937 if (arg2 == 0 && arg3 == 0) {
9938 /* Special-case NULL buffer and zero length, which should succeed */
9939 p = 0;
9940 } else {
9941 p = lock_user(VERIFY_READ, arg2, arg3, 1);
9942 if (!p) {
9943 return -TARGET_EFAULT;
9944 }
9945 }
aurel32f2c7ba12008-03-28 22:32:06 +00009946 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9947 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009948 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +00009949#endif
bellard31e31b82003-02-18 22:55:36 +00009950 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009951 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009952 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009953 ret = get_errno(sys_getcwd1(p, arg2));
9954 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009955 return ret;
bellard31e31b82003-02-18 22:55:36 +00009956 case TARGET_NR_capget:
9957 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009958 {
9959 struct target_user_cap_header *target_header;
9960 struct target_user_cap_data *target_data = NULL;
9961 struct __user_cap_header_struct header;
9962 struct __user_cap_data_struct data[2];
9963 struct __user_cap_data_struct *dataptr = NULL;
9964 int i, target_datalen;
9965 int data_items = 1;
9966
9967 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009968 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +00009969 }
9970 header.version = tswap32(target_header->version);
9971 header.pid = tswap32(target_header->pid);
9972
Peter Maydellec864872014-03-19 16:07:30 +00009973 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009974 /* Version 2 and up takes pointer to two user_data structs */
9975 data_items = 2;
9976 }
9977
9978 target_datalen = sizeof(*target_data) * data_items;
9979
9980 if (arg2) {
9981 if (num == TARGET_NR_capget) {
9982 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9983 } else {
9984 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9985 }
9986 if (!target_data) {
9987 unlock_user_struct(target_header, arg1, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07009988 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +00009989 }
9990
9991 if (num == TARGET_NR_capset) {
9992 for (i = 0; i < data_items; i++) {
9993 data[i].effective = tswap32(target_data[i].effective);
9994 data[i].permitted = tswap32(target_data[i].permitted);
9995 data[i].inheritable = tswap32(target_data[i].inheritable);
9996 }
9997 }
9998
9999 dataptr = data;
10000 }
10001
10002 if (num == TARGET_NR_capget) {
10003 ret = get_errno(capget(&header, dataptr));
10004 } else {
10005 ret = get_errno(capset(&header, dataptr));
10006 }
10007
10008 /* The kernel always updates version for both capget and capset */
10009 target_header->version = tswap32(header.version);
10010 unlock_user_struct(target_header, arg1, 1);
10011
10012 if (arg2) {
10013 if (num == TARGET_NR_capget) {
10014 for (i = 0; i < data_items; i++) {
10015 target_data[i].effective = tswap32(data[i].effective);
10016 target_data[i].permitted = tswap32(data[i].permitted);
10017 target_data[i].inheritable = tswap32(data[i].inheritable);
10018 }
10019 unlock_user(target_data, arg2, target_datalen);
10020 } else {
10021 unlock_user(target_data, arg2, 0);
10022 }
10023 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010024 return ret;
Peter Maydelle0eb2102014-03-17 12:15:35 +000010025 }
bellard31e31b82003-02-18 22:55:36 +000010026 case TARGET_NR_sigaltstack:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010027 return do_sigaltstack(arg1, arg2,
10028 get_sp_from_cpustate((CPUArchState *)cpu_env));
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010029
10030#ifdef CONFIG_SENDFILE
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010031#ifdef TARGET_NR_sendfile
bellard31e31b82003-02-18 22:55:36 +000010032 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010033 {
10034 off_t *offp = NULL;
10035 off_t off;
10036 if (arg3) {
10037 ret = get_user_sal(off, arg3);
10038 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010039 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010040 }
10041 offp = &off;
10042 }
10043 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10044 if (!is_error(ret) && arg3) {
10045 abi_long ret2 = put_user_sal(off, arg3);
10046 if (is_error(ret2)) {
10047 ret = ret2;
10048 }
10049 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010050 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010051 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010052#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010053#ifdef TARGET_NR_sendfile64
10054 case TARGET_NR_sendfile64:
10055 {
10056 off_t *offp = NULL;
10057 off_t off;
10058 if (arg3) {
10059 ret = get_user_s64(off, arg3);
10060 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010061 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010062 }
10063 offp = &off;
10064 }
10065 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10066 if (!is_error(ret) && arg3) {
10067 abi_long ret2 = put_user_s64(off, arg3);
10068 if (is_error(ret2)) {
10069 ret = ret2;
10070 }
10071 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010072 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010073 }
10074#endif
bellardebc05482003-09-30 21:08:41 +000010075#endif
bellard048f6b42005-11-26 18:47:20 +000010076#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010077 case TARGET_NR_vfork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010078 return get_errno(do_fork(cpu_env,
10079 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
10080 0, 0, 0, 0));
bellard048f6b42005-11-26 18:47:20 +000010081#endif
bellardebc05482003-09-30 21:08:41 +000010082#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010083 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010084 {
10085 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010086 int resource = target_to_host_resource(arg1);
10087 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010088 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010089 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010090 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010091 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010092 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10093 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010094 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010095 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010096 return ret;
bellard728584b2003-04-29 20:43:36 +000010097 }
bellardebc05482003-09-30 21:08:41 +000010098#endif
bellarda315a142005-01-30 22:59:18 +000010099#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010100 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010101 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010102 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010103 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10104 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010105 return ret;
bellarda315a142005-01-30 22:59:18 +000010106#endif
10107#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010108 case TARGET_NR_ftruncate64:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010109 return target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellarda315a142005-01-30 22:59:18 +000010110#endif
10111#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010112 case TARGET_NR_stat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010113 if (!(p = lock_user_string(arg1))) {
10114 return -TARGET_EFAULT;
10115 }
pbrook53a59602006-03-25 19:31:22 +000010116 ret = get_errno(stat(path(p), &st));
10117 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010118 if (!is_error(ret))
10119 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010120 return ret;
bellarda315a142005-01-30 22:59:18 +000010121#endif
10122#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010123 case TARGET_NR_lstat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010124 if (!(p = lock_user_string(arg1))) {
10125 return -TARGET_EFAULT;
10126 }
pbrook53a59602006-03-25 19:31:22 +000010127 ret = get_errno(lstat(path(p), &st));
10128 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010129 if (!is_error(ret))
10130 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010131 return ret;
bellarda315a142005-01-30 22:59:18 +000010132#endif
10133#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010134 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010135 ret = get_errno(fstat(arg1, &st));
10136 if (!is_error(ret))
10137 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010138 return ret;
bellardec86b0f2003-04-11 00:15:04 +000010139#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010140#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010141#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010142 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010143#endif
10144#ifdef TARGET_NR_newfstatat
10145 case TARGET_NR_newfstatat:
10146#endif
Richard Henderson2852aaf2018-08-18 12:01:06 -070010147 if (!(p = lock_user_string(arg2))) {
10148 return -TARGET_EFAULT;
10149 }
Peter Maydellc0d472b2013-06-12 16:20:21 +010010150 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
Richard Henderson2852aaf2018-08-18 12:01:06 -070010151 unlock_user(p, arg2, 0);
balrog6a24a772008-09-20 02:23:36 +000010152 if (!is_error(ret))
10153 ret = host_to_target_stat64(cpu_env, arg3, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010154 return ret;
bellarda315a142005-01-30 22:59:18 +000010155#endif
Chen Gang704eff62015-08-21 05:37:33 +080010156#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010157 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010158 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010159 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010160 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10161 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010162 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010163#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010164#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010165 case TARGET_NR_getuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010166 return get_errno(high2lowuid(getuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030010167#endif
10168#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010169 case TARGET_NR_getgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010170 return get_errno(high2lowgid(getgid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030010171#endif
10172#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010173 case TARGET_NR_geteuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010174 return get_errno(high2lowuid(geteuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030010175#endif
10176#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010177 case TARGET_NR_getegid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010178 return get_errno(high2lowgid(getegid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030010179#endif
bellard67867302003-11-23 17:05:30 +000010180 case TARGET_NR_setreuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010181 return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
bellard67867302003-11-23 17:05:30 +000010182 case TARGET_NR_setregid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010183 return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
bellard67867302003-11-23 17:05:30 +000010184 case TARGET_NR_getgroups:
10185 {
10186 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010187 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010188 gid_t *grouplist;
10189 int i;
10190
10191 grouplist = alloca(gidsetsize * sizeof(gid_t));
10192 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010193 if (gidsetsize == 0)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010194 return ret;
bellard67867302003-11-23 17:05:30 +000010195 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010196 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010197 if (!target_grouplist)
Richard Henderson2852aaf2018-08-18 12:01:06 -070010198 return -TARGET_EFAULT;
balroga2155fc2008-09-20 02:12:08 +000010199 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010200 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010201 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010202 }
10203 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010204 return ret;
bellard67867302003-11-23 17:05:30 +000010205 case TARGET_NR_setgroups:
10206 {
10207 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010208 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010209 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010210 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010211 if (gidsetsize) {
10212 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010213 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010214 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070010215 return -TARGET_EFAULT;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010216 }
10217 for (i = 0; i < gidsetsize; i++) {
10218 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10219 }
10220 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010221 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010222 return get_errno(setgroups(gidsetsize, grouplist));
bellard67867302003-11-23 17:05:30 +000010223 }
bellard67867302003-11-23 17:05:30 +000010224 case TARGET_NR_fchown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010225 return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
Peter Maydellc0d472b2013-06-12 16:20:21 +010010226#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010227 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010228 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010229 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010230 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10231 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010232 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010233 return ret;
thsccfa72b2007-09-24 09:23:34 +000010234#endif
bellard67867302003-11-23 17:05:30 +000010235#ifdef TARGET_NR_setresuid
10236 case TARGET_NR_setresuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010237 return get_errno(sys_setresuid(low2highuid(arg1),
10238 low2highuid(arg2),
10239 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010240#endif
10241#ifdef TARGET_NR_getresuid
10242 case TARGET_NR_getresuid:
10243 {
pbrook53a59602006-03-25 19:31:22 +000010244 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010245 ret = get_errno(getresuid(&ruid, &euid, &suid));
10246 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010247 if (put_user_id(high2lowuid(ruid), arg1)
10248 || put_user_id(high2lowuid(euid), arg2)
10249 || put_user_id(high2lowuid(suid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010250 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000010251 }
10252 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010253 return ret;
bellard67867302003-11-23 17:05:30 +000010254#endif
10255#ifdef TARGET_NR_getresgid
10256 case TARGET_NR_setresgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010257 return get_errno(sys_setresgid(low2highgid(arg1),
10258 low2highgid(arg2),
10259 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010260#endif
10261#ifdef TARGET_NR_getresgid
10262 case TARGET_NR_getresgid:
10263 {
pbrook53a59602006-03-25 19:31:22 +000010264 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010265 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10266 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010267 if (put_user_id(high2lowgid(rgid), arg1)
10268 || put_user_id(high2lowgid(egid), arg2)
10269 || put_user_id(high2lowgid(sgid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010270 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000010271 }
10272 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010273 return ret;
bellard67867302003-11-23 17:05:30 +000010274#endif
Chen Gang704eff62015-08-21 05:37:33 +080010275#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000010276 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000010277 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010278 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010279 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
10280 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010281 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010282#endif
bellard67867302003-11-23 17:05:30 +000010283 case TARGET_NR_setuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010284 return get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000010285 case TARGET_NR_setgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010286 return get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000010287 case TARGET_NR_setfsuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010288 return get_errno(setfsuid(arg1));
bellard67867302003-11-23 17:05:30 +000010289 case TARGET_NR_setfsgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010290 return get_errno(setfsgid(arg1));
bellard67867302003-11-23 17:05:30 +000010291
bellarda315a142005-01-30 22:59:18 +000010292#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000010293 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000010294 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010295 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010296 ret = get_errno(lchown(p, arg2, arg3));
10297 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010298 return ret;
bellarda315a142005-01-30 22:59:18 +000010299#endif
10300#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000010301 case TARGET_NR_getuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010302 return get_errno(getuid());
bellarda315a142005-01-30 22:59:18 +000010303#endif
aurel3264b4d282008-11-14 17:20:15 +000010304
10305#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
10306 /* Alpha specific */
10307 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010308 {
10309 uid_t euid;
10310 euid=geteuid();
10311 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
10312 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010313 return get_errno(getuid());
aurel3264b4d282008-11-14 17:20:15 +000010314#endif
10315#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
10316 /* Alpha specific */
10317 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010318 {
10319 uid_t egid;
10320 egid=getegid();
10321 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
10322 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010323 return get_errno(getgid());
aurel3264b4d282008-11-14 17:20:15 +000010324#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080010325#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
10326 /* Alpha specific */
10327 case TARGET_NR_osf_getsysinfo:
10328 ret = -TARGET_EOPNOTSUPP;
10329 switch (arg1) {
10330 case TARGET_GSI_IEEE_FP_CONTROL:
10331 {
Richard Henderson21ba8562019-04-26 15:20:51 -070010332 uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env);
10333 uint64_t swcr = ((CPUAlphaState *)cpu_env)->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010334
Richard Henderson21ba8562019-04-26 15:20:51 -070010335 swcr &= ~SWCR_STATUS_MASK;
10336 swcr |= (fpcr >> 35) & SWCR_STATUS_MASK;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010337
10338 if (put_user_u64 (swcr, arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010339 return -TARGET_EFAULT;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010340 ret = 0;
10341 }
10342 break;
10343
10344 /* case GSI_IEEE_STATE_AT_SIGNAL:
10345 -- Not implemented in linux kernel.
10346 case GSI_UACPROC:
10347 -- Retrieves current unaligned access state; not much used.
10348 case GSI_PROC_TYPE:
10349 -- Retrieves implver information; surely not used.
10350 case GSI_GET_HWRPB:
10351 -- Grabs a copy of the HWRPB; surely not used.
10352 */
10353 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010354 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010355#endif
10356#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
10357 /* Alpha specific */
10358 case TARGET_NR_osf_setsysinfo:
10359 ret = -TARGET_EOPNOTSUPP;
10360 switch (arg1) {
10361 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010362 {
Richard Henderson21ba8562019-04-26 15:20:51 -070010363 uint64_t swcr, fpcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010364
Richard Henderson6e06d512012-06-01 09:08:21 -070010365 if (get_user_u64 (swcr, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010366 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070010367 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010368
Richard Henderson21ba8562019-04-26 15:20:51 -070010369 /*
10370 * The kernel calls swcr_update_status to update the
10371 * status bits from the fpcr at every point that it
10372 * could be queried. Therefore, we store the status
10373 * bits only in FPCR.
10374 */
10375 ((CPUAlphaState *)cpu_env)->swcr
10376 = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010377
Richard Henderson21ba8562019-04-26 15:20:51 -070010378 fpcr = cpu_alpha_load_fpcr(cpu_env);
10379 fpcr &= ((uint64_t)FPCR_DYN_MASK << 32);
10380 fpcr |= alpha_ieee_swcr_to_fpcr(swcr);
Richard Henderson6e06d512012-06-01 09:08:21 -070010381 cpu_alpha_store_fpcr(cpu_env, fpcr);
10382 ret = 0;
10383 }
10384 break;
10385
10386 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
10387 {
Richard Henderson21ba8562019-04-26 15:20:51 -070010388 uint64_t exc, fpcr, fex;
Richard Henderson6e06d512012-06-01 09:08:21 -070010389
10390 if (get_user_u64(exc, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010391 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070010392 }
Richard Henderson21ba8562019-04-26 15:20:51 -070010393 exc &= SWCR_STATUS_MASK;
10394 fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010395
Richard Henderson6e06d512012-06-01 09:08:21 -070010396 /* Old exceptions are not signaled. */
Richard Henderson21ba8562019-04-26 15:20:51 -070010397 fex = alpha_ieee_fpcr_to_swcr(fpcr);
10398 fex = exc & ~fex;
10399 fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT;
10400 fex &= ((CPUArchState *)cpu_env)->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010401
Richard Henderson21ba8562019-04-26 15:20:51 -070010402 /* Update the hardware fpcr. */
10403 fpcr |= alpha_ieee_swcr_to_fpcr(exc);
10404 cpu_alpha_store_fpcr(cpu_env, fpcr);
10405
10406 if (fex) {
10407 int si_code = TARGET_FPE_FLTUNK;
Richard Henderson6e06d512012-06-01 09:08:21 -070010408 target_siginfo_t info;
Richard Henderson21ba8562019-04-26 15:20:51 -070010409
10410 if (fex & SWCR_TRAP_ENABLE_DNO) {
10411 si_code = TARGET_FPE_FLTUND;
10412 }
10413 if (fex & SWCR_TRAP_ENABLE_INE) {
10414 si_code = TARGET_FPE_FLTRES;
10415 }
10416 if (fex & SWCR_TRAP_ENABLE_UNF) {
10417 si_code = TARGET_FPE_FLTUND;
10418 }
10419 if (fex & SWCR_TRAP_ENABLE_OVF) {
10420 si_code = TARGET_FPE_FLTOVF;
10421 }
10422 if (fex & SWCR_TRAP_ENABLE_DZE) {
10423 si_code = TARGET_FPE_FLTDIV;
10424 }
10425 if (fex & SWCR_TRAP_ENABLE_INV) {
10426 si_code = TARGET_FPE_FLTINV;
10427 }
10428
Richard Henderson6e06d512012-06-01 09:08:21 -070010429 info.si_signo = SIGFPE;
10430 info.si_errno = 0;
10431 info.si_code = si_code;
10432 info._sifields._sigfault._addr
10433 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010010434 queue_signal((CPUArchState *)cpu_env, info.si_signo,
10435 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010436 }
Richard Henderson21ba8562019-04-26 15:20:51 -070010437 ret = 0;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010438 }
10439 break;
10440
10441 /* case SSI_NVPAIRS:
10442 -- Used with SSIN_UACPROC to enable unaligned accesses.
10443 case SSI_IEEE_STATE_AT_SIGNAL:
10444 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
10445 -- Not implemented in linux kernel
10446 */
10447 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010448 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010449#endif
10450#ifdef TARGET_NR_osf_sigprocmask
10451 /* Alpha specific. */
10452 case TARGET_NR_osf_sigprocmask:
10453 {
10454 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010455 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010456 sigset_t set, oldset;
10457
10458 switch(arg1) {
10459 case TARGET_SIG_BLOCK:
10460 how = SIG_BLOCK;
10461 break;
10462 case TARGET_SIG_UNBLOCK:
10463 how = SIG_UNBLOCK;
10464 break;
10465 case TARGET_SIG_SETMASK:
10466 how = SIG_SETMASK;
10467 break;
10468 default:
Richard Henderson259841c2018-08-18 12:01:09 -070010469 return -TARGET_EINVAL;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010470 }
10471 mask = arg2;
10472 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010473 ret = do_sigprocmask(how, &set, &oldset);
10474 if (!ret) {
10475 host_to_target_old_sigset(&mask, &oldset);
10476 ret = mask;
10477 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010478 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010479 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010480#endif
aurel3264b4d282008-11-14 17:20:15 +000010481
bellarda315a142005-01-30 22:59:18 +000010482#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010483 case TARGET_NR_getgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010484 return get_errno(getgid());
bellarda315a142005-01-30 22:59:18 +000010485#endif
10486#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010487 case TARGET_NR_geteuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010488 return get_errno(geteuid());
bellarda315a142005-01-30 22:59:18 +000010489#endif
10490#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010491 case TARGET_NR_getegid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010492 return get_errno(getegid());
bellarda315a142005-01-30 22:59:18 +000010493#endif
10494#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010495 case TARGET_NR_setreuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010496 return get_errno(setreuid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000010497#endif
10498#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010499 case TARGET_NR_setregid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010500 return get_errno(setregid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000010501#endif
10502#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010503 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010504 {
10505 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010506 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010507 gid_t *grouplist;
10508 int i;
10509
10510 grouplist = alloca(gidsetsize * sizeof(gid_t));
10511 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010512 if (gidsetsize == 0)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010513 return ret;
bellard99c475a2005-01-31 20:45:13 +000010514 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010515 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10516 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070010517 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010518 }
balroga2155fc2008-09-20 02:12:08 +000010519 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010520 target_grouplist[i] = tswap32(grouplist[i]);
10521 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010522 }
10523 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010524 return ret;
bellarda315a142005-01-30 22:59:18 +000010525#endif
10526#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010527 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010528 {
10529 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010530 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010531 gid_t *grouplist;
10532 int i;
ths3b46e622007-09-17 08:09:54 +000010533
bellard99c475a2005-01-31 20:45:13 +000010534 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010535 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10536 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070010537 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010538 }
bellard99c475a2005-01-31 20:45:13 +000010539 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010540 grouplist[i] = tswap32(target_grouplist[i]);
10541 unlock_user(target_grouplist, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010542 return get_errno(setgroups(gidsetsize, grouplist));
bellard99c475a2005-01-31 20:45:13 +000010543 }
bellarda315a142005-01-30 22:59:18 +000010544#endif
10545#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010546 case TARGET_NR_fchown32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010547 return get_errno(fchown(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000010548#endif
10549#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010550 case TARGET_NR_setresuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010551 return get_errno(sys_setresuid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000010552#endif
10553#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010554 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010555 {
pbrook53a59602006-03-25 19:31:22 +000010556 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000010557 ret = get_errno(getresuid(&ruid, &euid, &suid));
10558 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010559 if (put_user_u32(ruid, arg1)
10560 || put_user_u32(euid, arg2)
10561 || put_user_u32(suid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010562 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000010563 }
10564 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010565 return ret;
bellarda315a142005-01-30 22:59:18 +000010566#endif
10567#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000010568 case TARGET_NR_setresgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010569 return get_errno(sys_setresgid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000010570#endif
10571#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000010572 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000010573 {
pbrook53a59602006-03-25 19:31:22 +000010574 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000010575 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10576 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000010577 if (put_user_u32(rgid, arg1)
10578 || put_user_u32(egid, arg2)
10579 || put_user_u32(sgid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010580 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000010581 }
10582 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010583 return ret;
bellarda315a142005-01-30 22:59:18 +000010584#endif
10585#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000010586 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000010587 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010588 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010589 ret = get_errno(chown(p, arg2, arg3));
10590 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010591 return ret;
bellarda315a142005-01-30 22:59:18 +000010592#endif
10593#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000010594 case TARGET_NR_setuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010595 return get_errno(sys_setuid(arg1));
bellarda315a142005-01-30 22:59:18 +000010596#endif
10597#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000010598 case TARGET_NR_setgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010599 return get_errno(sys_setgid(arg1));
bellarda315a142005-01-30 22:59:18 +000010600#endif
10601#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000010602 case TARGET_NR_setfsuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010603 return get_errno(setfsuid(arg1));
bellarda315a142005-01-30 22:59:18 +000010604#endif
10605#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010606 case TARGET_NR_setfsgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010607 return get_errno(setfsgid(arg1));
bellarda315a142005-01-30 22:59:18 +000010608#endif
bellardffa65c32004-01-04 23:57:22 +000010609#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010610 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010611 {
Richard Henderson259841c2018-08-18 12:01:09 -070010612 void *a = lock_user(VERIFY_READ, arg1, arg2, 0);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000010613 if (!a) {
Richard Henderson259841c2018-08-18 12:01:09 -070010614 return -TARGET_ENOMEM;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000010615 }
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000010616 p = lock_user_string(arg3);
10617 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -070010618 ret = -TARGET_EFAULT;
10619 } else {
10620 ret = get_errno(mincore(a, arg2, p));
10621 unlock_user(p, arg3, ret);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000010622 }
aurel3204bb9ac2008-10-01 21:46:41 +000010623 unlock_user(a, arg1, 0);
10624 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010625 return ret;
bellardffa65c32004-01-04 23:57:22 +000010626#endif
aurel32408321b2008-10-01 21:46:32 +000010627#ifdef TARGET_NR_arm_fadvise64_64
10628 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010629 /* arm_fadvise64_64 looks like fadvise64_64 but
10630 * with different argument order: fd, advice, offset, len
10631 * rather than the usual fd, offset, len, advice.
10632 * Note that offset and len are both 64-bit so appear as
10633 * pairs of 32-bit registers.
10634 */
10635 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10636 target_offset64(arg5, arg6), arg2);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010637 return -host_to_target_errno(ret);
aurel32408321b2008-10-01 21:46:32 +000010638#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010639
10640#if TARGET_ABI_BITS == 32
10641
10642#ifdef TARGET_NR_fadvise64_64
10643 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070010644#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010010645 /* 6 args: fd, advice, offset (high, low), len (high, low) */
10646 ret = arg2;
10647 arg2 = arg3;
10648 arg3 = arg4;
10649 arg4 = arg5;
10650 arg5 = arg6;
10651 arg6 = ret;
10652#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010653 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010010654 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010655 /* offset is in (3,4), len in (5,6) and advice in 7 */
10656 arg2 = arg3;
10657 arg3 = arg4;
10658 arg4 = arg5;
10659 arg5 = arg6;
10660 arg6 = arg7;
10661 }
Laurent Vivier43046b52017-03-02 01:11:45 +010010662#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010663 ret = posix_fadvise(arg1, target_offset64(arg2, arg3),
10664 target_offset64(arg4, arg5), arg6);
10665 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010666#endif
10667
10668#ifdef TARGET_NR_fadvise64
10669 case TARGET_NR_fadvise64:
10670 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010010671 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010672 /* offset is in (3,4), len in 5 and advice in 6 */
10673 arg2 = arg3;
10674 arg3 = arg4;
10675 arg4 = arg5;
10676 arg5 = arg6;
10677 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010678 ret = posix_fadvise(arg1, target_offset64(arg2, arg3), arg4, arg5);
10679 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010680#endif
10681
10682#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010683#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010684#ifdef TARGET_NR_fadvise64_64
10685 case TARGET_NR_fadvise64_64:
10686#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010687#ifdef TARGET_NR_fadvise64
10688 case TARGET_NR_fadvise64:
10689#endif
10690#ifdef TARGET_S390X
10691 switch (arg4) {
10692 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10693 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10694 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10695 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10696 default: break;
10697 }
10698#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010699 return -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
aurel32408321b2008-10-01 21:46:32 +000010700#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010701#endif /* end of 64-bit ABI fadvise handling */
10702
bellardffa65c32004-01-04 23:57:22 +000010703#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010704 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010705 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010706 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010707 This will break MADV_DONTNEED.
10708 This is a hint, so ignoring and returning success is ok. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010709 return 0;
bellardffa65c32004-01-04 23:57:22 +000010710#endif
blueswir1992f48a2007-10-14 16:27:31 +000010711#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010712 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010713 {
thsb1e341e2007-03-20 21:50:52 +000010714 int cmd;
bellard77e46722003-04-29 20:39:06 +000010715 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010010716 from_flock64_fn *copyfrom = copy_from_user_flock64;
10717 to_flock64_fn *copyto = copy_to_user_flock64;
10718
pbrookce4defa2006-02-09 16:49:55 +000010719#ifdef TARGET_ARM
Laurent Vivier7f254c52018-05-02 23:57:30 +020010720 if (!((CPUARMState *)cpu_env)->eabi) {
10721 copyfrom = copy_from_user_oabi_flock64;
10722 copyto = copy_to_user_oabi_flock64;
Peter Maydell213d3e92016-06-13 11:22:05 +010010723 }
pbrookce4defa2006-02-09 16:49:55 +000010724#endif
bellard77e46722003-04-29 20:39:06 +000010725
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010726 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010727 if (cmd == -TARGET_EINVAL) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010728 return cmd;
Peter Maydell31b63192011-12-05 23:11:50 +000010729 }
thsb1e341e2007-03-20 21:50:52 +000010730
bellard60cd49d2003-03-16 22:53:56 +000010731 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010732 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010733 ret = copyfrom(&fl, arg3);
10734 if (ret) {
10735 break;
ths58134272007-03-31 18:59:32 +000010736 }
Laurent Vivieraf8ab2b2018-07-13 14:58:05 +020010737 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010010738 if (ret == 0) {
10739 ret = copyto(arg3, &fl);
10740 }
bellard77e46722003-04-29 20:39:06 +000010741 break;
10742
thsb1e341e2007-03-20 21:50:52 +000010743 case TARGET_F_SETLK64:
10744 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010010745 ret = copyfrom(&fl, arg3);
10746 if (ret) {
10747 break;
pbrookce4defa2006-02-09 16:49:55 +000010748 }
Peter Maydell435da5e2016-06-13 11:22:05 +010010749 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010750 break;
bellard60cd49d2003-03-16 22:53:56 +000010751 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010752 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010753 break;
10754 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010755 return ret;
bellard77e46722003-04-29 20:39:06 +000010756 }
bellard60cd49d2003-03-16 22:53:56 +000010757#endif
ths7d600c82006-12-08 01:32:58 +000010758#ifdef TARGET_NR_cacheflush
10759 case TARGET_NR_cacheflush:
10760 /* self-modifying code is handled automatically, so nothing needed */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010761 return 0;
ths7d600c82006-12-08 01:32:58 +000010762#endif
bellardc573ff62004-01-04 15:51:36 +000010763#ifdef TARGET_NR_getpagesize
10764 case TARGET_NR_getpagesize:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010765 return TARGET_PAGE_SIZE;
bellardc573ff62004-01-04 15:51:36 +000010766#endif
bellard31e31b82003-02-18 22:55:36 +000010767 case TARGET_NR_gettid:
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +000010768 return get_errno(sys_gettid());
thse5febef2007-04-01 18:31:35 +000010769#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010770 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010771#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010010772 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000010773 arg2 = arg3;
10774 arg3 = arg4;
10775 arg4 = arg5;
10776 }
Lena Djokic77c68502016-11-24 17:08:56 +010010777 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000010778#else
10779 ret = get_errno(readahead(arg1, arg2, arg3));
10780#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010781 return ret;
thse5febef2007-04-01 18:31:35 +000010782#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010783#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010784#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010785 case TARGET_NR_listxattr:
10786 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010787 {
10788 void *p, *b = 0;
10789 if (arg2) {
10790 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10791 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010792 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010793 }
10794 }
10795 p = lock_user_string(arg1);
10796 if (p) {
10797 if (num == TARGET_NR_listxattr) {
10798 ret = get_errno(listxattr(p, b, arg3));
10799 } else {
10800 ret = get_errno(llistxattr(p, b, arg3));
10801 }
10802 } else {
10803 ret = -TARGET_EFAULT;
10804 }
10805 unlock_user(p, arg1, 0);
10806 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010807 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010808 }
10809 case TARGET_NR_flistxattr:
10810 {
10811 void *b = 0;
10812 if (arg2) {
10813 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10814 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010815 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010816 }
10817 }
10818 ret = get_errno(flistxattr(arg1, b, arg3));
10819 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010820 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010821 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010822 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010823 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010824 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010825 void *p, *n, *v = 0;
10826 if (arg3) {
10827 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10828 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010829 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010830 }
10831 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010832 p = lock_user_string(arg1);
10833 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010834 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010835 if (num == TARGET_NR_setxattr) {
10836 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10837 } else {
10838 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10839 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010840 } else {
10841 ret = -TARGET_EFAULT;
10842 }
10843 unlock_user(p, arg1, 0);
10844 unlock_user(n, arg2, 0);
10845 unlock_user(v, arg3, 0);
10846 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010847 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000010848 case TARGET_NR_fsetxattr:
10849 {
10850 void *n, *v = 0;
10851 if (arg3) {
10852 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10853 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010854 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000010855 }
10856 }
10857 n = lock_user_string(arg2);
10858 if (n) {
10859 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10860 } else {
10861 ret = -TARGET_EFAULT;
10862 }
10863 unlock_user(n, arg2, 0);
10864 unlock_user(v, arg3, 0);
10865 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010866 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010867 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010868 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010869 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010870 void *p, *n, *v = 0;
10871 if (arg3) {
10872 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10873 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010874 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010875 }
10876 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010877 p = lock_user_string(arg1);
10878 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010879 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010880 if (num == TARGET_NR_getxattr) {
10881 ret = get_errno(getxattr(p, n, v, arg4));
10882 } else {
10883 ret = get_errno(lgetxattr(p, n, v, arg4));
10884 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010885 } else {
10886 ret = -TARGET_EFAULT;
10887 }
10888 unlock_user(p, arg1, 0);
10889 unlock_user(n, arg2, 0);
10890 unlock_user(v, arg3, arg4);
10891 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010892 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000010893 case TARGET_NR_fgetxattr:
10894 {
10895 void *n, *v = 0;
10896 if (arg3) {
10897 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10898 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010899 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000010900 }
10901 }
10902 n = lock_user_string(arg2);
10903 if (n) {
10904 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10905 } else {
10906 ret = -TARGET_EFAULT;
10907 }
10908 unlock_user(n, arg2, 0);
10909 unlock_user(v, arg3, arg4);
10910 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010911 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010912 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010913 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010914 {
10915 void *p, *n;
10916 p = lock_user_string(arg1);
10917 n = lock_user_string(arg2);
10918 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010919 if (num == TARGET_NR_removexattr) {
10920 ret = get_errno(removexattr(p, n));
10921 } else {
10922 ret = get_errno(lremovexattr(p, n));
10923 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010924 } else {
10925 ret = -TARGET_EFAULT;
10926 }
10927 unlock_user(p, arg1, 0);
10928 unlock_user(n, arg2, 0);
10929 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010930 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000010931 case TARGET_NR_fremovexattr:
10932 {
10933 void *n;
10934 n = lock_user_string(arg2);
10935 if (n) {
10936 ret = get_errno(fremovexattr(arg1, n));
10937 } else {
10938 ret = -TARGET_EFAULT;
10939 }
10940 unlock_user(n, arg2, 0);
10941 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010942 return ret;
bellardebc05482003-09-30 21:08:41 +000010943#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010944#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010945#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010946 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010947#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010948 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010949 return 0;
edgar_iglef967792009-01-07 14:19:38 +000010950#elif defined(TARGET_CRIS)
10951 if (arg1 & 0xff)
10952 ret = -TARGET_EINVAL;
10953 else {
10954 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10955 ret = 0;
10956 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010957 return ret;
bellard8d18e892007-11-14 15:18:40 +000010958#elif defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010959 return do_set_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010010960#elif defined(TARGET_M68K)
10961 {
Andreas Färber0429a972013-08-26 18:14:44 +020010962 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010963 ts->tp_value = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010964 return 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010965 }
ths6f5b89a2007-03-02 20:48:00 +000010966#else
Richard Henderson10f45d92018-08-18 12:01:07 -070010967 return -TARGET_ENOSYS;
ths6f5b89a2007-03-02 20:48:00 +000010968#endif
10969#endif
10970#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010971 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010972#if defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010973 return do_get_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010010974#elif defined(TARGET_M68K)
10975 {
Andreas Färber0429a972013-08-26 18:14:44 +020010976 TaskState *ts = cpu->opaque;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010977 return ts->tp_value;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010978 }
bellard8d18e892007-11-14 15:18:40 +000010979#else
Richard Henderson10f45d92018-08-18 12:01:07 -070010980 return -TARGET_ENOSYS;
bellardebc05482003-09-30 21:08:41 +000010981#endif
bellard8d18e892007-11-14 15:18:40 +000010982#endif
bellard48dc41e2006-06-21 18:15:50 +000010983#ifdef TARGET_NR_getdomainname
10984 case TARGET_NR_getdomainname:
Richard Henderson10f45d92018-08-18 12:01:07 -070010985 return -TARGET_ENOSYS;
bellard48dc41e2006-06-21 18:15:50 +000010986#endif
ths6f5b89a2007-03-02 20:48:00 +000010987
Max Filippov12e33402018-04-01 13:13:49 -070010988#ifdef TARGET_NR_clock_settime
10989 case TARGET_NR_clock_settime:
10990 {
10991 struct timespec ts;
10992
10993 ret = target_to_host_timespec(&ts, arg2);
10994 if (!is_error(ret)) {
10995 ret = get_errno(clock_settime(arg1, &ts));
10996 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010997 return ret;
Max Filippov12e33402018-04-01 13:13:49 -070010998 }
10999#endif
thsb5906f92007-03-19 13:32:45 +000011000#ifdef TARGET_NR_clock_gettime
11001 case TARGET_NR_clock_gettime:
11002 {
11003 struct timespec ts;
11004 ret = get_errno(clock_gettime(arg1, &ts));
11005 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070011006 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000011007 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011008 return ret;
thsb5906f92007-03-19 13:32:45 +000011009 }
11010#endif
11011#ifdef TARGET_NR_clock_getres
11012 case TARGET_NR_clock_getres:
11013 {
11014 struct timespec ts;
11015 ret = get_errno(clock_getres(arg1, &ts));
11016 if (!is_error(ret)) {
11017 host_to_target_timespec(arg2, &ts);
11018 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011019 return ret;
thsb5906f92007-03-19 13:32:45 +000011020 }
11021#endif
pbrook63d76512008-05-29 13:43:29 +000011022#ifdef TARGET_NR_clock_nanosleep
11023 case TARGET_NR_clock_nanosleep:
11024 {
11025 struct timespec ts;
11026 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011027 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11028 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011029 if (arg4)
11030 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011031
11032#if defined(TARGET_PPC)
11033 /* clock_nanosleep is odd in that it returns positive errno values.
11034 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011035 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011036 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11037 }
11038#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011039 return ret;
pbrook63d76512008-05-29 13:43:29 +000011040 }
11041#endif
thsb5906f92007-03-19 13:32:45 +000011042
ths6f5b89a2007-03-02 20:48:00 +000011043#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11044 case TARGET_NR_set_tid_address:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011045 return get_errno(set_tid_address((int *)g2h(arg1)));
ths6f5b89a2007-03-02 20:48:00 +000011046#endif
11047
ths4cae1d12007-07-12 11:06:53 +000011048 case TARGET_NR_tkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011049 return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011050
ths71455572007-06-21 21:45:30 +000011051 case TARGET_NR_tgkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011052 return get_errno(safe_tgkill((int)arg1, (int)arg2,
11053 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +000011054
ths4f2b1fe2007-06-21 21:57:12 +000011055#ifdef TARGET_NR_set_robust_list
11056 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011057 case TARGET_NR_get_robust_list:
11058 /* The ABI for supporting robust futexes has userspace pass
11059 * the kernel a pointer to a linked list which is updated by
11060 * userspace after the syscall; the list is walked by the kernel
11061 * when the thread exits. Since the linked list in QEMU guest
11062 * memory isn't a valid linked list for the host and we have
11063 * no way to reliably intercept the thread-death event, we can't
11064 * support these. Silently return ENOSYS so that guest userspace
11065 * falls back to a non-robust futex implementation (which should
11066 * be OK except in the corner case of the guest crashing while
11067 * holding a mutex that is shared with another process via
11068 * shared memory).
11069 */
Richard Henderson10f45d92018-08-18 12:01:07 -070011070 return -TARGET_ENOSYS;
ths4f2b1fe2007-06-21 21:57:12 +000011071#endif
11072
Peter Maydell1acae9f2013-07-02 14:04:12 +010011073#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011074 case TARGET_NR_utimensat:
11075 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011076 struct timespec *tsp, ts[2];
11077 if (!arg3) {
11078 tsp = NULL;
11079 } else {
11080 target_to_host_timespec(ts, arg3);
11081 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11082 tsp = ts;
11083 }
ths9007f0e2007-09-25 17:50:37 +000011084 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011085 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011086 else {
bellard579a97f2007-11-11 14:26:47 +000011087 if (!(p = lock_user_string(arg2))) {
Richard Henderson259841c2018-08-18 12:01:09 -070011088 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011089 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011090 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011091 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011092 }
11093 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011094 return ret;
ths9007f0e2007-09-25 17:50:37 +000011095#endif
pbrookbd0c5662008-05-29 14:34:11 +000011096 case TARGET_NR_futex:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011097 return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
aurel32dbfe4c32009-04-08 21:29:30 +000011098#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011099 case TARGET_NR_inotify_init:
11100 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011101 if (ret >= 0) {
11102 fd_trans_register(ret, &target_inotify_trans);
11103 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011104 return ret;
aurel3239b59762008-10-01 21:46:50 +000011105#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011106#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011107#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11108 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010011109 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
11110 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011111 if (ret >= 0) {
11112 fd_trans_register(ret, &target_inotify_trans);
11113 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011114 return ret;
Riku Voipioc05c7a72010-03-26 15:25:11 +000011115#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011116#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011117#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011118 case TARGET_NR_inotify_add_watch:
11119 p = lock_user_string(arg2);
11120 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11121 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011122 return ret;
aurel3239b59762008-10-01 21:46:50 +000011123#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011124#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011125 case TARGET_NR_inotify_rm_watch:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011126 return get_errno(sys_inotify_rm_watch(arg1, arg2));
aurel3239b59762008-10-01 21:46:50 +000011127#endif
ths9007f0e2007-09-25 17:50:37 +000011128
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011129#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011130 case TARGET_NR_mq_open:
11131 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011132 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010011133 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011134 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000011135
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011136 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010011137 pposix_mq_attr = NULL;
11138 if (arg4) {
11139 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011140 return -TARGET_EFAULT;
Lena Djokic26400772016-11-24 17:08:58 +010011141 }
11142 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050011143 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011144 p = lock_user_string(arg1 - 1);
11145 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011146 return -TARGET_EFAULT;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011147 }
Lena Djokic26400772016-11-24 17:08:58 +010011148 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000011149 unlock_user (p, arg1, 0);
11150 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011151 return ret;
aurel3224e10032009-04-15 16:11:43 +000011152
11153 case TARGET_NR_mq_unlink:
11154 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010011155 if (!p) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011156 return -TARGET_EFAULT;
Peter Maydell32112152016-07-12 13:02:13 +010011157 }
aurel3224e10032009-04-15 16:11:43 +000011158 ret = get_errno(mq_unlink(p));
11159 unlock_user (p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011160 return ret;
aurel3224e10032009-04-15 16:11:43 +000011161
11162 case TARGET_NR_mq_timedsend:
11163 {
11164 struct timespec ts;
11165
11166 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11167 if (arg5 != 0) {
11168 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011169 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011170 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011171 } else {
11172 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011173 }
aurel3224e10032009-04-15 16:11:43 +000011174 unlock_user (p, arg2, arg3);
11175 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011176 return ret;
aurel3224e10032009-04-15 16:11:43 +000011177
11178 case TARGET_NR_mq_timedreceive:
11179 {
11180 struct timespec ts;
11181 unsigned int prio;
11182
11183 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11184 if (arg5 != 0) {
11185 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011186 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11187 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011188 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011189 } else {
11190 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11191 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011192 }
aurel3224e10032009-04-15 16:11:43 +000011193 unlock_user (p, arg2, arg3);
11194 if (arg4 != 0)
11195 put_user_u32(prio, arg4);
11196 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011197 return ret;
aurel3224e10032009-04-15 16:11:43 +000011198
11199 /* Not implemented for now... */
11200/* case TARGET_NR_mq_notify: */
11201/* break; */
11202
11203 case TARGET_NR_mq_getsetattr:
11204 {
11205 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11206 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000011207 if (arg2 != 0) {
11208 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070011209 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
11210 &posix_mq_attr_out));
11211 } else if (arg3 != 0) {
11212 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000011213 }
Max Filippova23ea402018-03-31 08:20:15 -070011214 if (ret == 0 && arg3 != 0) {
11215 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11216 }
aurel3224e10032009-04-15 16:11:43 +000011217 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011218 return ret;
aurel3224e10032009-04-15 16:11:43 +000011219#endif
11220
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011221#ifdef CONFIG_SPLICE
11222#ifdef TARGET_NR_tee
11223 case TARGET_NR_tee:
11224 {
11225 ret = get_errno(tee(arg1,arg2,arg3,arg4));
11226 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011227 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011228#endif
11229#ifdef TARGET_NR_splice
11230 case TARGET_NR_splice:
11231 {
11232 loff_t loff_in, loff_out;
11233 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010011234 if (arg2) {
11235 if (get_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011236 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010011237 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011238 ploff_in = &loff_in;
11239 }
Andreas Schwab17644b32015-03-10 17:11:35 +010011240 if (arg4) {
11241 if (get_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011242 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010011243 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011244 ploff_out = &loff_out;
11245 }
11246 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010011247 if (arg2) {
11248 if (put_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011249 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010011250 }
11251 }
11252 if (arg4) {
11253 if (put_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011254 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010011255 }
11256 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011257 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011258 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011259#endif
11260#ifdef TARGET_NR_vmsplice
11261 case TARGET_NR_vmsplice:
11262 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011263 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11264 if (vec != NULL) {
11265 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
11266 unlock_iovec(vec, arg2, arg3, 0);
11267 } else {
11268 ret = -host_to_target_errno(errno);
11269 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011270 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011271 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011272#endif
11273#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030011274#ifdef CONFIG_EVENTFD
11275#if defined(TARGET_NR_eventfd)
11276 case TARGET_NR_eventfd:
11277 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011278 if (ret >= 0) {
11279 fd_trans_register(ret, &target_eventfd_trans);
11280 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011281 return ret;
Riku Voipioc2882b92009-08-12 15:08:24 +030011282#endif
11283#if defined(TARGET_NR_eventfd2)
11284 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020011285 {
11286 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
11287 if (arg2 & TARGET_O_NONBLOCK) {
11288 host_flags |= O_NONBLOCK;
11289 }
11290 if (arg2 & TARGET_O_CLOEXEC) {
11291 host_flags |= O_CLOEXEC;
11292 }
11293 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011294 if (ret >= 0) {
11295 fd_trans_register(ret, &target_eventfd_trans);
11296 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011297 return ret;
Petar Jovanovic5947c692013-04-08 20:26:10 +020011298 }
Riku Voipioc2882b92009-08-12 15:08:24 +030011299#endif
11300#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030011301#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
11302 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010011303#if TARGET_ABI_BITS == 32
11304 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
11305 target_offset64(arg5, arg6)));
11306#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030011307 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010011308#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011309 return ret;
Ulrich Hechtd0927932009-09-17 20:22:14 +030011310#endif
Peter Maydellc727f472011-01-06 11:05:10 +000011311#if defined(CONFIG_SYNC_FILE_RANGE)
11312#if defined(TARGET_NR_sync_file_range)
11313 case TARGET_NR_sync_file_range:
11314#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030011315#if defined(TARGET_MIPS)
11316 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11317 target_offset64(arg5, arg6), arg7));
11318#else
Peter Maydellc727f472011-01-06 11:05:10 +000011319 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
11320 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030011321#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000011322#else
11323 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
11324#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011325 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000011326#endif
11327#if defined(TARGET_NR_sync_file_range2)
11328 case TARGET_NR_sync_file_range2:
11329 /* This is like sync_file_range but the arguments are reordered */
11330#if TARGET_ABI_BITS == 32
11331 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11332 target_offset64(arg5, arg6), arg2));
11333#else
11334 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
11335#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011336 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000011337#endif
11338#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020011339#if defined(TARGET_NR_signalfd4)
11340 case TARGET_NR_signalfd4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011341 return do_signalfd4(arg1, arg2, arg4);
Laurent Viviere36800c2015-10-02 14:48:09 +020011342#endif
11343#if defined(TARGET_NR_signalfd)
11344 case TARGET_NR_signalfd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011345 return do_signalfd4(arg1, arg2, 0);
Laurent Viviere36800c2015-10-02 14:48:09 +020011346#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000011347#if defined(CONFIG_EPOLL)
11348#if defined(TARGET_NR_epoll_create)
11349 case TARGET_NR_epoll_create:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011350 return get_errno(epoll_create(arg1));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011351#endif
11352#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
11353 case TARGET_NR_epoll_create1:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011354 return get_errno(epoll_create1(arg1));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011355#endif
11356#if defined(TARGET_NR_epoll_ctl)
11357 case TARGET_NR_epoll_ctl:
11358 {
11359 struct epoll_event ep;
11360 struct epoll_event *epp = 0;
11361 if (arg4) {
11362 struct target_epoll_event *target_ep;
11363 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011364 return -TARGET_EFAULT;
Peter Maydell3b6edd12011-02-15 18:35:05 +000011365 }
11366 ep.events = tswap32(target_ep->events);
11367 /* The epoll_data_t union is just opaque data to the kernel,
11368 * so we transfer all 64 bits across and need not worry what
11369 * actual data type it is.
11370 */
11371 ep.data.u64 = tswap64(target_ep->data.u64);
11372 unlock_user_struct(target_ep, arg4, 0);
11373 epp = &ep;
11374 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011375 return get_errno(epoll_ctl(arg1, arg2, arg3, epp));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011376 }
11377#endif
11378
Peter Maydell227f0212016-06-06 19:58:11 +010011379#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011380#if defined(TARGET_NR_epoll_wait)
11381 case TARGET_NR_epoll_wait:
11382#endif
Peter Maydell227f0212016-06-06 19:58:11 +010011383#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011384 case TARGET_NR_epoll_pwait:
11385#endif
11386 {
11387 struct target_epoll_event *target_ep;
11388 struct epoll_event *ep;
11389 int epfd = arg1;
11390 int maxevents = arg3;
11391 int timeout = arg4;
11392
Peter Maydell2ba7fae32016-07-18 15:35:59 +010011393 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011394 return -TARGET_EINVAL;
Peter Maydell2ba7fae32016-07-18 15:35:59 +010011395 }
11396
Peter Maydell3b6edd12011-02-15 18:35:05 +000011397 target_ep = lock_user(VERIFY_WRITE, arg2,
11398 maxevents * sizeof(struct target_epoll_event), 1);
11399 if (!target_ep) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011400 return -TARGET_EFAULT;
Peter Maydell3b6edd12011-02-15 18:35:05 +000011401 }
11402
Peter Maydell04c95f42016-07-18 15:36:00 +010011403 ep = g_try_new(struct epoll_event, maxevents);
11404 if (!ep) {
11405 unlock_user(target_ep, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011406 return -TARGET_ENOMEM;
Peter Maydell04c95f42016-07-18 15:36:00 +010011407 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000011408
11409 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010011410#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011411 case TARGET_NR_epoll_pwait:
11412 {
11413 target_sigset_t *target_set;
11414 sigset_t _set, *set = &_set;
11415
11416 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010011417 if (arg6 != sizeof(target_sigset_t)) {
11418 ret = -TARGET_EINVAL;
11419 break;
11420 }
11421
Peter Maydell3b6edd12011-02-15 18:35:05 +000011422 target_set = lock_user(VERIFY_READ, arg5,
11423 sizeof(target_sigset_t), 1);
11424 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010011425 ret = -TARGET_EFAULT;
11426 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000011427 }
11428 target_to_host_sigset(set, target_set);
11429 unlock_user(target_set, arg5, 0);
11430 } else {
11431 set = NULL;
11432 }
11433
Peter Maydell227f0212016-06-06 19:58:11 +010011434 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11435 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011436 break;
11437 }
11438#endif
11439#if defined(TARGET_NR_epoll_wait)
11440 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010011441 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11442 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011443 break;
11444#endif
11445 default:
11446 ret = -TARGET_ENOSYS;
11447 }
11448 if (!is_error(ret)) {
11449 int i;
11450 for (i = 0; i < ret; i++) {
11451 target_ep[i].events = tswap32(ep[i].events);
11452 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11453 }
Peter Maydell04c95f42016-07-18 15:36:00 +010011454 unlock_user(target_ep, arg2,
11455 ret * sizeof(struct target_epoll_event));
11456 } else {
11457 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000011458 }
Peter Maydell04c95f42016-07-18 15:36:00 +010011459 g_free(ep);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011460 return ret;
Peter Maydell3b6edd12011-02-15 18:35:05 +000011461 }
11462#endif
11463#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011464#ifdef TARGET_NR_prlimit64
11465 case TARGET_NR_prlimit64:
11466 {
11467 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11468 struct target_rlimit64 *target_rnew, *target_rold;
11469 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011470 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011471 if (arg3) {
11472 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011473 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010011474 }
11475 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11476 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11477 unlock_user_struct(target_rnew, arg3, 0);
11478 rnewp = &rnew;
11479 }
11480
Felix Janda95018012014-12-02 22:11:17 +010011481 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011482 if (!is_error(ret) && arg4) {
11483 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011484 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010011485 }
11486 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11487 target_rold->rlim_max = tswap64(rold.rlim_max);
11488 unlock_user_struct(target_rold, arg4, 1);
11489 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011490 return ret;
Peter Maydell163a05a2011-06-27 17:44:52 +010011491 }
11492#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011493#ifdef TARGET_NR_gethostname
11494 case TARGET_NR_gethostname:
11495 {
11496 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11497 if (name) {
11498 ret = get_errno(gethostname(name, arg2));
11499 unlock_user(name, arg1, arg2);
11500 } else {
11501 ret = -TARGET_EFAULT;
11502 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011503 return ret;
Richard Henderson3d21d292012-09-15 13:20:46 -070011504 }
11505#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011506#ifdef TARGET_NR_atomic_cmpxchg_32
11507 case TARGET_NR_atomic_cmpxchg_32:
11508 {
11509 /* should use start_exclusive from main.c */
11510 abi_ulong mem_value;
11511 if (get_user_u32(mem_value, arg6)) {
11512 target_siginfo_t info;
11513 info.si_signo = SIGSEGV;
11514 info.si_errno = 0;
11515 info.si_code = TARGET_SEGV_MAPERR;
11516 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011517 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11518 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011519 ret = 0xdeadbeef;
11520
11521 }
11522 if (mem_value == arg2)
11523 put_user_u32(arg1, arg6);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011524 return mem_value;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011525 }
11526#endif
11527#ifdef TARGET_NR_atomic_barrier
11528 case TARGET_NR_atomic_barrier:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011529 /* Like the kernel implementation and the
11530 qemu arm barrier, no-op this? */
11531 return 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011532#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011533
11534#ifdef TARGET_NR_timer_create
11535 case TARGET_NR_timer_create:
11536 {
11537 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11538
11539 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011540
11541 int clkid = arg1;
11542 int timer_index = next_free_host_timer();
11543
11544 if (timer_index < 0) {
11545 ret = -TARGET_EAGAIN;
11546 } else {
11547 timer_t *phtimer = g_posix_timers + timer_index;
11548
11549 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011550 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010011551 ret = target_to_host_sigevent(phost_sevp, arg2);
11552 if (ret != 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011553 return ret;
Peter Maydellc0659762014-08-09 15:42:32 +010011554 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011555 }
11556
11557 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
11558 if (ret) {
11559 phtimer = NULL;
11560 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010011561 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011562 return -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011563 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011564 }
11565 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011566 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011567 }
11568#endif
11569
11570#ifdef TARGET_NR_timer_settime
11571 case TARGET_NR_timer_settime:
11572 {
11573 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11574 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011575 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011576
Alexander Grafaecc8862014-11-10 21:33:03 +010011577 if (timerid < 0) {
11578 ret = timerid;
11579 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011580 ret = -TARGET_EINVAL;
11581 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011582 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011583 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11584
Marc-André Lureau40c80b52017-01-19 10:15:32 -050011585 if (target_to_host_itimerspec(&hspec_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011586 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050011587 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011588 ret = get_errno(
11589 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050011590 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011591 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050011592 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011593 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011594 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011595 }
11596#endif
11597
11598#ifdef TARGET_NR_timer_gettime
11599 case TARGET_NR_timer_gettime:
11600 {
11601 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011602 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011603
Alexander Grafaecc8862014-11-10 21:33:03 +010011604 if (timerid < 0) {
11605 ret = timerid;
11606 } else if (!arg2) {
11607 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011608 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011609 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011610 struct itimerspec hspec;
11611 ret = get_errno(timer_gettime(htimer, &hspec));
11612
11613 if (host_to_target_itimerspec(arg2, &hspec)) {
11614 ret = -TARGET_EFAULT;
11615 }
11616 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011617 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011618 }
11619#endif
11620
11621#ifdef TARGET_NR_timer_getoverrun
11622 case TARGET_NR_timer_getoverrun:
11623 {
11624 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011625 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011626
Alexander Grafaecc8862014-11-10 21:33:03 +010011627 if (timerid < 0) {
11628 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011629 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011630 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011631 ret = get_errno(timer_getoverrun(htimer));
11632 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011633 fd_trans_unregister(ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011634 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011635 }
11636#endif
11637
11638#ifdef TARGET_NR_timer_delete
11639 case TARGET_NR_timer_delete:
11640 {
11641 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011642 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011643
Alexander Grafaecc8862014-11-10 21:33:03 +010011644 if (timerid < 0) {
11645 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011646 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011647 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011648 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011649 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011650 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011651 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011652 }
11653#endif
11654
Riku Voipio51834342014-06-22 11:25:42 +010011655#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11656 case TARGET_NR_timerfd_create:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011657 return get_errno(timerfd_create(arg1,
11658 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
Riku Voipio51834342014-06-22 11:25:42 +010011659#endif
11660
11661#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11662 case TARGET_NR_timerfd_gettime:
11663 {
11664 struct itimerspec its_curr;
11665
11666 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11667
11668 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011669 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010011670 }
11671 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011672 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010011673#endif
11674
11675#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11676 case TARGET_NR_timerfd_settime:
11677 {
11678 struct itimerspec its_new, its_old, *p_new;
11679
11680 if (arg3) {
11681 if (target_to_host_itimerspec(&its_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011682 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010011683 }
11684 p_new = &its_new;
11685 } else {
11686 p_new = NULL;
11687 }
11688
11689 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11690
11691 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011692 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010011693 }
11694 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011695 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010011696#endif
11697
Paul Burtonab31cda2014-06-22 11:25:43 +010011698#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11699 case TARGET_NR_ioprio_get:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011700 return get_errno(ioprio_get(arg1, arg2));
Paul Burtonab31cda2014-06-22 11:25:43 +010011701#endif
11702
11703#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11704 case TARGET_NR_ioprio_set:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011705 return get_errno(ioprio_set(arg1, arg2, arg3));
Paul Burtonab31cda2014-06-22 11:25:43 +010011706#endif
11707
Riku Voipio9af5c902014-08-12 15:58:57 +030011708#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11709 case TARGET_NR_setns:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011710 return get_errno(setns(arg1, arg2));
Riku Voipio9af5c902014-08-12 15:58:57 +030011711#endif
11712#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11713 case TARGET_NR_unshare:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011714 return get_errno(unshare(arg1));
Riku Voipio9af5c902014-08-12 15:58:57 +030011715#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020011716#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
11717 case TARGET_NR_kcmp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011718 return get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
Laurent Vivier2f147882016-09-25 22:20:20 +020011719#endif
Richard Hendersonfa97e382018-07-18 13:06:48 -070011720#ifdef TARGET_NR_swapcontext
11721 case TARGET_NR_swapcontext:
11722 /* PowerPC specific. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011723 return do_swapcontext(cpu_env, arg1, arg2, arg3);
Richard Hendersonfa97e382018-07-18 13:06:48 -070011724#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030011725
bellard31e31b82003-02-18 22:55:36 +000011726 default:
Philippe Mathieu-Daudé122f9c82018-07-06 12:51:25 -030011727 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011728 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011729 }
bellard31e31b82003-02-18 22:55:36 +000011730 return ret;
11731}
Richard Hendersondc1ce182018-08-18 12:01:04 -070011732
11733abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
11734 abi_long arg2, abi_long arg3, abi_long arg4,
11735 abi_long arg5, abi_long arg6, abi_long arg7,
11736 abi_long arg8)
11737{
Richard Henderson29a0af62019-03-22 16:07:18 -070011738 CPUState *cpu = env_cpu(cpu_env);
Richard Hendersondc1ce182018-08-18 12:01:04 -070011739 abi_long ret;
11740
11741#ifdef DEBUG_ERESTARTSYS
11742 /* Debug-only code for exercising the syscall-restart code paths
11743 * in the per-architecture cpu main loops: restart every syscall
11744 * the guest makes once before letting it through.
11745 */
11746 {
11747 static bool flag;
11748 flag = !flag;
11749 if (flag) {
11750 return -TARGET_ERESTARTSYS;
11751 }
11752 }
11753#endif
11754
11755 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4,
11756 arg5, arg6, arg7, arg8);
11757
11758 if (unlikely(do_strace)) {
11759 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
11760 ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
11761 arg5, arg6, arg7, arg8);
11762 print_syscall_ret(num, ret);
11763 } else {
11764 ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
11765 arg5, arg6, arg7, arg8);
11766 }
11767
11768 trace_guest_user_syscall_ret(cpu, num, ret);
11769 return ret;
11770}