blob: cd520ae42e6de246c6d64c8ac12a664e22cec792 [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"
Shu-Chun Weng9bdfa4d2019-08-19 11:09:47 -070023#include "qemu/memfd.h"
Markus Armbrusterdc5e9ac2019-08-12 07:23:49 +020024#include "qemu/queue.h"
bellard31e31b82003-02-18 22:55:36 +000025#include <elf.h>
26#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010027#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000028#include <sys/ipc.h>
29#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000030#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000031#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010032#include <sys/file.h>
33#include <sys/fsuid.h>
34#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000035#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000036#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000037#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000038#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sched.h>
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020040#include <sys/timex.h>
bellard31e31b82003-02-18 22:55:36 +000041#include <sys/socket.h>
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +020042#include <linux/sockios.h>
aurel32607175e2009-04-15 16:11:59 +000043#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000044#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040045#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000046#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000047#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000048#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000049#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000050#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000051#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020052#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000053//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000054#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000055#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020056#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000057#include <linux/icmp.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010058#include <linux/icmpv6.h>
59#include <linux/errqueue.h>
Marco A L Barbosad6d6d6f2017-10-05 10:55:30 -030060#include <linux/random.h>
Riku Voipiod80a1902014-10-01 16:05:46 +030061#ifdef CONFIG_TIMERFD
62#include <sys/timerfd.h>
63#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030064#ifdef CONFIG_EVENTFD
65#include <sys/eventfd.h>
66#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000067#ifdef CONFIG_EPOLL
68#include <sys/epoll.h>
69#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070070#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010071#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070072#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000073#ifdef CONFIG_SENDFILE
74#include <sys/sendfile.h>
75#endif
Aleksandar Markovicbd27e672020-01-16 23:49:50 +010076#ifdef CONFIG_KCOV
77#include <sys/kcov.h>
78#endif
bellard31e31b82003-02-18 22:55:36 +000079
80#define termios host_termios
81#define winsize host_winsize
82#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000083#define sgttyb host_sgttyb /* same as target */
84#define tchars host_tchars /* same as target */
85#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000086
87#include <linux/termios.h>
88#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000089#include <linux/cdrom.h>
90#include <linux/hdreg.h>
91#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000092#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000093#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030094#include <linux/fs.h>
Yunqiang Suab22b4d2019-09-04 14:59:24 +020095#include <linux/fd.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000096#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000097#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000098#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020099#include <linux/fb.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -0700100#if defined(CONFIG_USBFS)
101#include <linux/usbdevice_fs.h>
Cortland Tölvaa1333672018-10-08 09:35:21 -0700102#include <linux/usb/ch9.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -0700103#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200104#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100105#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000106#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100107#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200108#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100109#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200110#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200111#include <linux/netlink.h>
Yunqiang Suf31dddd2019-06-19 16:17:11 +0200112#include <linux/if_alg.h>
Filip Bozuta68365f92020-01-15 20:36:35 +0100113#include <linux/rtc.h>
Filip Bozuta1c4c6fc2020-01-15 20:36:41 +0100114#include <sound/asound.h>
Filip Bozutad6092e02020-08-23 21:50:07 +0200115#ifdef CONFIG_BTRFS
116#include <linux/btrfs.h>
117#endif
Chen Gange865b972020-06-05 09:32:21 +0800118#ifdef HAVE_DRM_H
119#include <libdrm/drm.h>
Chen Gang913b03c2020-08-02 21:39:38 +0800120#include <libdrm/i915_drm.h>
Chen Gange865b972020-06-05 09:32:21 +0800121#endif
pbrookd7e40362008-05-23 16:06:43 +0000122#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200123#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000124
bellard3ef693a2003-03-23 20:17:16 +0000125#include "qemu.h"
Richard Henderson5ebdd772019-03-14 13:10:53 -0700126#include "qemu/guest-random.h"
Alex Bennée01ef6b92020-04-03 20:11:46 +0100127#include "qemu/selfmap.h"
Emilio G. Cotac36f7a62018-10-21 13:27:44 -0400128#include "user/syscall-trace.h"
Richard Henderson51977e22019-03-12 19:22:20 -0700129#include "qapi/error.h"
Laurent Vivierf7e6a402018-08-24 00:22:15 +0200130#include "fd-trans.h"
Philippe Mathieu-Daudédcb32f12020-01-01 12:23:00 +0100131#include "tcg/tcg.h"
bellard31e31b82003-02-18 22:55:36 +0000132
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100133#ifndef CLONE_IO
134#define CLONE_IO 0x80000000 /* Clone io context */
135#endif
136
137/* We can't directly call the host clone syscall, because this will
138 * badly confuse libc (breaking mutexes, for example). So we must
139 * divide clone flags into:
140 * * flag combinations that look like pthread_create()
141 * * flag combinations that look like fork()
142 * * flags we can implement within QEMU itself
143 * * flags we can't support and will return an error for
144 */
145/* For thread creation, all these flags must be present; for
146 * fork, none must be present.
147 */
148#define CLONE_THREAD_FLAGS \
149 (CLONE_VM | CLONE_FS | CLONE_FILES | \
150 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
151
152/* These flags are ignored:
153 * CLONE_DETACHED is now ignored by the kernel;
154 * CLONE_IO is just an optimisation hint to the I/O scheduler
155 */
156#define CLONE_IGNORED_FLAGS \
157 (CLONE_DETACHED | CLONE_IO)
158
159/* Flags for fork which we can implement within QEMU itself */
160#define CLONE_OPTIONAL_FORK_FLAGS \
161 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
162 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
163
164/* Flags for thread creation which we can implement within QEMU itself */
165#define CLONE_OPTIONAL_THREAD_FLAGS \
166 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
167 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
168
169#define CLONE_INVALID_FORK_FLAGS \
170 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
171
172#define CLONE_INVALID_THREAD_FLAGS \
173 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
174 CLONE_IGNORED_FLAGS))
175
176/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
177 * have almost all been allocated. We cannot support any of
178 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
179 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
180 * The checks against the invalid thread masks above will catch these.
181 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
182 */
pbrook30813ce2008-06-02 15:45:44 +0000183
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100184/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
185 * once. This exercises the codepaths for restart.
186 */
187//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000188
bellard1a9353d2003-03-16 20:28:50 +0000189//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000190#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
191#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000192
bellard70a194b2003-08-11 22:20:16 +0000193#undef _syscall0
194#undef _syscall1
195#undef _syscall2
196#undef _syscall3
197#undef _syscall4
198#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000199#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000200
bellard83fcb512006-06-14 13:37:16 +0000201#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000202static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000203{ \
204 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000205}
206
bellard83fcb512006-06-14 13:37:16 +0000207#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000208static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000209{ \
210 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000211}
212
bellard83fcb512006-06-14 13:37:16 +0000213#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000214static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000215{ \
216 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000217}
218
bellard83fcb512006-06-14 13:37:16 +0000219#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000220static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000221{ \
222 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000223}
224
bellard83fcb512006-06-14 13:37:16 +0000225#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000226static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000227{ \
228 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000229}
230
bellard83fcb512006-06-14 13:37:16 +0000231#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
232 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000233static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000234{ \
235 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000236}
bellard83fcb512006-06-14 13:37:16 +0000237
238
239#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
240 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000241static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
242 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000243{ \
244 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
245}
246
bellard70a194b2003-08-11 22:20:16 +0000247
bellard31e31b82003-02-18 22:55:36 +0000248#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000249#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000250#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000251#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000252#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000253#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200254#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000255#define __NR_sys_syslog __NR_syslog
Alistair Francis14690292020-03-18 15:47:01 -0700256#if defined(__NR_futex)
257# define __NR_sys_futex __NR_futex
258#endif
259#if defined(__NR_futex_time64)
260# define __NR_sys_futex_time64 __NR_futex_time64
261#endif
aurel3239b59762008-10-01 21:46:50 +0000262#define __NR_sys_inotify_init __NR_inotify_init
263#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
264#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200265#define __NR_sys_statx __NR_statx
bellard31e31b82003-02-18 22:55:36 +0000266
Peter Maydellb1cef6d2018-01-25 16:19:49 +0000267#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000268#define __NR__llseek __NR_lseek
269#endif
270
James Hogana29e5ba2014-03-25 21:51:08 +0000271/* Newer kernel ports have llseek() instead of _llseek() */
272#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
273#define TARGET_NR__llseek TARGET_NR_llseek
274#endif
275
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +0000276#define __NR_sys_gettid __NR_gettid
277_syscall0(int, sys_gettid)
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100278
279/* For the 64-bit guest on 32-bit host case we must emulate
280 * getdents using getdents64, because otherwise the host
281 * might hand us back more dirent records than we can fit
282 * into the guest buffer after structure format conversion.
283 * Otherwise we emulate getdents with getdents if the host has it.
284 */
285#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
286#define EMULATE_GETDENTS_WITH_GETDENTS
287#endif
288
289#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
aurel323b3f24a2009-04-15 16:12:13 +0000290_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100291#endif
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100292#if (defined(TARGET_NR_getdents) && \
293 !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
Peter Maydell3307e232013-06-12 16:20:21 +0100294 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000295_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
296#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700297#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000298_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
299 loff_t *, res, uint, wh);
300#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200301_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200302_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
303 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000304_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000305#ifdef __NR_exit_group
306_syscall1(int,exit_group,int,error_code)
307#endif
308#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
309_syscall1(int,set_tid_address,int *,tidptr)
310#endif
Alistair Francis14690292020-03-18 15:47:01 -0700311#if defined(__NR_futex)
aurel323b3f24a2009-04-15 16:12:13 +0000312_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
313 const struct timespec *,timeout,int *,uaddr2,int,val3)
314#endif
Alistair Francis14690292020-03-18 15:47:01 -0700315#if defined(__NR_futex_time64)
316_syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val,
317 const struct timespec *,timeout,int *,uaddr2,int,val3)
318#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500319#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
320_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
321 unsigned long *, user_mask_ptr);
322#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
323_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
324 unsigned long *, user_mask_ptr);
Samuel Thibaultb827c3e2018-01-12 09:14:35 +0100325#define __NR_sys_getcpu __NR_getcpu
326_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200327_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
328 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000329_syscall2(int, capget, struct __user_cap_header_struct *, header,
330 struct __user_cap_data_struct *, data);
331_syscall2(int, capset, struct __user_cap_header_struct *, header,
332 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100333#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
334_syscall2(int, ioprio_get, int, which, int, who)
335#endif
336#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
337_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
338#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100339#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
340_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
341#endif
aurel323b3f24a2009-04-15 16:12:13 +0000342
Laurent Vivier2f147882016-09-25 22:20:20 +0200343#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
344_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
345 unsigned long, idx1, unsigned long, idx2)
346#endif
347
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200348/*
349 * It is assumed that struct statx is architecture independent.
350 */
351#if defined(TARGET_NR_statx) && defined(__NR_statx)
352_syscall5(int, sys_statx, int, dirfd, const char *, pathname, int, flags,
353 unsigned int, mask, struct target_statx *, statxbuf)
354#endif
Andreas Schwab85004762019-05-13 11:02:53 +0200355#if defined(TARGET_NR_membarrier) && defined(__NR_membarrier)
356_syscall2(int, membarrier, int, cmd, int, flags)
357#endif
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200358
aurel323b3f24a2009-04-15 16:12:13 +0000359static bitmask_transtbl fcntl_flags_tbl[] = {
360 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
361 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
362 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
363 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
364 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
365 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
366 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
367 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700368 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000369 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
370 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
371 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
372 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000373#if defined(O_DIRECT)
374 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
375#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700376#if defined(O_NOATIME)
377 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
378#endif
379#if defined(O_CLOEXEC)
380 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
381#endif
382#if defined(O_PATH)
383 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
384#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300385#if defined(O_TMPFILE)
386 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
387#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700388 /* Don't terminate the list prematurely on 64-bit host+guest. */
389#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
390 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
391#endif
aurel323b3f24a2009-04-15 16:12:13 +0000392 { 0, 0, 0, 0 }
393};
394
Andreas Schwab0f6bb192020-07-23 12:27:13 +0200395_syscall2(int, sys_getcwd1, char *, buf, size_t, size)
aurel323b3f24a2009-04-15 16:12:13 +0000396
Filip Bozutacac46eb2020-08-25 00:30:50 +0200397#if defined(TARGET_NR_utimensat) || defined(TARGET_NR_utimensat_time64)
Peter Maydell700fa582016-07-18 11:47:55 +0100398#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100399#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000400_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
401 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100402#else
403static int sys_utimensat(int dirfd, const char *pathname,
404 const struct timespec times[2], int flags)
405{
406 errno = ENOSYS;
407 return -1;
408}
ths9007f0e2007-09-25 17:50:37 +0000409#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100410#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000411
Andreas Schwab95d03072018-01-23 11:53:31 +0100412#ifdef TARGET_NR_renameat2
413#if defined(__NR_renameat2)
414#define __NR_sys_renameat2 __NR_renameat2
415_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
416 const char *, new, unsigned int, flags)
417#else
418static int sys_renameat2(int oldfd, const char *old,
419 int newfd, const char *new, int flags)
420{
421 if (flags == 0) {
422 return renameat(oldfd, old, newfd, new);
423 }
424 errno = ENOSYS;
425 return -1;
426}
427#endif
428#endif /* TARGET_NR_renameat2 */
429
aurel323b3f24a2009-04-15 16:12:13 +0000430#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000431#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000432
aurel3239b59762008-10-01 21:46:50 +0000433#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000434static int sys_inotify_init(void)
435{
436 return (inotify_init());
437}
aurel3239b59762008-10-01 21:46:50 +0000438#endif
439#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000440static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
441{
442 return (inotify_add_watch(fd, pathname, mask));
443}
aurel3239b59762008-10-01 21:46:50 +0000444#endif
445#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000446static int sys_inotify_rm_watch(int fd, int32_t wd)
447{
aurel328690e422009-04-17 13:50:32 +0000448 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000449}
aurel3239b59762008-10-01 21:46:50 +0000450#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000451#ifdef CONFIG_INOTIFY1
452#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
453static int sys_inotify_init1(int flags)
454{
455 return (inotify_init1(flags));
456}
457#endif
458#endif
aurel323b3f24a2009-04-15 16:12:13 +0000459#else
460/* Userspace can usually survive runtime without inotify */
461#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000462#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000463#undef TARGET_NR_inotify_add_watch
464#undef TARGET_NR_inotify_rm_watch
465#endif /* CONFIG_INOTIFY */
466
Peter Maydell163a05a2011-06-27 17:44:52 +0100467#if defined(TARGET_NR_prlimit64)
468#ifndef __NR_prlimit64
469# define __NR_prlimit64 -1
470#endif
471#define __NR_sys_prlimit64 __NR_prlimit64
472/* The glibc rlimit structure may not be that used by the underlying syscall */
473struct host_rlimit64 {
474 uint64_t rlim_cur;
475 uint64_t rlim_max;
476};
477_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
478 const struct host_rlimit64 *, new_limit,
479 struct host_rlimit64 *, old_limit)
480#endif
481
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100482
483#if defined(TARGET_NR_timer_create)
zhaolichang6f9ff552020-09-17 15:50:25 +0800484/* Maximum of 32 active POSIX timers allowed at any one time. */
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100485static timer_t g_posix_timers[32] = { 0, } ;
486
487static inline int next_free_host_timer(void)
488{
489 int k ;
490 /* FIXME: Does finding the next free slot require a lock? */
491 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
492 if (g_posix_timers[k] == 0) {
493 g_posix_timers[k] = (timer_t) 1;
494 return k;
495 }
496 }
497 return -1;
498}
499#endif
500
thsb92c47c2007-11-01 00:07:38 +0000501#define ERRNO_TABLE_SIZE 1200
502
503/* target_to_host_errno_table[] is initialized from
504 * host_to_target_errno_table[] in syscall_init(). */
505static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
506};
507
ths637947f2007-06-01 12:09:19 +0000508/*
thsfe8f0962007-07-12 10:59:21 +0000509 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000510 * minus the errnos that are not actually generic to all archs.
511 */
thsb92c47c2007-11-01 00:07:38 +0000512static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800513 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000514 [EIDRM] = TARGET_EIDRM,
515 [ECHRNG] = TARGET_ECHRNG,
516 [EL2NSYNC] = TARGET_EL2NSYNC,
517 [EL3HLT] = TARGET_EL3HLT,
518 [EL3RST] = TARGET_EL3RST,
519 [ELNRNG] = TARGET_ELNRNG,
520 [EUNATCH] = TARGET_EUNATCH,
521 [ENOCSI] = TARGET_ENOCSI,
522 [EL2HLT] = TARGET_EL2HLT,
523 [EDEADLK] = TARGET_EDEADLK,
524 [ENOLCK] = TARGET_ENOLCK,
525 [EBADE] = TARGET_EBADE,
526 [EBADR] = TARGET_EBADR,
527 [EXFULL] = TARGET_EXFULL,
528 [ENOANO] = TARGET_ENOANO,
529 [EBADRQC] = TARGET_EBADRQC,
530 [EBADSLT] = TARGET_EBADSLT,
531 [EBFONT] = TARGET_EBFONT,
532 [ENOSTR] = TARGET_ENOSTR,
533 [ENODATA] = TARGET_ENODATA,
534 [ETIME] = TARGET_ETIME,
535 [ENOSR] = TARGET_ENOSR,
536 [ENONET] = TARGET_ENONET,
537 [ENOPKG] = TARGET_ENOPKG,
538 [EREMOTE] = TARGET_EREMOTE,
539 [ENOLINK] = TARGET_ENOLINK,
540 [EADV] = TARGET_EADV,
541 [ESRMNT] = TARGET_ESRMNT,
542 [ECOMM] = TARGET_ECOMM,
543 [EPROTO] = TARGET_EPROTO,
544 [EDOTDOT] = TARGET_EDOTDOT,
545 [EMULTIHOP] = TARGET_EMULTIHOP,
546 [EBADMSG] = TARGET_EBADMSG,
547 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
548 [EOVERFLOW] = TARGET_EOVERFLOW,
549 [ENOTUNIQ] = TARGET_ENOTUNIQ,
550 [EBADFD] = TARGET_EBADFD,
551 [EREMCHG] = TARGET_EREMCHG,
552 [ELIBACC] = TARGET_ELIBACC,
553 [ELIBBAD] = TARGET_ELIBBAD,
554 [ELIBSCN] = TARGET_ELIBSCN,
555 [ELIBMAX] = TARGET_ELIBMAX,
556 [ELIBEXEC] = TARGET_ELIBEXEC,
557 [EILSEQ] = TARGET_EILSEQ,
558 [ENOSYS] = TARGET_ENOSYS,
559 [ELOOP] = TARGET_ELOOP,
560 [ERESTART] = TARGET_ERESTART,
561 [ESTRPIPE] = TARGET_ESTRPIPE,
562 [ENOTEMPTY] = TARGET_ENOTEMPTY,
563 [EUSERS] = TARGET_EUSERS,
564 [ENOTSOCK] = TARGET_ENOTSOCK,
565 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
566 [EMSGSIZE] = TARGET_EMSGSIZE,
567 [EPROTOTYPE] = TARGET_EPROTOTYPE,
568 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
569 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
570 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
571 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
572 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
573 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
574 [EADDRINUSE] = TARGET_EADDRINUSE,
575 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
576 [ENETDOWN] = TARGET_ENETDOWN,
577 [ENETUNREACH] = TARGET_ENETUNREACH,
578 [ENETRESET] = TARGET_ENETRESET,
579 [ECONNABORTED] = TARGET_ECONNABORTED,
580 [ECONNRESET] = TARGET_ECONNRESET,
581 [ENOBUFS] = TARGET_ENOBUFS,
582 [EISCONN] = TARGET_EISCONN,
583 [ENOTCONN] = TARGET_ENOTCONN,
584 [EUCLEAN] = TARGET_EUCLEAN,
585 [ENOTNAM] = TARGET_ENOTNAM,
586 [ENAVAIL] = TARGET_ENAVAIL,
587 [EISNAM] = TARGET_EISNAM,
588 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200589 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000590 [ESHUTDOWN] = TARGET_ESHUTDOWN,
591 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
592 [ETIMEDOUT] = TARGET_ETIMEDOUT,
593 [ECONNREFUSED] = TARGET_ECONNREFUSED,
594 [EHOSTDOWN] = TARGET_EHOSTDOWN,
595 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
596 [EALREADY] = TARGET_EALREADY,
597 [EINPROGRESS] = TARGET_EINPROGRESS,
598 [ESTALE] = TARGET_ESTALE,
599 [ECANCELED] = TARGET_ECANCELED,
600 [ENOMEDIUM] = TARGET_ENOMEDIUM,
601 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000602#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000603 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000604#endif
605#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000606 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000607#endif
608#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000609 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000610#endif
611#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000612 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000613#endif
614#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000615 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000616#endif
617#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000618 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000619#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200620#ifdef ENOMSG
621 [ENOMSG] = TARGET_ENOMSG,
622#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800623#ifdef ERKFILL
624 [ERFKILL] = TARGET_ERFKILL,
625#endif
626#ifdef EHWPOISON
627 [EHWPOISON] = TARGET_EHWPOISON,
628#endif
thsb92c47c2007-11-01 00:07:38 +0000629};
ths637947f2007-06-01 12:09:19 +0000630
631static inline int host_to_target_errno(int err)
632{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100633 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
634 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000635 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100636 }
ths637947f2007-06-01 12:09:19 +0000637 return err;
638}
639
thsb92c47c2007-11-01 00:07:38 +0000640static inline int target_to_host_errno(int err)
641{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100642 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
643 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000644 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100645 }
thsb92c47c2007-11-01 00:07:38 +0000646 return err;
647}
648
blueswir1992f48a2007-10-14 16:27:31 +0000649static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000650{
651 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000652 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000653 else
654 return ret;
655}
656
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100657const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000658{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100659 if (err == TARGET_ERESTARTSYS) {
660 return "To be restarted";
661 }
662 if (err == TARGET_QEMU_ESIGRETURN) {
663 return "Successful exit from sigreturn";
664 }
665
Alexander Graf962b2892011-11-21 12:04:07 +0100666 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
667 return NULL;
668 }
thsb92c47c2007-11-01 00:07:38 +0000669 return strerror(target_to_host_errno(err));
670}
671
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100672#define safe_syscall0(type, name) \
673static type safe_##name(void) \
674{ \
675 return safe_syscall(__NR_##name); \
676}
677
678#define safe_syscall1(type, name, type1, arg1) \
679static type safe_##name(type1 arg1) \
680{ \
681 return safe_syscall(__NR_##name, arg1); \
682}
683
684#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
685static type safe_##name(type1 arg1, type2 arg2) \
686{ \
687 return safe_syscall(__NR_##name, arg1, arg2); \
688}
689
690#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
691static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
692{ \
693 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
694}
695
696#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
697 type4, arg4) \
698static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
699{ \
700 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
701}
702
703#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
704 type4, arg4, type5, arg5) \
705static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
706 type5 arg5) \
707{ \
708 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
709}
710
711#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
712 type4, arg4, type5, arg5, type6, arg6) \
713static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
714 type5 arg5, type6 arg6) \
715{ \
716 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
717}
718
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100719safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
720safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100721safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
722 int, flags, mode_t, mode)
Alistair Francis859e8a82020-03-12 15:13:49 -0700723#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100724safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
725 struct rusage *, rusage)
Alistair Francis859e8a82020-03-12 15:13:49 -0700726#endif
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100727safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
728 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100729safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Alistair Francis859e8a82020-03-12 15:13:49 -0700730#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +0200731 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
Peter Maydell6df9d382016-05-12 18:47:51 +0100732safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
733 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Alistair Francis859e8a82020-03-12 15:13:49 -0700734#endif
Filip Bozutae5ce9682020-08-25 00:30:49 +0200735#if defined(TARGET_NR_ppoll) || defined(TARGET_NR_ppoll_time64)
Peter Maydella6130232016-06-06 19:58:10 +0100736safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
737 struct timespec *, tsp, const sigset_t *, sigmask,
738 size_t, sigsetsize)
Alistair Francis859e8a82020-03-12 15:13:49 -0700739#endif
Peter Maydell227f0212016-06-06 19:58:11 +0100740safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
741 int, maxevents, int, timeout, const sigset_t *, sigmask,
742 size_t, sigsetsize)
Alistair Francis14690292020-03-18 15:47:01 -0700743#if defined(__NR_futex)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100744safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
745 const struct timespec *,timeout,int *,uaddr2,int,val3)
Alistair Francis859e8a82020-03-12 15:13:49 -0700746#endif
Alistair Francis14690292020-03-18 15:47:01 -0700747#if defined(__NR_futex_time64)
748safe_syscall6(int,futex_time64,int *,uaddr,int,op,int,val, \
749 const struct timespec *,timeout,int *,uaddr2,int,val3)
750#endif
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100751safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100752safe_syscall2(int, kill, pid_t, pid, int, sig)
753safe_syscall2(int, tkill, int, tid, int, sig)
754safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100755safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
756safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200757safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
758 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200759safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
760 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100761safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
762 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100763safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
764 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
765safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
766 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
767safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
768safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100769safe_syscall2(int, flock, int, fd, int, operation)
Filip Bozutaddcbde12020-08-24 21:21:16 +0200770#if defined(TARGET_NR_rt_sigtimedwait) || defined(TARGET_NR_rt_sigtimedwait_time64)
Peter Maydellb3f82332016-06-06 19:58:08 +0100771safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
772 const struct timespec *, uts, size_t, sigsetsize)
Alistair Francis859e8a82020-03-12 15:13:49 -0700773#endif
Peter Maydellff6dc132016-06-06 19:58:13 +0100774safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
775 int, flags)
Alistair Francis859e8a82020-03-12 15:13:49 -0700776#if defined(TARGET_NR_nanosleep)
Peter Maydell9e518222016-06-06 19:58:09 +0100777safe_syscall2(int, nanosleep, const struct timespec *, req,
778 struct timespec *, rem)
Alistair Francis859e8a82020-03-12 15:13:49 -0700779#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +0200780#if defined(TARGET_NR_clock_nanosleep) || \
781 defined(TARGET_NR_clock_nanosleep_time64)
Peter Maydell9e518222016-06-06 19:58:09 +0100782safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
783 const struct timespec *, req, struct timespec *, rem)
784#endif
Laurent Vivier524fa342019-05-29 10:48:04 +0200785#ifdef __NR_ipc
Matus Kyseld8c08b12020-06-26 14:46:11 +0200786#ifdef __s390x__
787safe_syscall5(int, ipc, int, call, long, first, long, second, long, third,
788 void *, ptr)
789#else
Peter Maydell89f9fe42016-06-06 19:58:05 +0100790safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
791 void *, ptr, long, fifth)
Laurent Vivier86e63692019-05-23 19:54:13 +0200792#endif
Matus Kyseld8c08b12020-06-26 14:46:11 +0200793#endif
Laurent Vivier86e63692019-05-23 19:54:13 +0200794#ifdef __NR_msgsnd
795safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
796 int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200797#endif
798#ifdef __NR_msgrcv
799safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
800 long, msgtype, int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200801#endif
802#ifdef __NR_semtimedop
803safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
804 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100805#endif
Filip Bozutad107e372020-08-24 21:37:52 +0200806#if defined(TARGET_NR_mq_timedsend) || \
807 defined(TARGET_NR_mq_timedsend_time64)
Peter Maydelld40ecd62016-06-06 19:58:06 +0100808safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
809 size_t, len, unsigned, prio, const struct timespec *, timeout)
Alistair Francis859e8a82020-03-12 15:13:49 -0700810#endif
Filip Bozutad107e372020-08-24 21:37:52 +0200811#if defined(TARGET_NR_mq_timedreceive) || \
812 defined(TARGET_NR_mq_timedreceive_time64)
Peter Maydelld40ecd62016-06-06 19:58:06 +0100813safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
814 size_t, len, unsigned *, prio, const struct timespec *, timeout)
815#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100816/* We do ioctl like this rather than via safe_syscall3 to preserve the
817 * "third argument might be integer or pointer or not present" behaviour of
818 * the libc function.
819 */
820#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100821/* Similarly for fcntl. Note that callers must always:
822 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
823 * use the flock64 struct rather than unsuffixed flock
824 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
825 */
826#ifdef __NR_fcntl64
827#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
828#else
829#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
830#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100831
Paul Burton8289d112014-06-22 11:25:33 +0100832static inline int host_to_target_sock_type(int host_type)
833{
834 int target_type;
835
836 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
837 case SOCK_DGRAM:
838 target_type = TARGET_SOCK_DGRAM;
839 break;
840 case SOCK_STREAM:
841 target_type = TARGET_SOCK_STREAM;
842 break;
843 default:
844 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
845 break;
846 }
847
848#if defined(SOCK_CLOEXEC)
849 if (host_type & SOCK_CLOEXEC) {
850 target_type |= TARGET_SOCK_CLOEXEC;
851 }
852#endif
853
854#if defined(SOCK_NONBLOCK)
855 if (host_type & SOCK_NONBLOCK) {
856 target_type |= TARGET_SOCK_NONBLOCK;
857 }
858#endif
859
860 return target_type;
861}
862
blueswir1992f48a2007-10-14 16:27:31 +0000863static abi_ulong target_brk;
864static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000865static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000866
blueswir1992f48a2007-10-14 16:27:31 +0000867void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000868{
blueswir14c1de732007-07-07 20:45:44 +0000869 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000870 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000871}
872
vincent4d1de872011-06-14 21:56:33 +0000873//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
874#define DEBUGF_BRK(message, args...)
875
ths0da46a62007-10-20 20:23:07 +0000876/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000877abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000878{
blueswir1992f48a2007-10-14 16:27:31 +0000879 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +0100880 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +0000881
Paul Brook3a0c6c42012-02-09 19:04:27 +0000882 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000883
vincent4d1de872011-06-14 21:56:33 +0000884 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000885 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000886 return target_brk;
887 }
888 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000889 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
890 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000891 return target_brk;
892 }
bellard31e31b82003-02-18 22:55:36 +0000893
vincent4d1de872011-06-14 21:56:33 +0000894 /* If the new brk is less than the highest page reserved to the
895 * target heap allocation, set it and we're almost done... */
896 if (new_brk <= brk_page) {
897 /* Heap contents are initialized to zero, as for anonymous
898 * mapped pages. */
899 if (new_brk > target_brk) {
900 memset(g2h(target_brk), 0, new_brk - target_brk);
901 }
bellard31e31b82003-02-18 22:55:36 +0000902 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000903 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
Paolo Bonzini72e21db2018-12-13 23:37:36 +0100904 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000905 }
906
Peter Maydell00faf082011-04-18 16:34:24 +0100907 /* We need to allocate more memory after the brk... Note that
908 * we don't use MAP_FIXED because that will map over the top of
909 * any existing mapping (like the one with the host libc or qemu
910 * itself); instead we treat "mapped but at wrong address" as
911 * a failure and unmap again.
912 */
vincent4d1de872011-06-14 21:56:33 +0000913 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000914 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000915 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100916 MAP_ANON|MAP_PRIVATE, 0, 0));
917
918 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200919 /* Heap contents are initialized to zero, as for anonymous
920 * mapped pages. Technically the new pages are already
921 * initialized to zero since they *are* anonymous mapped
922 * pages, however we have to take care with the contents that
923 * come from the remaining part of the previous page: it may
924 * contains garbage data due to a previous heap usage (grown
925 * then shrunken). */
926 memset(g2h(target_brk), 0, brk_page - target_brk);
927
Peter Maydell00faf082011-04-18 16:34:24 +0100928 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000929 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000930 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
931 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100932 return target_brk;
933 } else if (mapped_addr != -1) {
934 /* Mapped but at wrong address, meaning there wasn't actually
935 * enough space for this brk.
936 */
937 target_munmap(mapped_addr, new_alloc_size);
938 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000939 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000940 }
941 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000942 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100943 }
balrog7ab240a2008-04-26 12:17:34 +0000944
Richard Henderson7dd46c02010-05-03 10:07:49 -0700945#if defined(TARGET_ALPHA)
946 /* We (partially) emulate OSF/1 on Alpha, which requires we
947 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100948 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700949#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100950 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000951 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000952}
953
Alistair Francis859e8a82020-03-12 15:13:49 -0700954#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +0200955 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
ths26edcf42007-12-09 02:25:24 +0000956static inline abi_long copy_from_user_fdset(fd_set *fds,
957 abi_ulong target_fds_addr,
958 int n)
bellard31e31b82003-02-18 22:55:36 +0000959{
ths26edcf42007-12-09 02:25:24 +0000960 int i, nw, j, k;
961 abi_ulong b, *target_fds;
962
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200963 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000964 if (!(target_fds = lock_user(VERIFY_READ,
965 target_fds_addr,
966 sizeof(abi_ulong) * nw,
967 1)))
968 return -TARGET_EFAULT;
969
970 FD_ZERO(fds);
971 k = 0;
972 for (i = 0; i < nw; i++) {
973 /* grab the abi_ulong */
974 __get_user(b, &target_fds[i]);
975 for (j = 0; j < TARGET_ABI_BITS; j++) {
976 /* check the bit inside the abi_ulong */
977 if ((b >> j) & 1)
978 FD_SET(k, fds);
979 k++;
bellard31e31b82003-02-18 22:55:36 +0000980 }
bellard31e31b82003-02-18 22:55:36 +0000981 }
ths26edcf42007-12-09 02:25:24 +0000982
983 unlock_user(target_fds, target_fds_addr, 0);
984
985 return 0;
bellard31e31b82003-02-18 22:55:36 +0000986}
987
Mike Frysinger055e0902011-06-03 17:01:49 -0400988static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
989 abi_ulong target_fds_addr,
990 int n)
991{
992 if (target_fds_addr) {
993 if (copy_from_user_fdset(fds, target_fds_addr, n))
994 return -TARGET_EFAULT;
995 *fds_ptr = fds;
996 } else {
997 *fds_ptr = NULL;
998 }
999 return 0;
1000}
1001
ths26edcf42007-12-09 02:25:24 +00001002static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1003 const fd_set *fds,
1004 int n)
bellard31e31b82003-02-18 22:55:36 +00001005{
bellard31e31b82003-02-18 22:55:36 +00001006 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001007 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001008 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001009
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001010 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001011 if (!(target_fds = lock_user(VERIFY_WRITE,
1012 target_fds_addr,
1013 sizeof(abi_ulong) * nw,
1014 0)))
1015 return -TARGET_EFAULT;
1016
1017 k = 0;
1018 for (i = 0; i < nw; i++) {
1019 v = 0;
1020 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001021 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001022 k++;
bellard31e31b82003-02-18 22:55:36 +00001023 }
ths26edcf42007-12-09 02:25:24 +00001024 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001025 }
ths26edcf42007-12-09 02:25:24 +00001026
1027 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1028
1029 return 0;
bellard31e31b82003-02-18 22:55:36 +00001030}
Alistair Francis859e8a82020-03-12 15:13:49 -07001031#endif
bellard31e31b82003-02-18 22:55:36 +00001032
bellardc596ed12003-07-13 17:32:31 +00001033#if defined(__alpha__)
1034#define HOST_HZ 1024
1035#else
1036#define HOST_HZ 100
1037#endif
1038
blueswir1992f48a2007-10-14 16:27:31 +00001039static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001040{
1041#if HOST_HZ == TARGET_HZ
1042 return ticks;
1043#else
1044 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1045#endif
1046}
1047
bellard579a97f2007-11-11 14:26:47 +00001048static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1049 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001050{
pbrook53a59602006-03-25 19:31:22 +00001051 struct target_rusage *target_rusage;
1052
bellard579a97f2007-11-11 14:26:47 +00001053 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1054 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001055 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1056 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1057 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1058 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1059 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1060 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1061 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1062 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1063 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1064 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1065 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1066 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1067 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1068 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1069 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1070 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1071 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1072 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001073 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001074
1075 return 0;
bellardb4091862003-05-16 15:39:34 +00001076}
1077
Alistair Francis859e8a82020-03-12 15:13:49 -07001078#ifdef TARGET_NR_setrlimit
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001079static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001080{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001081 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001082 rlim_t result;
1083
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001084 target_rlim_swap = tswapal(target_rlim);
1085 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1086 return RLIM_INFINITY;
1087
1088 result = target_rlim_swap;
1089 if (target_rlim_swap != (rlim_t)result)
1090 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001091
1092 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001093}
Alistair Francis859e8a82020-03-12 15:13:49 -07001094#endif
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001095
Alistair Francis859e8a82020-03-12 15:13:49 -07001096#if defined(TARGET_NR_getrlimit) || defined(TARGET_NR_ugetrlimit)
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001097static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001098{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001099 abi_ulong target_rlim_swap;
1100 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001101
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001102 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001103 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001104 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001105 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001106 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001107
1108 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001109}
Alistair Francis859e8a82020-03-12 15:13:49 -07001110#endif
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001111
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001112static inline int target_to_host_resource(int code)
1113{
1114 switch (code) {
1115 case TARGET_RLIMIT_AS:
1116 return RLIMIT_AS;
1117 case TARGET_RLIMIT_CORE:
1118 return RLIMIT_CORE;
1119 case TARGET_RLIMIT_CPU:
1120 return RLIMIT_CPU;
1121 case TARGET_RLIMIT_DATA:
1122 return RLIMIT_DATA;
1123 case TARGET_RLIMIT_FSIZE:
1124 return RLIMIT_FSIZE;
1125 case TARGET_RLIMIT_LOCKS:
1126 return RLIMIT_LOCKS;
1127 case TARGET_RLIMIT_MEMLOCK:
1128 return RLIMIT_MEMLOCK;
1129 case TARGET_RLIMIT_MSGQUEUE:
1130 return RLIMIT_MSGQUEUE;
1131 case TARGET_RLIMIT_NICE:
1132 return RLIMIT_NICE;
1133 case TARGET_RLIMIT_NOFILE:
1134 return RLIMIT_NOFILE;
1135 case TARGET_RLIMIT_NPROC:
1136 return RLIMIT_NPROC;
1137 case TARGET_RLIMIT_RSS:
1138 return RLIMIT_RSS;
1139 case TARGET_RLIMIT_RTPRIO:
1140 return RLIMIT_RTPRIO;
1141 case TARGET_RLIMIT_SIGPENDING:
1142 return RLIMIT_SIGPENDING;
1143 case TARGET_RLIMIT_STACK:
1144 return RLIMIT_STACK;
1145 default:
1146 return code;
1147 }
1148}
1149
ths788f5ec2007-12-09 02:37:05 +00001150static inline abi_long copy_from_user_timeval(struct timeval *tv,
1151 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001152{
pbrook53a59602006-03-25 19:31:22 +00001153 struct target_timeval *target_tv;
1154
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001155 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
bellard579a97f2007-11-11 14:26:47 +00001156 return -TARGET_EFAULT;
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001157 }
ths788f5ec2007-12-09 02:37:05 +00001158
1159 __get_user(tv->tv_sec, &target_tv->tv_sec);
1160 __get_user(tv->tv_usec, &target_tv->tv_usec);
1161
1162 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001163
1164 return 0;
bellard31e31b82003-02-18 22:55:36 +00001165}
1166
ths788f5ec2007-12-09 02:37:05 +00001167static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1168 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001169{
pbrook53a59602006-03-25 19:31:22 +00001170 struct target_timeval *target_tv;
1171
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001172 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
bellard579a97f2007-11-11 14:26:47 +00001173 return -TARGET_EFAULT;
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001174 }
ths788f5ec2007-12-09 02:37:05 +00001175
1176 __put_user(tv->tv_sec, &target_tv->tv_sec);
1177 __put_user(tv->tv_usec, &target_tv->tv_usec);
1178
1179 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001180
1181 return 0;
bellard31e31b82003-02-18 22:55:36 +00001182}
1183
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001184#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
1185static inline abi_long copy_from_user_timeval64(struct timeval *tv,
1186 abi_ulong target_tv_addr)
1187{
1188 struct target__kernel_sock_timeval *target_tv;
1189
1190 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
1191 return -TARGET_EFAULT;
1192 }
1193
1194 __get_user(tv->tv_sec, &target_tv->tv_sec);
1195 __get_user(tv->tv_usec, &target_tv->tv_usec);
1196
1197 unlock_user_struct(target_tv, target_tv_addr, 0);
1198
1199 return 0;
1200}
1201#endif
1202
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001203static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr,
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001204 const struct timeval *tv)
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001205{
1206 struct target__kernel_sock_timeval *target_tv;
1207
1208 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
1209 return -TARGET_EFAULT;
1210 }
1211
1212 __put_user(tv->tv_sec, &target_tv->tv_sec);
1213 __put_user(tv->tv_usec, &target_tv->tv_usec);
1214
1215 unlock_user_struct(target_tv, target_tv_addr, 1);
1216
1217 return 0;
1218}
1219
Alistair Francis859e8a82020-03-12 15:13:49 -07001220#if defined(TARGET_NR_futex) || \
1221 defined(TARGET_NR_rt_sigtimedwait) || \
1222 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6) || \
1223 defined(TARGET_NR_nanosleep) || defined(TARGET_NR_clock_settime) || \
1224 defined(TARGET_NR_utimensat) || defined(TARGET_NR_mq_timedsend) || \
Matus Kyseld8c08b12020-06-26 14:46:11 +02001225 defined(TARGET_NR_mq_timedreceive) || defined(TARGET_NR_ipc) || \
Filip Bozuta2c86c902020-07-22 17:34:20 +02001226 defined(TARGET_NR_semop) || defined(TARGET_NR_semtimedop) || \
1227 defined(TARGET_NR_timer_settime) || \
1228 (defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD))
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001229static inline abi_long target_to_host_timespec(struct timespec *host_ts,
1230 abi_ulong target_addr)
1231{
1232 struct target_timespec *target_ts;
1233
1234 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) {
1235 return -TARGET_EFAULT;
1236 }
1237 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
1238 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1239 unlock_user_struct(target_ts, target_addr, 0);
1240 return 0;
1241}
Alistair Francis859e8a82020-03-12 15:13:49 -07001242#endif
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001243
Filip Bozuta828cb3a2020-07-22 17:34:21 +02001244#if defined(TARGET_NR_clock_settime64) || defined(TARGET_NR_futex_time64) || \
1245 defined(TARGET_NR_timer_settime64) || \
Filip Bozutad107e372020-08-24 21:37:52 +02001246 defined(TARGET_NR_mq_timedsend_time64) || \
1247 defined(TARGET_NR_mq_timedreceive_time64) || \
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001248 (defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD)) || \
Filip Bozutaddcbde12020-08-24 21:21:16 +02001249 defined(TARGET_NR_clock_nanosleep_time64) || \
Filip Bozutacac46eb2020-08-25 00:30:50 +02001250 defined(TARGET_NR_rt_sigtimedwait_time64) || \
1251 defined(TARGET_NR_utimensat) || \
1252 defined(TARGET_NR_utimensat_time64) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +02001253 defined(TARGET_NR_semtimedop_time64) || \
1254 defined(TARGET_NR_pselect6_time64) || defined(TARGET_NR_ppoll_time64)
Alistair Francisc6c8d102020-03-12 15:13:53 -07001255static inline abi_long target_to_host_timespec64(struct timespec *host_ts,
1256 abi_ulong target_addr)
1257{
1258 struct target__kernel_timespec *target_ts;
1259
1260 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) {
1261 return -TARGET_EFAULT;
1262 }
1263 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
1264 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
Laurent Vivier00576752020-08-27 09:04:49 +02001265 /* in 32bit mode, this drops the padding */
1266 host_ts->tv_nsec = (long)(abi_long)host_ts->tv_nsec;
Alistair Francisc6c8d102020-03-12 15:13:53 -07001267 unlock_user_struct(target_ts, target_addr, 0);
1268 return 0;
1269}
1270#endif
1271
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001272static inline abi_long host_to_target_timespec(abi_ulong target_addr,
1273 struct timespec *host_ts)
1274{
1275 struct target_timespec *target_ts;
1276
1277 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
1278 return -TARGET_EFAULT;
1279 }
1280 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
1281 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1282 unlock_user_struct(target_ts, target_addr, 1);
1283 return 0;
1284}
1285
1286static inline abi_long host_to_target_timespec64(abi_ulong target_addr,
1287 struct timespec *host_ts)
1288{
1289 struct target__kernel_timespec *target_ts;
1290
1291 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
1292 return -TARGET_EFAULT;
1293 }
1294 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
1295 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1296 unlock_user_struct(target_ts, target_addr, 1);
1297 return 0;
1298}
1299
Richard Hendersona52f5f82020-02-12 19:22:23 -08001300#if defined(TARGET_NR_gettimeofday)
1301static inline abi_long copy_to_user_timezone(abi_ulong target_tz_addr,
1302 struct timezone *tz)
1303{
1304 struct target_timezone *target_tz;
1305
1306 if (!lock_user_struct(VERIFY_WRITE, target_tz, target_tz_addr, 1)) {
1307 return -TARGET_EFAULT;
1308 }
1309
1310 __put_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1311 __put_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1312
1313 unlock_user_struct(target_tz, target_tz_addr, 1);
1314
1315 return 0;
1316}
1317#endif
1318
Alistair Francis859e8a82020-03-12 15:13:49 -07001319#if defined(TARGET_NR_settimeofday)
Paul Burtonef4467e2014-06-22 11:25:40 +01001320static inline abi_long copy_from_user_timezone(struct timezone *tz,
1321 abi_ulong target_tz_addr)
1322{
1323 struct target_timezone *target_tz;
1324
1325 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1326 return -TARGET_EFAULT;
1327 }
1328
1329 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1330 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1331
1332 unlock_user_struct(target_tz, target_tz_addr, 0);
1333
1334 return 0;
1335}
Alistair Francis859e8a82020-03-12 15:13:49 -07001336#endif
Paul Burtonef4467e2014-06-22 11:25:40 +01001337
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001338#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1339#include <mqueue.h>
1340
aurel3224e10032009-04-15 16:11:43 +00001341static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1342 abi_ulong target_mq_attr_addr)
1343{
1344 struct target_mq_attr *target_mq_attr;
1345
1346 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1347 target_mq_attr_addr, 1))
1348 return -TARGET_EFAULT;
1349
1350 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1351 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1352 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1353 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1354
1355 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1356
1357 return 0;
1358}
1359
1360static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1361 const struct mq_attr *attr)
1362{
1363 struct target_mq_attr *target_mq_attr;
1364
1365 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1366 target_mq_attr_addr, 0))
1367 return -TARGET_EFAULT;
1368
1369 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1370 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1371 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1372 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1373
1374 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1375
1376 return 0;
1377}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001378#endif
bellard31e31b82003-02-18 22:55:36 +00001379
Mike Frysinger055e0902011-06-03 17:01:49 -04001380#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001381/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001382static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001383 abi_ulong rfd_addr, abi_ulong wfd_addr,
1384 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001385{
1386 fd_set rfds, wfds, efds;
1387 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001388 struct timeval tv;
1389 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001390 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001391
Mike Frysinger055e0902011-06-03 17:01:49 -04001392 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1393 if (ret) {
1394 return ret;
pbrook53a59602006-03-25 19:31:22 +00001395 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001396 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1397 if (ret) {
1398 return ret;
pbrook53a59602006-03-25 19:31:22 +00001399 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001400 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1401 if (ret) {
1402 return ret;
pbrook53a59602006-03-25 19:31:22 +00001403 }
ths3b46e622007-09-17 08:09:54 +00001404
ths26edcf42007-12-09 02:25:24 +00001405 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001406 if (copy_from_user_timeval(&tv, target_tv_addr))
1407 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001408 ts.tv_sec = tv.tv_sec;
1409 ts.tv_nsec = tv.tv_usec * 1000;
1410 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001411 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001412 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001413 }
ths26edcf42007-12-09 02:25:24 +00001414
Peter Maydell6df9d382016-05-12 18:47:51 +01001415 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1416 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001417
ths26edcf42007-12-09 02:25:24 +00001418 if (!is_error(ret)) {
1419 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1420 return -TARGET_EFAULT;
1421 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1422 return -TARGET_EFAULT;
1423 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1424 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001425
Peter Maydell6df9d382016-05-12 18:47:51 +01001426 if (target_tv_addr) {
1427 tv.tv_sec = ts.tv_sec;
1428 tv.tv_usec = ts.tv_nsec / 1000;
1429 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1430 return -TARGET_EFAULT;
1431 }
1432 }
bellard31e31b82003-02-18 22:55:36 +00001433 }
bellard579a97f2007-11-11 14:26:47 +00001434
bellard31e31b82003-02-18 22:55:36 +00001435 return ret;
1436}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001437
1438#if defined(TARGET_WANT_OLD_SYS_SELECT)
1439static abi_long do_old_select(abi_ulong arg1)
1440{
1441 struct target_sel_arg_struct *sel;
1442 abi_ulong inp, outp, exp, tvp;
1443 long nsel;
1444
1445 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1446 return -TARGET_EFAULT;
1447 }
1448
1449 nsel = tswapal(sel->n);
1450 inp = tswapal(sel->inp);
1451 outp = tswapal(sel->outp);
1452 exp = tswapal(sel->exp);
1453 tvp = tswapal(sel->tvp);
1454
1455 unlock_user_struct(sel, arg1, 0);
1456
1457 return do_select(nsel, inp, outp, exp, tvp);
1458}
1459#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001460#endif
bellard31e31b82003-02-18 22:55:36 +00001461
Filip Bozutae5ce9682020-08-25 00:30:49 +02001462#if defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
1463static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
1464 abi_long arg4, abi_long arg5, abi_long arg6,
1465 bool time64)
1466{
1467 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
1468 fd_set rfds, wfds, efds;
1469 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1470 struct timespec ts, *ts_ptr;
1471 abi_long ret;
1472
1473 /*
1474 * The 6th arg is actually two args smashed together,
1475 * so we cannot use the C library.
1476 */
1477 sigset_t set;
1478 struct {
1479 sigset_t *set;
1480 size_t size;
1481 } sig, *sig_ptr;
1482
1483 abi_ulong arg_sigset, arg_sigsize, *arg7;
1484 target_sigset_t *target_sigset;
1485
1486 n = arg1;
1487 rfd_addr = arg2;
1488 wfd_addr = arg3;
1489 efd_addr = arg4;
1490 ts_addr = arg5;
1491
1492 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1493 if (ret) {
1494 return ret;
1495 }
1496 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1497 if (ret) {
1498 return ret;
1499 }
1500 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1501 if (ret) {
1502 return ret;
1503 }
1504
1505 /*
1506 * This takes a timespec, and not a timeval, so we cannot
1507 * use the do_select() helper ...
1508 */
1509 if (ts_addr) {
1510 if (time64) {
1511 if (target_to_host_timespec64(&ts, ts_addr)) {
1512 return -TARGET_EFAULT;
1513 }
1514 } else {
1515 if (target_to_host_timespec(&ts, ts_addr)) {
1516 return -TARGET_EFAULT;
1517 }
1518 }
1519 ts_ptr = &ts;
1520 } else {
1521 ts_ptr = NULL;
1522 }
1523
1524 /* Extract the two packed args for the sigset */
1525 if (arg6) {
1526 sig_ptr = &sig;
1527 sig.size = SIGSET_T_SIZE;
1528
1529 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
1530 if (!arg7) {
1531 return -TARGET_EFAULT;
1532 }
1533 arg_sigset = tswapal(arg7[0]);
1534 arg_sigsize = tswapal(arg7[1]);
1535 unlock_user(arg7, arg6, 0);
1536
1537 if (arg_sigset) {
1538 sig.set = &set;
1539 if (arg_sigsize != sizeof(*target_sigset)) {
1540 /* Like the kernel, we enforce correct size sigsets */
1541 return -TARGET_EINVAL;
1542 }
1543 target_sigset = lock_user(VERIFY_READ, arg_sigset,
1544 sizeof(*target_sigset), 1);
1545 if (!target_sigset) {
1546 return -TARGET_EFAULT;
1547 }
1548 target_to_host_sigset(&set, target_sigset);
1549 unlock_user(target_sigset, arg_sigset, 0);
1550 } else {
1551 sig.set = NULL;
1552 }
1553 } else {
1554 sig_ptr = NULL;
1555 }
1556
1557 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1558 ts_ptr, sig_ptr));
1559
1560 if (!is_error(ret)) {
1561 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) {
1562 return -TARGET_EFAULT;
1563 }
1564 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) {
1565 return -TARGET_EFAULT;
1566 }
1567 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) {
1568 return -TARGET_EFAULT;
1569 }
1570 if (time64) {
1571 if (ts_addr && host_to_target_timespec64(ts_addr, &ts)) {
1572 return -TARGET_EFAULT;
1573 }
1574 } else {
1575 if (ts_addr && host_to_target_timespec(ts_addr, &ts)) {
1576 return -TARGET_EFAULT;
1577 }
1578 }
1579 }
1580 return ret;
1581}
1582#endif
1583
1584#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll) || \
1585 defined(TARGET_NR_ppoll_time64)
1586static abi_long do_ppoll(abi_long arg1, abi_long arg2, abi_long arg3,
1587 abi_long arg4, abi_long arg5, bool ppoll, bool time64)
1588{
1589 struct target_pollfd *target_pfd;
1590 unsigned int nfds = arg2;
1591 struct pollfd *pfd;
1592 unsigned int i;
1593 abi_long ret;
1594
1595 pfd = NULL;
1596 target_pfd = NULL;
1597 if (nfds) {
1598 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
1599 return -TARGET_EINVAL;
1600 }
1601 target_pfd = lock_user(VERIFY_WRITE, arg1,
1602 sizeof(struct target_pollfd) * nfds, 1);
1603 if (!target_pfd) {
1604 return -TARGET_EFAULT;
1605 }
1606
1607 pfd = alloca(sizeof(struct pollfd) * nfds);
1608 for (i = 0; i < nfds; i++) {
1609 pfd[i].fd = tswap32(target_pfd[i].fd);
1610 pfd[i].events = tswap16(target_pfd[i].events);
1611 }
1612 }
1613 if (ppoll) {
1614 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
1615 target_sigset_t *target_set;
1616 sigset_t _set, *set = &_set;
1617
1618 if (arg3) {
1619 if (time64) {
1620 if (target_to_host_timespec64(timeout_ts, arg3)) {
1621 unlock_user(target_pfd, arg1, 0);
1622 return -TARGET_EFAULT;
1623 }
1624 } else {
1625 if (target_to_host_timespec(timeout_ts, arg3)) {
1626 unlock_user(target_pfd, arg1, 0);
1627 return -TARGET_EFAULT;
1628 }
1629 }
1630 } else {
1631 timeout_ts = NULL;
1632 }
1633
1634 if (arg4) {
1635 if (arg5 != sizeof(target_sigset_t)) {
1636 unlock_user(target_pfd, arg1, 0);
1637 return -TARGET_EINVAL;
1638 }
1639
1640 target_set = lock_user(VERIFY_READ, arg4,
1641 sizeof(target_sigset_t), 1);
1642 if (!target_set) {
1643 unlock_user(target_pfd, arg1, 0);
1644 return -TARGET_EFAULT;
1645 }
1646 target_to_host_sigset(set, target_set);
1647 } else {
1648 set = NULL;
1649 }
1650
1651 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
1652 set, SIGSET_T_SIZE));
1653
1654 if (!is_error(ret) && arg3) {
1655 if (time64) {
1656 if (host_to_target_timespec64(arg3, timeout_ts)) {
1657 return -TARGET_EFAULT;
1658 }
1659 } else {
1660 if (host_to_target_timespec(arg3, timeout_ts)) {
1661 return -TARGET_EFAULT;
1662 }
1663 }
1664 }
1665 if (arg4) {
1666 unlock_user(target_set, arg4, 0);
1667 }
1668 } else {
1669 struct timespec ts, *pts;
1670
1671 if (arg3 >= 0) {
1672 /* Convert ms to secs, ns */
1673 ts.tv_sec = arg3 / 1000;
1674 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
1675 pts = &ts;
1676 } else {
1677 /* -ve poll() timeout means "infinite" */
1678 pts = NULL;
1679 }
1680 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
1681 }
1682
1683 if (!is_error(ret)) {
1684 for (i = 0; i < nfds; i++) {
1685 target_pfd[i].revents = tswap16(pfd[i].revents);
1686 }
1687 }
1688 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
1689 return ret;
1690}
1691#endif
1692
Riku Voipio099d6b02009-05-05 12:10:04 +03001693static abi_long do_pipe2(int host_pipe[], int flags)
1694{
1695#ifdef CONFIG_PIPE2
1696 return pipe2(host_pipe, flags);
1697#else
1698 return -ENOSYS;
1699#endif
1700}
1701
Richard Hendersonfb41a662010-05-03 10:07:52 -07001702static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1703 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001704{
1705 int host_pipe[2];
1706 abi_long ret;
1707 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1708
1709 if (is_error(ret))
1710 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001711
1712 /* Several targets have special calling conventions for the original
1713 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1714 if (!is_pipe2) {
1715#if defined(TARGET_ALPHA)
1716 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1717 return host_pipe[0];
1718#elif defined(TARGET_MIPS)
1719 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1720 return host_pipe[0];
1721#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001722 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001723 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001724#elif defined(TARGET_SPARC)
1725 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1726 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001727#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001728 }
1729
Riku Voipio099d6b02009-05-05 12:10:04 +03001730 if (put_user_s32(host_pipe[0], pipedes)
1731 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1732 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001733 return get_errno(ret);
1734}
1735
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001736static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1737 abi_ulong target_addr,
1738 socklen_t len)
1739{
1740 struct target_ip_mreqn *target_smreqn;
1741
1742 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1743 if (!target_smreqn)
1744 return -TARGET_EFAULT;
1745 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1746 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1747 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001748 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001749 unlock_user(target_smreqn, target_addr, 0);
1750
1751 return 0;
1752}
1753
Laurent Vivier7b36f782015-10-28 21:40:44 +01001754static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001755 abi_ulong target_addr,
1756 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001757{
aurel32607175e2009-04-15 16:11:59 +00001758 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1759 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001760 struct target_sockaddr *target_saddr;
1761
Laurent Vivier7b36f782015-10-28 21:40:44 +01001762 if (fd_trans_target_to_host_addr(fd)) {
1763 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1764 }
1765
bellard579a97f2007-11-11 14:26:47 +00001766 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1767 if (!target_saddr)
1768 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001769
1770 sa_family = tswap16(target_saddr->sa_family);
1771
1772 /* Oops. The caller might send a incomplete sun_path; sun_path
1773 * must be terminated by \0 (see the manual page), but
1774 * unfortunately it is quite common to specify sockaddr_un
1775 * length as "strlen(x->sun_path)" while it should be
1776 * "strlen(...) + 1". We'll fix that here if needed.
1777 * Linux kernel has a similar feature.
1778 */
1779
1780 if (sa_family == AF_UNIX) {
1781 if (len < unix_maxlen && len > 0) {
1782 char *cp = (char*)target_saddr;
1783
1784 if ( cp[len-1] && !cp[len] )
1785 len++;
1786 }
1787 if (len > unix_maxlen)
1788 len = unix_maxlen;
1789 }
1790
pbrook53a59602006-03-25 19:31:22 +00001791 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001792 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001793 if (sa_family == AF_NETLINK) {
1794 struct sockaddr_nl *nladdr;
1795
1796 nladdr = (struct sockaddr_nl *)addr;
1797 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1798 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1799 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001800 struct target_sockaddr_ll *lladdr;
1801
1802 lladdr = (struct target_sockaddr_ll *)addr;
1803 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1804 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1805 }
pbrook53a59602006-03-25 19:31:22 +00001806 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001807
1808 return 0;
bellard7854b052003-03-29 17:22:23 +00001809}
1810
bellard579a97f2007-11-11 14:26:47 +00001811static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1812 struct sockaddr *addr,
1813 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001814{
pbrook53a59602006-03-25 19:31:22 +00001815 struct target_sockaddr *target_saddr;
1816
Peter Maydella1e22192016-07-07 15:44:43 +01001817 if (len == 0) {
1818 return 0;
1819 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001820 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001821
bellard579a97f2007-11-11 14:26:47 +00001822 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1823 if (!target_saddr)
1824 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001825 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001826 if (len >= offsetof(struct target_sockaddr, sa_family) +
1827 sizeof(target_saddr->sa_family)) {
1828 target_saddr->sa_family = tswap16(addr->sa_family);
1829 }
Philippe Mathieu-Daudéa47401b2019-10-21 13:48:52 +02001830 if (addr->sa_family == AF_NETLINK &&
1831 len >= sizeof(struct target_sockaddr_nl)) {
1832 struct target_sockaddr_nl *target_nl =
1833 (struct target_sockaddr_nl *)target_saddr;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001834 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1835 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001836 } else if (addr->sa_family == AF_PACKET) {
1837 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1838 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1839 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001840 } else if (addr->sa_family == AF_INET6 &&
1841 len >= sizeof(struct target_sockaddr_in6)) {
1842 struct target_sockaddr_in6 *target_in6 =
1843 (struct target_sockaddr_in6 *)target_saddr;
1844 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001845 }
pbrook53a59602006-03-25 19:31:22 +00001846 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001847
1848 return 0;
bellard7854b052003-03-29 17:22:23 +00001849}
1850
bellard5a4a8982007-11-11 17:39:18 +00001851static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1852 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001853{
1854 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001855 abi_long msg_controllen;
1856 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001857 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001858 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001859
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001860 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001861 if (msg_controllen < sizeof (struct target_cmsghdr))
1862 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001863 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001864 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001865 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001866 if (!target_cmsg)
1867 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001868
1869 while (cmsg && target_cmsg) {
1870 void *data = CMSG_DATA(cmsg);
1871 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1872
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001873 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001874 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001875
1876 space += CMSG_SPACE(len);
1877 if (space > msgh->msg_controllen) {
1878 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001879 /* This is a QEMU bug, since we allocated the payload
1880 * area ourselves (unlike overflow in host-to-target
1881 * conversion, which is just the guest giving us a buffer
1882 * that's too small). It can't happen for the payload types
1883 * we currently support; if it becomes an issue in future
1884 * we would need to improve our allocation strategy to
1885 * something more intelligent than "twice the size of the
1886 * target buffer we're reading from".
1887 */
Josh Kunz39be5352020-02-03 18:54:13 -08001888 qemu_log_mask(LOG_UNIMP,
1889 ("Unsupported ancillary data %d/%d: "
1890 "unhandled msg size\n"),
1891 tswap32(target_cmsg->cmsg_level),
1892 tswap32(target_cmsg->cmsg_type));
bellard7854b052003-03-29 17:22:23 +00001893 break;
1894 }
1895
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001896 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1897 cmsg->cmsg_level = SOL_SOCKET;
1898 } else {
1899 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1900 }
bellard7854b052003-03-29 17:22:23 +00001901 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1902 cmsg->cmsg_len = CMSG_LEN(len);
1903
Alex Suykov30b8b682014-12-23 07:52:58 +02001904 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001905 int *fd = (int *)data;
1906 int *target_fd = (int *)target_data;
1907 int i, numfds = len / sizeof(int);
1908
Peter Maydell876e23c2015-05-26 19:46:32 +01001909 for (i = 0; i < numfds; i++) {
1910 __get_user(fd[i], target_fd + i);
1911 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001912 } else if (cmsg->cmsg_level == SOL_SOCKET
1913 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1914 struct ucred *cred = (struct ucred *)data;
1915 struct target_ucred *target_cred =
1916 (struct target_ucred *)target_data;
1917
Peter Maydell876e23c2015-05-26 19:46:32 +01001918 __get_user(cred->pid, &target_cred->pid);
1919 __get_user(cred->uid, &target_cred->uid);
1920 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001921 } else {
Josh Kunz39be5352020-02-03 18:54:13 -08001922 qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
1923 cmsg->cmsg_level, cmsg->cmsg_type);
Alex Suykov30b8b682014-12-23 07:52:58 +02001924 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001925 }
1926
1927 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001928 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1929 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001930 }
bellard5a4a8982007-11-11 17:39:18 +00001931 unlock_user(target_cmsg, target_cmsg_addr, 0);
1932 the_end:
bellard7854b052003-03-29 17:22:23 +00001933 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001934 return 0;
bellard7854b052003-03-29 17:22:23 +00001935}
1936
bellard5a4a8982007-11-11 17:39:18 +00001937static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1938 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001939{
1940 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001941 abi_long msg_controllen;
1942 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001943 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001944 socklen_t space = 0;
1945
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001946 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001947 if (msg_controllen < sizeof (struct target_cmsghdr))
1948 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001949 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001950 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001951 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001952 if (!target_cmsg)
1953 return -TARGET_EFAULT;
1954
bellard7854b052003-03-29 17:22:23 +00001955 while (cmsg && target_cmsg) {
1956 void *data = CMSG_DATA(cmsg);
1957 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1958
Peter Maydellad762b92017-12-15 13:52:56 +00001959 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001960 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001961
Peter Maydellc2aeb252015-05-26 19:46:31 +01001962 /* We never copy a half-header but may copy half-data;
1963 * this is Linux's behaviour in put_cmsg(). Note that
1964 * truncation here is a guest problem (which we report
1965 * to the guest via the CTRUNC bit), unlike truncation
1966 * in target_to_host_cmsg, which is a QEMU bug.
1967 */
Peter Maydell71749702017-12-15 13:52:55 +00001968 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001969 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001970 break;
1971 }
1972
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001973 if (cmsg->cmsg_level == SOL_SOCKET) {
1974 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1975 } else {
1976 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1977 }
bellard7854b052003-03-29 17:22:23 +00001978 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001979
Peter Maydellc2aeb252015-05-26 19:46:31 +01001980 /* Payload types which need a different size of payload on
1981 * the target must adjust tgt_len here.
1982 */
Peter Maydell309786c2018-05-18 19:47:15 +01001983 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001984 switch (cmsg->cmsg_level) {
1985 case SOL_SOCKET:
1986 switch (cmsg->cmsg_type) {
1987 case SO_TIMESTAMP:
1988 tgt_len = sizeof(struct target_timeval);
1989 break;
1990 default:
1991 break;
1992 }
Peter Maydell309786c2018-05-18 19:47:15 +01001993 break;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001994 default:
1995 break;
1996 }
1997
Peter Maydell71749702017-12-15 13:52:55 +00001998 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001999 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00002000 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002001 }
2002
2003 /* We must now copy-and-convert len bytes of payload
2004 * into tgt_len bytes of destination space. Bear in mind
2005 * that in both source and destination we may be dealing
2006 * with a truncated value!
2007 */
Huw Davies52b65492014-04-17 14:02:47 +01002008 switch (cmsg->cmsg_level) {
2009 case SOL_SOCKET:
2010 switch (cmsg->cmsg_type) {
2011 case SCM_RIGHTS:
2012 {
2013 int *fd = (int *)data;
2014 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01002015 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00002016
Peter Maydell876e23c2015-05-26 19:46:32 +01002017 for (i = 0; i < numfds; i++) {
2018 __put_user(fd[i], target_fd + i);
2019 }
Huw Davies52b65492014-04-17 14:02:47 +01002020 break;
2021 }
2022 case SO_TIMESTAMP:
2023 {
2024 struct timeval *tv = (struct timeval *)data;
2025 struct target_timeval *target_tv =
2026 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00002027
Peter Maydellc2aeb252015-05-26 19:46:31 +01002028 if (len != sizeof(struct timeval) ||
2029 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01002030 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01002031 }
Huw Davies52b65492014-04-17 14:02:47 +01002032
2033 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01002034 __put_user(tv->tv_sec, &target_tv->tv_sec);
2035 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01002036 break;
2037 }
Huw Davies4bc29752014-04-17 14:02:48 +01002038 case SCM_CREDENTIALS:
2039 {
2040 struct ucred *cred = (struct ucred *)data;
2041 struct target_ucred *target_cred =
2042 (struct target_ucred *)target_data;
2043
2044 __put_user(cred->pid, &target_cred->pid);
2045 __put_user(cred->uid, &target_cred->uid);
2046 __put_user(cred->gid, &target_cred->gid);
2047 break;
2048 }
Huw Davies52b65492014-04-17 14:02:47 +01002049 default:
2050 goto unimplemented;
2051 }
2052 break;
2053
Helge Delleree1ac3a2017-02-18 23:31:30 +01002054 case SOL_IP:
2055 switch (cmsg->cmsg_type) {
2056 case IP_TTL:
2057 {
2058 uint32_t *v = (uint32_t *)data;
2059 uint32_t *t_int = (uint32_t *)target_data;
2060
Peter Maydell71749702017-12-15 13:52:55 +00002061 if (len != sizeof(uint32_t) ||
2062 tgt_len != sizeof(uint32_t)) {
2063 goto unimplemented;
2064 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002065 __put_user(*v, t_int);
2066 break;
2067 }
2068 case IP_RECVERR:
2069 {
2070 struct errhdr_t {
2071 struct sock_extended_err ee;
2072 struct sockaddr_in offender;
2073 };
2074 struct errhdr_t *errh = (struct errhdr_t *)data;
2075 struct errhdr_t *target_errh =
2076 (struct errhdr_t *)target_data;
2077
Peter Maydell71749702017-12-15 13:52:55 +00002078 if (len != sizeof(struct errhdr_t) ||
2079 tgt_len != sizeof(struct errhdr_t)) {
2080 goto unimplemented;
2081 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002082 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
2083 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
2084 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
2085 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
2086 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
2087 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
2088 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
2089 host_to_target_sockaddr((unsigned long) &target_errh->offender,
2090 (void *) &errh->offender, sizeof(errh->offender));
2091 break;
2092 }
2093 default:
2094 goto unimplemented;
2095 }
2096 break;
2097
2098 case SOL_IPV6:
2099 switch (cmsg->cmsg_type) {
2100 case IPV6_HOPLIMIT:
2101 {
2102 uint32_t *v = (uint32_t *)data;
2103 uint32_t *t_int = (uint32_t *)target_data;
2104
Peter Maydell71749702017-12-15 13:52:55 +00002105 if (len != sizeof(uint32_t) ||
2106 tgt_len != sizeof(uint32_t)) {
2107 goto unimplemented;
2108 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002109 __put_user(*v, t_int);
2110 break;
2111 }
2112 case IPV6_RECVERR:
2113 {
2114 struct errhdr6_t {
2115 struct sock_extended_err ee;
2116 struct sockaddr_in6 offender;
2117 };
2118 struct errhdr6_t *errh = (struct errhdr6_t *)data;
2119 struct errhdr6_t *target_errh =
2120 (struct errhdr6_t *)target_data;
2121
Peter Maydell71749702017-12-15 13:52:55 +00002122 if (len != sizeof(struct errhdr6_t) ||
2123 tgt_len != sizeof(struct errhdr6_t)) {
2124 goto unimplemented;
2125 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002126 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
2127 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
2128 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
2129 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
2130 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
2131 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
2132 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
2133 host_to_target_sockaddr((unsigned long) &target_errh->offender,
2134 (void *) &errh->offender, sizeof(errh->offender));
2135 break;
2136 }
2137 default:
2138 goto unimplemented;
2139 }
2140 break;
2141
Huw Davies52b65492014-04-17 14:02:47 +01002142 default:
2143 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08002144 qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
2145 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002146 memcpy(target_data, data, MIN(len, tgt_len));
2147 if (tgt_len > len) {
2148 memset(target_data + len, 0, tgt_len - len);
2149 }
bellard7854b052003-03-29 17:22:23 +00002150 }
2151
Peter Maydell71749702017-12-15 13:52:55 +00002152 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
2153 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002154 if (msg_controllen < tgt_space) {
2155 tgt_space = msg_controllen;
2156 }
2157 msg_controllen -= tgt_space;
2158 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00002159 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02002160 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
2161 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00002162 }
bellard5a4a8982007-11-11 17:39:18 +00002163 unlock_user(target_cmsg, target_cmsg_addr, space);
2164 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002165 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00002166 return 0;
bellard7854b052003-03-29 17:22:23 +00002167}
2168
ths0da46a62007-10-20 20:23:07 +00002169/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002170static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002171 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002172{
blueswir1992f48a2007-10-14 16:27:31 +00002173 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002174 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002175 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002176 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002177
bellard8853f862004-02-22 14:57:26 +00002178 switch(level) {
2179 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002180 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002181 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002182 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002183
bellard2f619692007-11-16 10:46:05 +00002184 if (get_user_u32(val, optval_addr))
2185 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002186 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2187 break;
2188 case SOL_IP:
2189 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002190 case IP_TOS:
2191 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002192 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002193 case IP_ROUTER_ALERT:
2194 case IP_RECVOPTS:
2195 case IP_RETOPTS:
2196 case IP_PKTINFO:
2197 case IP_MTU_DISCOVER:
2198 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002199 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002200 case IP_RECVTOS:
2201#ifdef IP_FREEBIND
2202 case IP_FREEBIND:
2203#endif
2204 case IP_MULTICAST_TTL:
2205 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002206 val = 0;
2207 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002208 if (get_user_u32(val, optval_addr))
2209 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002210 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002211 if (get_user_u8(val, optval_addr))
2212 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002213 }
2214 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2215 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002216 case IP_ADD_MEMBERSHIP:
2217 case IP_DROP_MEMBERSHIP:
2218 if (optlen < sizeof (struct target_ip_mreq) ||
2219 optlen > sizeof (struct target_ip_mreqn))
2220 return -TARGET_EINVAL;
2221
2222 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2223 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2224 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2225 break;
2226
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002227 case IP_BLOCK_SOURCE:
2228 case IP_UNBLOCK_SOURCE:
2229 case IP_ADD_SOURCE_MEMBERSHIP:
2230 case IP_DROP_SOURCE_MEMBERSHIP:
2231 if (optlen != sizeof (struct target_ip_mreq_source))
2232 return -TARGET_EINVAL;
2233
2234 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2235 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2236 unlock_user (ip_mreq_source, optval_addr, 0);
2237 break;
2238
bellard8853f862004-02-22 14:57:26 +00002239 default:
2240 goto unimplemented;
2241 }
2242 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002243 case SOL_IPV6:
2244 switch (optname) {
2245 case IPV6_MTU_DISCOVER:
2246 case IPV6_MTU:
2247 case IPV6_V6ONLY:
2248 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002249 case IPV6_UNICAST_HOPS:
Laurent Vivier21749c42018-06-27 23:21:52 +02002250 case IPV6_MULTICAST_HOPS:
2251 case IPV6_MULTICAST_LOOP:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002252 case IPV6_RECVERR:
2253 case IPV6_RECVHOPLIMIT:
2254 case IPV6_2292HOPLIMIT:
2255 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002256 case IPV6_ADDRFORM:
2257 case IPV6_2292PKTINFO:
2258 case IPV6_RECVTCLASS:
2259 case IPV6_RECVRTHDR:
2260 case IPV6_2292RTHDR:
2261 case IPV6_RECVHOPOPTS:
2262 case IPV6_2292HOPOPTS:
2263 case IPV6_RECVDSTOPTS:
2264 case IPV6_2292DSTOPTS:
2265 case IPV6_TCLASS:
2266#ifdef IPV6_RECVPATHMTU
2267 case IPV6_RECVPATHMTU:
2268#endif
2269#ifdef IPV6_TRANSPARENT
2270 case IPV6_TRANSPARENT:
2271#endif
2272#ifdef IPV6_FREEBIND
2273 case IPV6_FREEBIND:
2274#endif
2275#ifdef IPV6_RECVORIGDSTADDR
2276 case IPV6_RECVORIGDSTADDR:
2277#endif
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002278 val = 0;
2279 if (optlen < sizeof(uint32_t)) {
2280 return -TARGET_EINVAL;
2281 }
2282 if (get_user_u32(val, optval_addr)) {
2283 return -TARGET_EFAULT;
2284 }
2285 ret = get_errno(setsockopt(sockfd, level, optname,
2286 &val, sizeof(val)));
2287 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002288 case IPV6_PKTINFO:
2289 {
2290 struct in6_pktinfo pki;
2291
2292 if (optlen < sizeof(pki)) {
2293 return -TARGET_EINVAL;
2294 }
2295
2296 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2297 return -TARGET_EFAULT;
2298 }
2299
2300 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2301
2302 ret = get_errno(setsockopt(sockfd, level, optname,
2303 &pki, sizeof(pki)));
2304 break;
2305 }
Neng Chen22bf4ee2019-06-19 16:17:10 +02002306 case IPV6_ADD_MEMBERSHIP:
2307 case IPV6_DROP_MEMBERSHIP:
2308 {
2309 struct ipv6_mreq ipv6mreq;
2310
2311 if (optlen < sizeof(ipv6mreq)) {
2312 return -TARGET_EINVAL;
2313 }
2314
2315 if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) {
2316 return -TARGET_EFAULT;
2317 }
2318
2319 ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface);
2320
2321 ret = get_errno(setsockopt(sockfd, level, optname,
2322 &ipv6mreq, sizeof(ipv6mreq)));
2323 break;
2324 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002325 default:
2326 goto unimplemented;
2327 }
2328 break;
2329 case SOL_ICMPV6:
2330 switch (optname) {
2331 case ICMPV6_FILTER:
2332 {
2333 struct icmp6_filter icmp6f;
2334
2335 if (optlen > sizeof(icmp6f)) {
2336 optlen = sizeof(icmp6f);
2337 }
2338
2339 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
2340 return -TARGET_EFAULT;
2341 }
2342
2343 for (val = 0; val < 8; val++) {
2344 icmp6f.data[val] = tswap32(icmp6f.data[val]);
2345 }
2346
2347 ret = get_errno(setsockopt(sockfd, level, optname,
2348 &icmp6f, optlen));
2349 break;
2350 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002351 default:
2352 goto unimplemented;
2353 }
2354 break;
Jing Huang920394d2012-07-24 13:59:23 +00002355 case SOL_RAW:
2356 switch (optname) {
2357 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002358 case IPV6_CHECKSUM:
2359 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00002360 if (optlen < sizeof(uint32_t)) {
2361 return -TARGET_EINVAL;
2362 }
2363
2364 if (get_user_u32(val, optval_addr)) {
2365 return -TARGET_EFAULT;
2366 }
2367 ret = get_errno(setsockopt(sockfd, level, optname,
2368 &val, sizeof(val)));
2369 break;
2370
2371 default:
2372 goto unimplemented;
2373 }
2374 break;
Yunqiang Suf31dddd2019-06-19 16:17:11 +02002375#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE)
2376 case SOL_ALG:
2377 switch (optname) {
2378 case ALG_SET_KEY:
2379 {
2380 char *alg_key = g_malloc(optlen);
2381
2382 if (!alg_key) {
2383 return -TARGET_ENOMEM;
2384 }
2385 if (copy_from_user(alg_key, optval_addr, optlen)) {
2386 g_free(alg_key);
2387 return -TARGET_EFAULT;
2388 }
2389 ret = get_errno(setsockopt(sockfd, level, optname,
2390 alg_key, optlen));
2391 g_free(alg_key);
2392 break;
2393 }
2394 case ALG_SET_AEAD_AUTHSIZE:
2395 {
2396 ret = get_errno(setsockopt(sockfd, level, optname,
2397 NULL, optlen));
2398 break;
2399 }
2400 default:
2401 goto unimplemented;
2402 }
2403 break;
2404#endif
bellard3532fa72006-06-24 15:06:03 +00002405 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002406 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002407 case TARGET_SO_RCVTIMEO:
2408 {
2409 struct timeval tv;
2410
2411 optname = SO_RCVTIMEO;
2412
2413set_timeout:
2414 if (optlen != sizeof(struct target_timeval)) {
2415 return -TARGET_EINVAL;
2416 }
2417
2418 if (copy_from_user_timeval(&tv, optval_addr)) {
2419 return -TARGET_EFAULT;
2420 }
2421
2422 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2423 &tv, sizeof(tv)));
2424 return ret;
2425 }
2426 case TARGET_SO_SNDTIMEO:
2427 optname = SO_SNDTIMEO;
2428 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002429 case TARGET_SO_ATTACH_FILTER:
2430 {
2431 struct target_sock_fprog *tfprog;
2432 struct target_sock_filter *tfilter;
2433 struct sock_fprog fprog;
2434 struct sock_filter *filter;
2435 int i;
2436
2437 if (optlen != sizeof(*tfprog)) {
2438 return -TARGET_EINVAL;
2439 }
2440 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2441 return -TARGET_EFAULT;
2442 }
2443 if (!lock_user_struct(VERIFY_READ, tfilter,
2444 tswapal(tfprog->filter), 0)) {
2445 unlock_user_struct(tfprog, optval_addr, 1);
2446 return -TARGET_EFAULT;
2447 }
2448
2449 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302450 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002451 if (filter == NULL) {
2452 unlock_user_struct(tfilter, tfprog->filter, 1);
2453 unlock_user_struct(tfprog, optval_addr, 1);
2454 return -TARGET_ENOMEM;
2455 }
2456 for (i = 0; i < fprog.len; i++) {
2457 filter[i].code = tswap16(tfilter[i].code);
2458 filter[i].jt = tfilter[i].jt;
2459 filter[i].jf = tfilter[i].jf;
2460 filter[i].k = tswap32(tfilter[i].k);
2461 }
2462 fprog.filter = filter;
2463
2464 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2465 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302466 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002467
2468 unlock_user_struct(tfilter, tfprog->filter, 1);
2469 unlock_user_struct(tfprog, optval_addr, 1);
2470 return ret;
2471 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002472 case TARGET_SO_BINDTODEVICE:
2473 {
2474 char *dev_ifname, *addr_ifname;
2475
2476 if (optlen > IFNAMSIZ - 1) {
2477 optlen = IFNAMSIZ - 1;
2478 }
2479 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2480 if (!dev_ifname) {
2481 return -TARGET_EFAULT;
2482 }
2483 optname = SO_BINDTODEVICE;
2484 addr_ifname = alloca(IFNAMSIZ);
2485 memcpy(addr_ifname, dev_ifname, optlen);
2486 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002487 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2488 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002489 unlock_user (dev_ifname, optval_addr, 0);
2490 return ret;
2491 }
Carlo Marcelo Arenas BelĂłn83eb6e52018-08-24 01:56:01 -07002492 case TARGET_SO_LINGER:
2493 {
2494 struct linger lg;
2495 struct target_linger *tlg;
2496
2497 if (optlen != sizeof(struct target_linger)) {
2498 return -TARGET_EINVAL;
2499 }
2500 if (!lock_user_struct(VERIFY_READ, tlg, optval_addr, 1)) {
2501 return -TARGET_EFAULT;
2502 }
2503 __get_user(lg.l_onoff, &tlg->l_onoff);
2504 __get_user(lg.l_linger, &tlg->l_linger);
2505 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
2506 &lg, sizeof(lg)));
2507 unlock_user_struct(tlg, optval_addr, 0);
2508 return ret;
2509 }
bellard8853f862004-02-22 14:57:26 +00002510 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002511 case TARGET_SO_DEBUG:
2512 optname = SO_DEBUG;
2513 break;
2514 case TARGET_SO_REUSEADDR:
2515 optname = SO_REUSEADDR;
2516 break;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002517#ifdef SO_REUSEPORT
2518 case TARGET_SO_REUSEPORT:
2519 optname = SO_REUSEPORT;
2520 break;
2521#endif
bellard3532fa72006-06-24 15:06:03 +00002522 case TARGET_SO_TYPE:
2523 optname = SO_TYPE;
2524 break;
2525 case TARGET_SO_ERROR:
2526 optname = SO_ERROR;
2527 break;
2528 case TARGET_SO_DONTROUTE:
2529 optname = SO_DONTROUTE;
2530 break;
2531 case TARGET_SO_BROADCAST:
2532 optname = SO_BROADCAST;
2533 break;
2534 case TARGET_SO_SNDBUF:
2535 optname = SO_SNDBUF;
2536 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002537 case TARGET_SO_SNDBUFFORCE:
2538 optname = SO_SNDBUFFORCE;
2539 break;
bellard3532fa72006-06-24 15:06:03 +00002540 case TARGET_SO_RCVBUF:
2541 optname = SO_RCVBUF;
2542 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002543 case TARGET_SO_RCVBUFFORCE:
2544 optname = SO_RCVBUFFORCE;
2545 break;
bellard3532fa72006-06-24 15:06:03 +00002546 case TARGET_SO_KEEPALIVE:
2547 optname = SO_KEEPALIVE;
2548 break;
2549 case TARGET_SO_OOBINLINE:
2550 optname = SO_OOBINLINE;
2551 break;
2552 case TARGET_SO_NO_CHECK:
2553 optname = SO_NO_CHECK;
2554 break;
2555 case TARGET_SO_PRIORITY:
2556 optname = SO_PRIORITY;
2557 break;
bellard5e83e8e2005-03-01 22:32:06 +00002558#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002559 case TARGET_SO_BSDCOMPAT:
2560 optname = SO_BSDCOMPAT;
2561 break;
bellard5e83e8e2005-03-01 22:32:06 +00002562#endif
bellard3532fa72006-06-24 15:06:03 +00002563 case TARGET_SO_PASSCRED:
2564 optname = SO_PASSCRED;
2565 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002566 case TARGET_SO_PASSSEC:
2567 optname = SO_PASSSEC;
2568 break;
bellard3532fa72006-06-24 15:06:03 +00002569 case TARGET_SO_TIMESTAMP:
2570 optname = SO_TIMESTAMP;
2571 break;
2572 case TARGET_SO_RCVLOWAT:
2573 optname = SO_RCVLOWAT;
2574 break;
bellard8853f862004-02-22 14:57:26 +00002575 default:
2576 goto unimplemented;
2577 }
bellard3532fa72006-06-24 15:06:03 +00002578 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002579 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002580
bellard2f619692007-11-16 10:46:05 +00002581 if (get_user_u32(val, optval_addr))
2582 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002583 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002584 break;
Josh Kunza2d86682019-10-29 15:43:10 -07002585#ifdef SOL_NETLINK
2586 case SOL_NETLINK:
2587 switch (optname) {
2588 case NETLINK_PKTINFO:
2589 case NETLINK_ADD_MEMBERSHIP:
2590 case NETLINK_DROP_MEMBERSHIP:
2591 case NETLINK_BROADCAST_ERROR:
2592 case NETLINK_NO_ENOBUFS:
2593#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2594 case NETLINK_LISTEN_ALL_NSID:
2595 case NETLINK_CAP_ACK:
2596#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
2597#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
2598 case NETLINK_EXT_ACK:
2599#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2600#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
2601 case NETLINK_GET_STRICT_CHK:
2602#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2603 break;
2604 default:
2605 goto unimplemented;
2606 }
2607 val = 0;
2608 if (optlen < sizeof(uint32_t)) {
2609 return -TARGET_EINVAL;
2610 }
2611 if (get_user_u32(val, optval_addr)) {
2612 return -TARGET_EFAULT;
2613 }
2614 ret = get_errno(setsockopt(sockfd, SOL_NETLINK, optname, &val,
2615 sizeof(val)));
2616 break;
2617#endif /* SOL_NETLINK */
bellard7854b052003-03-29 17:22:23 +00002618 default:
bellard8853f862004-02-22 14:57:26 +00002619 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08002620 qemu_log_mask(LOG_UNIMP, "Unsupported setsockopt level=%d optname=%d\n",
2621 level, optname);
ths6fa13c12007-12-18 02:41:04 +00002622 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002623 }
bellard8853f862004-02-22 14:57:26 +00002624 return ret;
bellard7854b052003-03-29 17:22:23 +00002625}
2626
ths0da46a62007-10-20 20:23:07 +00002627/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002628static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002629 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002630{
blueswir1992f48a2007-10-14 16:27:31 +00002631 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002632 int len, val;
2633 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002634
2635 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002636 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002637 level = SOL_SOCKET;
2638 switch (optname) {
2639 /* These don't just return a single integer */
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002640 case TARGET_SO_PEERNAME:
2641 goto unimplemented;
Andreas Schwab405dc4c2019-05-13 11:06:26 +02002642 case TARGET_SO_RCVTIMEO: {
2643 struct timeval tv;
2644 socklen_t tvlen;
2645
2646 optname = SO_RCVTIMEO;
2647
2648get_timeout:
2649 if (get_user_u32(len, optlen)) {
2650 return -TARGET_EFAULT;
2651 }
2652 if (len < 0) {
2653 return -TARGET_EINVAL;
2654 }
2655
2656 tvlen = sizeof(tv);
2657 ret = get_errno(getsockopt(sockfd, level, optname,
2658 &tv, &tvlen));
2659 if (ret < 0) {
2660 return ret;
2661 }
2662 if (len > sizeof(struct target_timeval)) {
2663 len = sizeof(struct target_timeval);
2664 }
2665 if (copy_to_user_timeval(optval_addr, &tv)) {
2666 return -TARGET_EFAULT;
2667 }
2668 if (put_user_u32(len, optlen)) {
2669 return -TARGET_EFAULT;
2670 }
2671 break;
2672 }
2673 case TARGET_SO_SNDTIMEO:
2674 optname = SO_SNDTIMEO;
2675 goto get_timeout;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002676 case TARGET_SO_PEERCRED: {
2677 struct ucred cr;
2678 socklen_t crlen;
2679 struct target_ucred *tcr;
2680
2681 if (get_user_u32(len, optlen)) {
2682 return -TARGET_EFAULT;
2683 }
2684 if (len < 0) {
2685 return -TARGET_EINVAL;
2686 }
2687
2688 crlen = sizeof(cr);
2689 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2690 &cr, &crlen));
2691 if (ret < 0) {
2692 return ret;
2693 }
2694 if (len > crlen) {
2695 len = crlen;
2696 }
2697 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2698 return -TARGET_EFAULT;
2699 }
2700 __put_user(cr.pid, &tcr->pid);
2701 __put_user(cr.uid, &tcr->uid);
2702 __put_user(cr.gid, &tcr->gid);
2703 unlock_user_struct(tcr, optval_addr, 1);
2704 if (put_user_u32(len, optlen)) {
2705 return -TARGET_EFAULT;
2706 }
2707 break;
2708 }
Laurent Vivier6d485a52020-02-04 22:19:01 +01002709 case TARGET_SO_PEERSEC: {
2710 char *name;
2711
2712 if (get_user_u32(len, optlen)) {
2713 return -TARGET_EFAULT;
2714 }
2715 if (len < 0) {
2716 return -TARGET_EINVAL;
2717 }
2718 name = lock_user(VERIFY_WRITE, optval_addr, len, 0);
2719 if (!name) {
2720 return -TARGET_EFAULT;
2721 }
2722 lv = len;
2723 ret = get_errno(getsockopt(sockfd, level, SO_PEERSEC,
2724 name, &lv));
2725 if (put_user_u32(lv, optlen)) {
2726 ret = -TARGET_EFAULT;
2727 }
2728 unlock_user(name, optval_addr, lv);
2729 break;
2730 }
Carlo Marcelo Arenas BelĂłn83eb6e52018-08-24 01:56:01 -07002731 case TARGET_SO_LINGER:
2732 {
2733 struct linger lg;
2734 socklen_t lglen;
2735 struct target_linger *tlg;
2736
2737 if (get_user_u32(len, optlen)) {
2738 return -TARGET_EFAULT;
2739 }
2740 if (len < 0) {
2741 return -TARGET_EINVAL;
2742 }
2743
2744 lglen = sizeof(lg);
2745 ret = get_errno(getsockopt(sockfd, level, SO_LINGER,
2746 &lg, &lglen));
2747 if (ret < 0) {
2748 return ret;
2749 }
2750 if (len > lglen) {
2751 len = lglen;
2752 }
2753 if (!lock_user_struct(VERIFY_WRITE, tlg, optval_addr, 0)) {
2754 return -TARGET_EFAULT;
2755 }
2756 __put_user(lg.l_onoff, &tlg->l_onoff);
2757 __put_user(lg.l_linger, &tlg->l_linger);
2758 unlock_user_struct(tlg, optval_addr, 1);
2759 if (put_user_u32(len, optlen)) {
2760 return -TARGET_EFAULT;
2761 }
2762 break;
2763 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002764 /* Options with 'int' argument. */
2765 case TARGET_SO_DEBUG:
2766 optname = SO_DEBUG;
2767 goto int_case;
2768 case TARGET_SO_REUSEADDR:
2769 optname = SO_REUSEADDR;
2770 goto int_case;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002771#ifdef SO_REUSEPORT
2772 case TARGET_SO_REUSEPORT:
2773 optname = SO_REUSEPORT;
2774 goto int_case;
2775#endif
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002776 case TARGET_SO_TYPE:
2777 optname = SO_TYPE;
2778 goto int_case;
2779 case TARGET_SO_ERROR:
2780 optname = SO_ERROR;
2781 goto int_case;
2782 case TARGET_SO_DONTROUTE:
2783 optname = SO_DONTROUTE;
2784 goto int_case;
2785 case TARGET_SO_BROADCAST:
2786 optname = SO_BROADCAST;
2787 goto int_case;
2788 case TARGET_SO_SNDBUF:
2789 optname = SO_SNDBUF;
2790 goto int_case;
2791 case TARGET_SO_RCVBUF:
2792 optname = SO_RCVBUF;
2793 goto int_case;
2794 case TARGET_SO_KEEPALIVE:
2795 optname = SO_KEEPALIVE;
2796 goto int_case;
2797 case TARGET_SO_OOBINLINE:
2798 optname = SO_OOBINLINE;
2799 goto int_case;
2800 case TARGET_SO_NO_CHECK:
2801 optname = SO_NO_CHECK;
2802 goto int_case;
2803 case TARGET_SO_PRIORITY:
2804 optname = SO_PRIORITY;
2805 goto int_case;
2806#ifdef SO_BSDCOMPAT
2807 case TARGET_SO_BSDCOMPAT:
2808 optname = SO_BSDCOMPAT;
2809 goto int_case;
2810#endif
2811 case TARGET_SO_PASSCRED:
2812 optname = SO_PASSCRED;
2813 goto int_case;
2814 case TARGET_SO_TIMESTAMP:
2815 optname = SO_TIMESTAMP;
2816 goto int_case;
2817 case TARGET_SO_RCVLOWAT:
2818 optname = SO_RCVLOWAT;
2819 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002820 case TARGET_SO_ACCEPTCONN:
2821 optname = SO_ACCEPTCONN;
2822 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002823 default:
bellard2efbe912005-07-23 15:10:20 +00002824 goto int_case;
2825 }
2826 break;
2827 case SOL_TCP:
2828 /* TCP options all take an 'int' value. */
2829 int_case:
bellard2f619692007-11-16 10:46:05 +00002830 if (get_user_u32(len, optlen))
2831 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002832 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002833 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002834 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002835 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2836 if (ret < 0)
2837 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002838 if (optname == SO_TYPE) {
2839 val = host_to_target_sock_type(val);
2840 }
bellard2efbe912005-07-23 15:10:20 +00002841 if (len > lv)
2842 len = lv;
bellard2f619692007-11-16 10:46:05 +00002843 if (len == 4) {
2844 if (put_user_u32(val, optval_addr))
2845 return -TARGET_EFAULT;
2846 } else {
2847 if (put_user_u8(val, optval_addr))
2848 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002849 }
bellard2f619692007-11-16 10:46:05 +00002850 if (put_user_u32(len, optlen))
2851 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002852 break;
2853 case SOL_IP:
2854 switch(optname) {
2855 case IP_TOS:
2856 case IP_TTL:
2857 case IP_HDRINCL:
2858 case IP_ROUTER_ALERT:
2859 case IP_RECVOPTS:
2860 case IP_RETOPTS:
2861 case IP_PKTINFO:
2862 case IP_MTU_DISCOVER:
2863 case IP_RECVERR:
2864 case IP_RECVTOS:
2865#ifdef IP_FREEBIND
2866 case IP_FREEBIND:
2867#endif
2868 case IP_MULTICAST_TTL:
2869 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002870 if (get_user_u32(len, optlen))
2871 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002872 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002873 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002874 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002875 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2876 if (ret < 0)
2877 return ret;
bellard2efbe912005-07-23 15:10:20 +00002878 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002879 len = 1;
bellard2f619692007-11-16 10:46:05 +00002880 if (put_user_u32(len, optlen)
2881 || put_user_u8(val, optval_addr))
2882 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002883 } else {
bellard2efbe912005-07-23 15:10:20 +00002884 if (len > sizeof(int))
2885 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002886 if (put_user_u32(len, optlen)
2887 || put_user_u32(val, optval_addr))
2888 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002889 }
bellard8853f862004-02-22 14:57:26 +00002890 break;
bellard2efbe912005-07-23 15:10:20 +00002891 default:
thsc02f4992007-12-18 02:39:59 +00002892 ret = -TARGET_ENOPROTOOPT;
2893 break;
bellard8853f862004-02-22 14:57:26 +00002894 }
2895 break;
Tom Deseynbd8ed482018-12-13 14:06:11 +01002896 case SOL_IPV6:
2897 switch (optname) {
2898 case IPV6_MTU_DISCOVER:
2899 case IPV6_MTU:
2900 case IPV6_V6ONLY:
2901 case IPV6_RECVPKTINFO:
2902 case IPV6_UNICAST_HOPS:
2903 case IPV6_MULTICAST_HOPS:
2904 case IPV6_MULTICAST_LOOP:
2905 case IPV6_RECVERR:
2906 case IPV6_RECVHOPLIMIT:
2907 case IPV6_2292HOPLIMIT:
2908 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002909 case IPV6_ADDRFORM:
2910 case IPV6_2292PKTINFO:
2911 case IPV6_RECVTCLASS:
2912 case IPV6_RECVRTHDR:
2913 case IPV6_2292RTHDR:
2914 case IPV6_RECVHOPOPTS:
2915 case IPV6_2292HOPOPTS:
2916 case IPV6_RECVDSTOPTS:
2917 case IPV6_2292DSTOPTS:
2918 case IPV6_TCLASS:
2919#ifdef IPV6_RECVPATHMTU
2920 case IPV6_RECVPATHMTU:
2921#endif
2922#ifdef IPV6_TRANSPARENT
2923 case IPV6_TRANSPARENT:
2924#endif
2925#ifdef IPV6_FREEBIND
2926 case IPV6_FREEBIND:
2927#endif
2928#ifdef IPV6_RECVORIGDSTADDR
2929 case IPV6_RECVORIGDSTADDR:
2930#endif
Tom Deseynbd8ed482018-12-13 14:06:11 +01002931 if (get_user_u32(len, optlen))
2932 return -TARGET_EFAULT;
2933 if (len < 0)
2934 return -TARGET_EINVAL;
2935 lv = sizeof(lv);
2936 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2937 if (ret < 0)
2938 return ret;
2939 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
2940 len = 1;
2941 if (put_user_u32(len, optlen)
2942 || put_user_u8(val, optval_addr))
2943 return -TARGET_EFAULT;
2944 } else {
2945 if (len > sizeof(int))
2946 len = sizeof(int);
2947 if (put_user_u32(len, optlen)
2948 || put_user_u32(val, optval_addr))
2949 return -TARGET_EFAULT;
2950 }
2951 break;
2952 default:
2953 ret = -TARGET_ENOPROTOOPT;
2954 break;
2955 }
2956 break;
Josh Kunza2d86682019-10-29 15:43:10 -07002957#ifdef SOL_NETLINK
2958 case SOL_NETLINK:
2959 switch (optname) {
2960 case NETLINK_PKTINFO:
2961 case NETLINK_BROADCAST_ERROR:
2962 case NETLINK_NO_ENOBUFS:
2963#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2964 case NETLINK_LISTEN_ALL_NSID:
2965 case NETLINK_CAP_ACK:
2966#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
2967#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
2968 case NETLINK_EXT_ACK:
2969#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2970#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
2971 case NETLINK_GET_STRICT_CHK:
2972#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2973 if (get_user_u32(len, optlen)) {
2974 return -TARGET_EFAULT;
2975 }
2976 if (len != sizeof(val)) {
2977 return -TARGET_EINVAL;
2978 }
2979 lv = len;
2980 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2981 if (ret < 0) {
2982 return ret;
2983 }
2984 if (put_user_u32(lv, optlen)
2985 || put_user_u32(val, optval_addr)) {
2986 return -TARGET_EFAULT;
2987 }
2988 break;
2989#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2990 case NETLINK_LIST_MEMBERSHIPS:
2991 {
2992 uint32_t *results;
2993 int i;
2994 if (get_user_u32(len, optlen)) {
2995 return -TARGET_EFAULT;
2996 }
2997 if (len < 0) {
2998 return -TARGET_EINVAL;
2999 }
3000 results = lock_user(VERIFY_WRITE, optval_addr, len, 1);
3001 if (!results) {
3002 return -TARGET_EFAULT;
3003 }
3004 lv = len;
3005 ret = get_errno(getsockopt(sockfd, level, optname, results, &lv));
3006 if (ret < 0) {
3007 unlock_user(results, optval_addr, 0);
3008 return ret;
3009 }
3010 /* swap host endianess to target endianess. */
3011 for (i = 0; i < (len / sizeof(uint32_t)); i++) {
3012 results[i] = tswap32(results[i]);
3013 }
3014 if (put_user_u32(lv, optlen)) {
3015 return -TARGET_EFAULT;
3016 }
3017 unlock_user(results, optval_addr, 0);
3018 break;
3019 }
3020#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
3021 default:
3022 goto unimplemented;
3023 }
Laurent Vivierc0cb8802019-11-12 11:50:55 +01003024 break;
Josh Kunza2d86682019-10-29 15:43:10 -07003025#endif /* SOL_NETLINK */
bellard8853f862004-02-22 14:57:26 +00003026 default:
3027 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08003028 qemu_log_mask(LOG_UNIMP,
3029 "getsockopt level=%d optname=%d not yet supported\n",
3030 level, optname);
thsc02f4992007-12-18 02:39:59 +00003031 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003032 break;
3033 }
3034 return ret;
bellard7854b052003-03-29 17:22:23 +00003035}
3036
Max Filippov9ac22512018-04-04 17:30:41 -07003037/* Convert target low/high pair representing file offset into the host
3038 * low/high pair. This function doesn't handle offsets bigger than 64 bits
3039 * as the kernel doesn't handle them either.
3040 */
3041static void target_to_host_low_high(abi_ulong tlow,
3042 abi_ulong thigh,
3043 unsigned long *hlow,
3044 unsigned long *hhigh)
3045{
3046 uint64_t off = tlow |
3047 ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
3048 TARGET_LONG_BITS / 2;
3049
3050 *hlow = off;
3051 *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
3052}
3053
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003054static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003055 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003056{
3057 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003058 struct iovec *vec;
3059 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003060 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003061 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003062 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003063
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003064 if (count == 0) {
3065 errno = 0;
3066 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003067 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003068 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003069 errno = EINVAL;
3070 return NULL;
3071 }
3072
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303073 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003074 if (vec == NULL) {
3075 errno = ENOMEM;
3076 return NULL;
3077 }
3078
3079 target_vec = lock_user(VERIFY_READ, target_addr,
3080 count * sizeof(struct target_iovec), 1);
3081 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003082 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003083 goto fail2;
3084 }
3085
3086 /* ??? If host page size > target page size, this will result in a
3087 value larger than what we can actually support. */
3088 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3089 total_len = 0;
3090
3091 for (i = 0; i < count; i++) {
3092 abi_ulong base = tswapal(target_vec[i].iov_base);
3093 abi_long len = tswapal(target_vec[i].iov_len);
3094
3095 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003096 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003097 goto fail;
3098 } else if (len == 0) {
3099 /* Zero length pointer is ignored. */
3100 vec[i].iov_base = 0;
3101 } else {
3102 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003103 /* If the first buffer pointer is bad, this is a fault. But
3104 * subsequent bad buffers will result in a partial write; this
3105 * is realized by filling the vector with null pointers and
3106 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003107 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003108 if (i == 0) {
3109 err = EFAULT;
3110 goto fail;
3111 } else {
3112 bad_address = true;
3113 }
3114 }
3115 if (bad_address) {
3116 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003117 }
3118 if (len > max_len - total_len) {
3119 len = max_len - total_len;
3120 }
3121 }
3122 vec[i].iov_len = len;
3123 total_len += len;
3124 }
3125
3126 unlock_user(target_vec, target_addr, 0);
3127 return vec;
3128
3129 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003130 while (--i >= 0) {
3131 if (tswapal(target_vec[i].iov_len) > 0) {
3132 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3133 }
3134 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003135 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003136 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303137 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003138 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003139 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003140}
3141
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003142static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003143 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003144{
3145 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003146 int i;
3147
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003148 target_vec = lock_user(VERIFY_READ, target_addr,
3149 count * sizeof(struct target_iovec), 1);
3150 if (target_vec) {
3151 for (i = 0; i < count; i++) {
3152 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003153 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003154 if (len < 0) {
3155 break;
3156 }
balrogd732dcb2008-10-28 10:21:03 +00003157 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3158 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003159 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003160 }
bellard579a97f2007-11-11 14:26:47 +00003161
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303162 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003163}
3164
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003165static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003166{
3167 int host_type = 0;
3168 int target_type = *type;
3169
3170 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3171 case TARGET_SOCK_DGRAM:
3172 host_type = SOCK_DGRAM;
3173 break;
3174 case TARGET_SOCK_STREAM:
3175 host_type = SOCK_STREAM;
3176 break;
3177 default:
3178 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3179 break;
3180 }
3181 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003182#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003183 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003184#else
3185 return -TARGET_EINVAL;
3186#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003187 }
3188 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003189#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003190 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003191#elif !defined(O_NONBLOCK)
3192 return -TARGET_EINVAL;
3193#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003194 }
3195 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003196 return 0;
3197}
3198
3199/* Try to emulate socket type flags after socket creation. */
3200static int sock_flags_fixup(int fd, int target_type)
3201{
3202#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3203 if (target_type & TARGET_SOCK_NONBLOCK) {
3204 int flags = fcntl(fd, F_GETFL);
3205 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3206 close(fd);
3207 return -TARGET_EINVAL;
3208 }
3209 }
3210#endif
3211 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003212}
3213
ths0da46a62007-10-20 20:23:07 +00003214/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003215static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003216{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003217 int target_type = type;
3218 int ret;
3219
3220 ret = target_to_host_sock_type(&type);
3221 if (ret) {
3222 return ret;
3223 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003224
Laurent Vivier575b22b2016-06-02 22:14:15 +02003225 if (domain == PF_NETLINK && !(
3226#ifdef CONFIG_RTNETLINK
3227 protocol == NETLINK_ROUTE ||
3228#endif
3229 protocol == NETLINK_KOBJECT_UEVENT ||
3230 protocol == NETLINK_AUDIT)) {
Josh Kunz71e24432020-07-06 17:10:36 -07003231 return -TARGET_EPROTONOSUPPORT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003232 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003233
3234 if (domain == AF_PACKET ||
3235 (domain == AF_INET && type == SOCK_PACKET)) {
3236 protocol = tswap16(protocol);
3237 }
3238
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003239 ret = get_errno(socket(domain, type, protocol));
3240 if (ret >= 0) {
3241 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003242 if (type == SOCK_PACKET) {
3243 /* Manage an obsolete case :
3244 * if socket type is SOCK_PACKET, bind by name
3245 */
3246 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003247 } else if (domain == PF_NETLINK) {
3248 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003249#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003250 case NETLINK_ROUTE:
3251 fd_trans_register(ret, &target_netlink_route_trans);
3252 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003253#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003254 case NETLINK_KOBJECT_UEVENT:
3255 /* nothing to do: messages are strings */
3256 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003257 case NETLINK_AUDIT:
3258 fd_trans_register(ret, &target_netlink_audit_trans);
3259 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003260 default:
3261 g_assert_not_reached();
3262 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003263 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003264 }
3265 return ret;
bellard3532fa72006-06-24 15:06:03 +00003266}
3267
ths0da46a62007-10-20 20:23:07 +00003268/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003269static abi_long do_bind(int sockfd, abi_ulong target_addr,
3270 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003271{
aurel328f7aeaf2009-01-30 19:47:57 +00003272 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003273 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003274
Blue Swirl38724252010-09-18 05:53:14 +00003275 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003276 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003277 }
aurel328f7aeaf2009-01-30 19:47:57 +00003278
aurel32607175e2009-04-15 16:11:59 +00003279 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003280
Laurent Vivier7b36f782015-10-28 21:40:44 +01003281 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003282 if (ret)
3283 return ret;
3284
bellard3532fa72006-06-24 15:06:03 +00003285 return get_errno(bind(sockfd, addr, addrlen));
3286}
3287
ths0da46a62007-10-20 20:23:07 +00003288/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003289static abi_long do_connect(int sockfd, abi_ulong target_addr,
3290 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003291{
aurel328f7aeaf2009-01-30 19:47:57 +00003292 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003293 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003294
Blue Swirl38724252010-09-18 05:53:14 +00003295 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003296 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003297 }
aurel328f7aeaf2009-01-30 19:47:57 +00003298
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003299 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003300
Laurent Vivier7b36f782015-10-28 21:40:44 +01003301 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003302 if (ret)
3303 return ret;
3304
Peter Maydell2a3c7612016-06-06 19:58:03 +01003305 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003306}
3307
Alexander Graff19e00d2014-03-02 19:36:42 +00003308/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3309static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3310 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003311{
balrog6de645c2008-10-28 10:26:29 +00003312 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003313 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003314 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003315 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003316 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003317
bellard3532fa72006-06-24 15:06:03 +00003318 if (msgp->msg_name) {
3319 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003320 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003321 ret = target_to_host_sockaddr(fd, msg.msg_name,
3322 tswapal(msgp->msg_name),
3323 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003324 if (ret == -TARGET_EFAULT) {
3325 /* For connected sockets msg_name and msg_namelen must
3326 * be ignored, so returning EFAULT immediately is wrong.
3327 * Instead, pass a bad msg_name to the host kernel, and
3328 * let it decide whether to return EFAULT or not.
3329 */
3330 msg.msg_name = (void *)-1;
3331 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003332 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003333 }
bellard3532fa72006-06-24 15:06:03 +00003334 } else {
3335 msg.msg_name = NULL;
3336 msg.msg_namelen = 0;
3337 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003338 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003339 msg.msg_control = alloca(msg.msg_controllen);
Jonas Schievink1d3d1b22018-07-12 00:12:44 +02003340 memset(msg.msg_control, 0, msg.msg_controllen);
3341
bellard3532fa72006-06-24 15:06:03 +00003342 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003343
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003344 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003345 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003346
3347 if (count > IOV_MAX) {
3348 /* sendrcvmsg returns a different errno for this condition than
3349 * readv/writev, so we must catch it here before lock_iovec() does.
3350 */
3351 ret = -TARGET_EMSGSIZE;
3352 goto out2;
3353 }
3354
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003355 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3356 target_vec, count, send);
3357 if (vec == NULL) {
3358 ret = -host_to_target_errno(errno);
3359 goto out2;
3360 }
bellard3532fa72006-06-24 15:06:03 +00003361 msg.msg_iovlen = count;
3362 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003363
bellard3532fa72006-06-24 15:06:03 +00003364 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003365 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003366 void *host_msg;
3367
3368 host_msg = g_malloc(msg.msg_iov->iov_len);
3369 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3370 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003371 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003372 if (ret >= 0) {
3373 msg.msg_iov->iov_base = host_msg;
3374 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3375 }
3376 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003377 } else {
3378 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003379 if (ret == 0) {
3380 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3381 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003382 }
bellard3532fa72006-06-24 15:06:03 +00003383 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003384 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003385 if (!is_error(ret)) {
3386 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003387 if (fd_trans_host_to_target_data(fd)) {
3388 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02003389 MIN(msg.msg_iov->iov_len, len));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003390 } else {
3391 ret = host_to_target_cmsg(msgp, &msg);
3392 }
Jing Huangca619062012-07-24 13:58:02 +00003393 if (!is_error(ret)) {
3394 msgp->msg_namelen = tswap32(msg.msg_namelen);
Andreas Schwab24894f32019-02-12 17:34:35 +01003395 msgp->msg_flags = tswap32(msg.msg_flags);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003396 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003397 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3398 msg.msg_name, msg.msg_namelen);
3399 if (ret) {
3400 goto out;
3401 }
3402 }
3403
balrog6de645c2008-10-28 10:26:29 +00003404 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003405 }
balrog6de645c2008-10-28 10:26:29 +00003406 }
bellard3532fa72006-06-24 15:06:03 +00003407 }
Jing Huangca619062012-07-24 13:58:02 +00003408
3409out:
bellard3532fa72006-06-24 15:06:03 +00003410 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003411out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003412 return ret;
3413}
3414
3415static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3416 int flags, int send)
3417{
3418 abi_long ret;
3419 struct target_msghdr *msgp;
3420
3421 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3422 msgp,
3423 target_msg,
3424 send ? 1 : 0)) {
3425 return -TARGET_EFAULT;
3426 }
3427 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003428 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003429 return ret;
3430}
3431
Alexander Graff19e00d2014-03-02 19:36:42 +00003432/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3433 * so it might not have this *mmsg-specific flag either.
3434 */
3435#ifndef MSG_WAITFORONE
3436#define MSG_WAITFORONE 0x10000
3437#endif
3438
3439static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3440 unsigned int vlen, unsigned int flags,
3441 int send)
3442{
3443 struct target_mmsghdr *mmsgp;
3444 abi_long ret = 0;
3445 int i;
3446
3447 if (vlen > UIO_MAXIOV) {
3448 vlen = UIO_MAXIOV;
3449 }
3450
3451 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3452 if (!mmsgp) {
3453 return -TARGET_EFAULT;
3454 }
3455
3456 for (i = 0; i < vlen; i++) {
3457 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3458 if (is_error(ret)) {
3459 break;
3460 }
3461 mmsgp[i].msg_len = tswap32(ret);
3462 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3463 if (flags & MSG_WAITFORONE) {
3464 flags |= MSG_DONTWAIT;
3465 }
3466 }
3467
3468 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3469
3470 /* Return number of datagrams sent if we sent any at all;
3471 * otherwise return the error.
3472 */
3473 if (i) {
3474 return i;
3475 }
3476 return ret;
3477}
Alexander Graff19e00d2014-03-02 19:36:42 +00003478
Peter Maydella94b4982013-02-08 04:35:04 +00003479/* do_accept4() Must return target values and target errnos. */
3480static abi_long do_accept4(int fd, abi_ulong target_addr,
3481 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003482{
Andreas Schwabcd813362019-02-14 12:43:40 +01003483 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003484 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003485 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003486 int host_flags;
3487
3488 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003489
Peter Maydella94b4982013-02-08 04:35:04 +00003490 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003491 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003492 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003493
3494 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003495 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003496 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003497
Blue Swirl38724252010-09-18 05:53:14 +00003498 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003499 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003500 }
aurel328f7aeaf2009-01-30 19:47:57 +00003501
Arnaud Patard917507b2009-06-19 10:44:45 +03003502 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3503 return -TARGET_EINVAL;
3504
bellard2f619692007-11-16 10:46:05 +00003505 addr = alloca(addrlen);
3506
Andreas Schwabcd813362019-02-14 12:43:40 +01003507 ret_addrlen = addrlen;
3508 ret = get_errno(safe_accept4(fd, addr, &ret_addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003509 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003510 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3511 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003512 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003513 }
pbrook1be9e1d2006-11-19 15:26:04 +00003514 }
3515 return ret;
3516}
3517
ths0da46a62007-10-20 20:23:07 +00003518/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003519static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003520 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003521{
Andreas Schwabcd813362019-02-14 12:43:40 +01003522 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003523 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003524 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003525
bellard2f619692007-11-16 10:46:05 +00003526 if (get_user_u32(addrlen, target_addrlen_addr))
3527 return -TARGET_EFAULT;
3528
Blue Swirl38724252010-09-18 05:53:14 +00003529 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003530 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003531 }
aurel328f7aeaf2009-01-30 19:47:57 +00003532
Arnaud Patard917507b2009-06-19 10:44:45 +03003533 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3534 return -TARGET_EFAULT;
3535
bellard2f619692007-11-16 10:46:05 +00003536 addr = alloca(addrlen);
3537
Andreas Schwabcd813362019-02-14 12:43:40 +01003538 ret_addrlen = addrlen;
3539 ret = get_errno(getpeername(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003540 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003541 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3542 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003543 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003544 }
pbrook1be9e1d2006-11-19 15:26:04 +00003545 }
3546 return ret;
3547}
3548
ths0da46a62007-10-20 20:23:07 +00003549/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003550static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003551 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003552{
Andreas Schwabcd813362019-02-14 12:43:40 +01003553 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003554 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003555 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003556
bellard2f619692007-11-16 10:46:05 +00003557 if (get_user_u32(addrlen, target_addrlen_addr))
3558 return -TARGET_EFAULT;
3559
Blue Swirl38724252010-09-18 05:53:14 +00003560 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003561 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003562 }
aurel328f7aeaf2009-01-30 19:47:57 +00003563
Arnaud Patard917507b2009-06-19 10:44:45 +03003564 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3565 return -TARGET_EFAULT;
3566
bellard2f619692007-11-16 10:46:05 +00003567 addr = alloca(addrlen);
3568
Andreas Schwabcd813362019-02-14 12:43:40 +01003569 ret_addrlen = addrlen;
3570 ret = get_errno(getsockname(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003571 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003572 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3573 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003574 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003575 }
pbrook1be9e1d2006-11-19 15:26:04 +00003576 }
3577 return ret;
3578}
3579
ths0da46a62007-10-20 20:23:07 +00003580/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003581static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003582 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003583{
3584 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003585 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003586
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003587 target_to_host_sock_type(&type);
3588
pbrook1be9e1d2006-11-19 15:26:04 +00003589 ret = get_errno(socketpair(domain, type, protocol, tab));
3590 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003591 if (put_user_s32(tab[0], target_tab_addr)
3592 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3593 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003594 }
3595 return ret;
3596}
3597
ths0da46a62007-10-20 20:23:07 +00003598/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003599static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3600 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003601{
3602 void *addr;
3603 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003604 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003605 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003606
Blue Swirl38724252010-09-18 05:53:14 +00003607 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003608 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003609 }
aurel328f7aeaf2009-01-30 19:47:57 +00003610
bellard579a97f2007-11-11 14:26:47 +00003611 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3612 if (!host_msg)
3613 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003614 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003615 copy_msg = host_msg;
3616 host_msg = g_malloc(len);
3617 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003618 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3619 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003620 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003621 }
3622 }
pbrook1be9e1d2006-11-19 15:26:04 +00003623 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003624 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003625 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003626 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003627 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003628 }
Peter Maydell66687532016-06-06 19:58:04 +01003629 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003630 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003631 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003632 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003633fail:
3634 if (copy_msg) {
3635 g_free(host_msg);
3636 host_msg = copy_msg;
3637 }
pbrook1be9e1d2006-11-19 15:26:04 +00003638 unlock_user(host_msg, msg, 0);
3639 return ret;
3640}
3641
ths0da46a62007-10-20 20:23:07 +00003642/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003643static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3644 abi_ulong target_addr,
3645 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003646{
Andreas Schwabcd813362019-02-14 12:43:40 +01003647 socklen_t addrlen, ret_addrlen;
pbrook1be9e1d2006-11-19 15:26:04 +00003648 void *addr;
3649 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003650 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003651
bellard579a97f2007-11-11 14:26:47 +00003652 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3653 if (!host_msg)
3654 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003655 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003656 if (get_user_u32(addrlen, target_addrlen)) {
3657 ret = -TARGET_EFAULT;
3658 goto fail;
3659 }
Blue Swirl38724252010-09-18 05:53:14 +00003660 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003661 ret = -TARGET_EINVAL;
3662 goto fail;
3663 }
pbrook1be9e1d2006-11-19 15:26:04 +00003664 addr = alloca(addrlen);
Andreas Schwabcd813362019-02-14 12:43:40 +01003665 ret_addrlen = addrlen;
Peter Maydell66687532016-06-06 19:58:04 +01003666 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
Andreas Schwabcd813362019-02-14 12:43:40 +01003667 addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003668 } else {
3669 addr = NULL; /* To keep compiler quiet. */
Andreas Schwabcd813362019-02-14 12:43:40 +01003670 addrlen = 0; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003671 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003672 }
3673 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003674 if (fd_trans_host_to_target_data(fd)) {
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02003675 abi_long trans;
3676 trans = fd_trans_host_to_target_data(fd)(host_msg, MIN(ret, len));
3677 if (is_error(trans)) {
3678 ret = trans;
3679 goto fail;
3680 }
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003681 }
pbrook1be9e1d2006-11-19 15:26:04 +00003682 if (target_addr) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003683 host_to_target_sockaddr(target_addr, addr,
3684 MIN(addrlen, ret_addrlen));
3685 if (put_user_u32(ret_addrlen, target_addrlen)) {
bellard2f619692007-11-16 10:46:05 +00003686 ret = -TARGET_EFAULT;
3687 goto fail;
3688 }
pbrook1be9e1d2006-11-19 15:26:04 +00003689 }
3690 unlock_user(host_msg, msg, len);
3691 } else {
bellard2f619692007-11-16 10:46:05 +00003692fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003693 unlock_user(host_msg, msg, 0);
3694 }
3695 return ret;
3696}
3697
j_mayer32407102007-09-26 23:01:49 +00003698#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003699/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003700static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003701{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003702 static const unsigned nargs[] = { /* number of arguments per operation */
3703 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
3704 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
3705 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
3706 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
3707 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
3708 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
3709 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
3710 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
3711 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
3712 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
3713 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
3714 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
3715 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
3716 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3717 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3718 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
3719 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
3720 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
3721 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
3722 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003723 };
3724 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003725 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00003726
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003727 /* check the range of the first argument num */
3728 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
3729 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
3730 return -TARGET_EINVAL;
3731 }
3732 /* ensure we have space for args */
3733 if (nargs[num] > ARRAY_SIZE(a)) {
3734 return -TARGET_EINVAL;
3735 }
3736 /* collect the arguments in a[] according to nargs[] */
3737 for (i = 0; i < nargs[num]; ++i) {
3738 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
3739 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01003740 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003741 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003742 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003743 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003744 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003745 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003746 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003747 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003748 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003749 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003750 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003751 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003752 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003753 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003754 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003755 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003756 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003757 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003758 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003759 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003760 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003761 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003762 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003763 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003764 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003765 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003766 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003767 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003768 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003769 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003770 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003771 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003772 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003773 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003774 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
3775 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3776 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
3777 return do_sendrecvmsg(a[0], a[1], a[2], 0);
3778 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
3779 return do_accept4(a[0], a[1], a[2], a[3]);
3780 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
3781 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
3782 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
3783 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00003784 default:
Josh Kunz39be5352020-02-03 18:54:13 -08003785 qemu_log_mask(LOG_UNIMP, "Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003786 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00003787 }
bellard31e31b82003-02-18 22:55:36 +00003788}
j_mayer32407102007-09-26 23:01:49 +00003789#endif
bellard31e31b82003-02-18 22:55:36 +00003790
bellard8853f862004-02-22 14:57:26 +00003791#define N_SHM_REGIONS 32
3792
3793static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003794 abi_ulong start;
3795 abi_ulong size;
3796 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003797} shm_regions[N_SHM_REGIONS];
3798
Peter Maydell005eb2a2016-07-15 16:50:47 +01003799#ifndef TARGET_SEMID64_DS
3800/* asm-generic version of this struct */
3801struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00003802{
3803 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003804 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003805#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003806 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003807#endif
blueswir1992f48a2007-10-14 16:27:31 +00003808 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003809#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003810 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003811#endif
blueswir1992f48a2007-10-14 16:27:31 +00003812 abi_ulong sem_nsems;
3813 abi_ulong __unused3;
3814 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003815};
Peter Maydell005eb2a2016-07-15 16:50:47 +01003816#endif
ths3eb6b042007-06-03 14:26:27 +00003817
bellard579a97f2007-11-11 14:26:47 +00003818static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3819 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003820{
3821 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003822 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003823
bellard579a97f2007-11-11 14:26:47 +00003824 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3825 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003826 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003827 host_ip->__key = tswap32(target_ip->__key);
3828 host_ip->uid = tswap32(target_ip->uid);
3829 host_ip->gid = tswap32(target_ip->gid);
3830 host_ip->cuid = tswap32(target_ip->cuid);
3831 host_ip->cgid = tswap32(target_ip->cgid);
3832#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3833 host_ip->mode = tswap32(target_ip->mode);
3834#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003835 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003836#endif
3837#if defined(TARGET_PPC)
3838 host_ip->__seq = tswap32(target_ip->__seq);
3839#else
3840 host_ip->__seq = tswap16(target_ip->__seq);
3841#endif
ths3eb6b042007-06-03 14:26:27 +00003842 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003843 return 0;
ths3eb6b042007-06-03 14:26:27 +00003844}
3845
bellard579a97f2007-11-11 14:26:47 +00003846static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3847 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003848{
3849 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003850 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003851
bellard579a97f2007-11-11 14:26:47 +00003852 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3853 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003854 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003855 target_ip->__key = tswap32(host_ip->__key);
3856 target_ip->uid = tswap32(host_ip->uid);
3857 target_ip->gid = tswap32(host_ip->gid);
3858 target_ip->cuid = tswap32(host_ip->cuid);
3859 target_ip->cgid = tswap32(host_ip->cgid);
3860#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3861 target_ip->mode = tswap32(host_ip->mode);
3862#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003863 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003864#endif
3865#if defined(TARGET_PPC)
3866 target_ip->__seq = tswap32(host_ip->__seq);
3867#else
3868 target_ip->__seq = tswap16(host_ip->__seq);
3869#endif
ths3eb6b042007-06-03 14:26:27 +00003870 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003871 return 0;
ths3eb6b042007-06-03 14:26:27 +00003872}
3873
bellard579a97f2007-11-11 14:26:47 +00003874static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3875 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003876{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003877 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003878
bellard579a97f2007-11-11 14:26:47 +00003879 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3880 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003881 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3882 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003883 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3884 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3885 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003886 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003887 return 0;
ths3eb6b042007-06-03 14:26:27 +00003888}
3889
bellard579a97f2007-11-11 14:26:47 +00003890static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3891 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003892{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003893 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003894
bellard579a97f2007-11-11 14:26:47 +00003895 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3896 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003897 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003898 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003899 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3900 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3901 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003902 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003903 return 0;
ths3eb6b042007-06-03 14:26:27 +00003904}
3905
aurel32e5289082009-04-18 16:16:12 +00003906struct target_seminfo {
3907 int semmap;
3908 int semmni;
3909 int semmns;
3910 int semmnu;
3911 int semmsl;
3912 int semopm;
3913 int semume;
3914 int semusz;
3915 int semvmx;
3916 int semaem;
3917};
3918
3919static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3920 struct seminfo *host_seminfo)
3921{
3922 struct target_seminfo *target_seminfo;
3923 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3924 return -TARGET_EFAULT;
3925 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3926 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3927 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3928 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3929 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3930 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3931 __put_user(host_seminfo->semume, &target_seminfo->semume);
3932 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3933 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3934 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3935 unlock_user_struct(target_seminfo, target_addr, 1);
3936 return 0;
3937}
3938
thsfa294812007-02-02 22:05:00 +00003939union semun {
3940 int val;
ths3eb6b042007-06-03 14:26:27 +00003941 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003942 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003943 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003944};
3945
ths3eb6b042007-06-03 14:26:27 +00003946union target_semun {
3947 int val;
aurel32e5289082009-04-18 16:16:12 +00003948 abi_ulong buf;
3949 abi_ulong array;
3950 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003951};
3952
aurel32e5289082009-04-18 16:16:12 +00003953static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3954 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003955{
aurel32e5289082009-04-18 16:16:12 +00003956 int nsems;
3957 unsigned short *array;
3958 union semun semun;
3959 struct semid_ds semid_ds;
3960 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003961
aurel32e5289082009-04-18 16:16:12 +00003962 semun.buf = &semid_ds;
3963
3964 ret = semctl(semid, 0, IPC_STAT, semun);
3965 if (ret == -1)
3966 return get_errno(ret);
3967
3968 nsems = semid_ds.sem_nsems;
3969
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303970 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003971 if (!*host_array) {
3972 return -TARGET_ENOMEM;
3973 }
aurel32e5289082009-04-18 16:16:12 +00003974 array = lock_user(VERIFY_READ, target_addr,
3975 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003976 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303977 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003978 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003979 }
aurel32e5289082009-04-18 16:16:12 +00003980
3981 for(i=0; i<nsems; i++) {
3982 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003983 }
aurel32e5289082009-04-18 16:16:12 +00003984 unlock_user(array, target_addr, 0);
3985
bellard579a97f2007-11-11 14:26:47 +00003986 return 0;
ths3eb6b042007-06-03 14:26:27 +00003987}
3988
aurel32e5289082009-04-18 16:16:12 +00003989static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3990 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003991{
aurel32e5289082009-04-18 16:16:12 +00003992 int nsems;
3993 unsigned short *array;
3994 union semun semun;
3995 struct semid_ds semid_ds;
3996 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003997
aurel32e5289082009-04-18 16:16:12 +00003998 semun.buf = &semid_ds;
3999
4000 ret = semctl(semid, 0, IPC_STAT, semun);
4001 if (ret == -1)
4002 return get_errno(ret);
4003
4004 nsems = semid_ds.sem_nsems;
4005
4006 array = lock_user(VERIFY_WRITE, target_addr,
4007 nsems*sizeof(unsigned short), 0);
4008 if (!array)
4009 return -TARGET_EFAULT;
4010
4011 for(i=0; i<nsems; i++) {
4012 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004013 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304014 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004015 unlock_user(array, target_addr, 1);
4016
bellard579a97f2007-11-11 14:26:47 +00004017 return 0;
ths3eb6b042007-06-03 14:26:27 +00004018}
4019
aurel32e5289082009-04-18 16:16:12 +00004020static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004021 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004022{
Stefan Weild1c002b2015-02-08 15:40:58 +01004023 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004024 union semun arg;
4025 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304026 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004027 struct seminfo seminfo;
4028 abi_long ret = -TARGET_EINVAL;
4029 abi_long err;
4030 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004031
4032 switch( cmd ) {
4033 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004034 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004035 /* In 64 bit cross-endian situations, we will erroneously pick up
4036 * the wrong half of the union for the "val" element. To rectify
4037 * this, the entire 8-byte structure is byteswapped, followed by
4038 * a swap of the 4 byte val field. In other cases, the data is
4039 * already in proper host byte order. */
4040 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4041 target_su.buf = tswapal(target_su.buf);
4042 arg.val = tswap32(target_su.val);
4043 } else {
4044 arg.val = target_su.val;
4045 }
aurel32e5289082009-04-18 16:16:12 +00004046 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004047 break;
4048 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004049 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004050 err = target_to_host_semarray(semid, &array, target_su.array);
4051 if (err)
4052 return err;
4053 arg.array = array;
4054 ret = get_errno(semctl(semid, semnum, cmd, arg));
4055 err = host_to_target_semarray(semid, target_su.array, &array);
4056 if (err)
4057 return err;
ths3eb6b042007-06-03 14:26:27 +00004058 break;
4059 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004060 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004061 case SEM_STAT:
4062 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4063 if (err)
4064 return err;
4065 arg.buf = &dsarg;
4066 ret = get_errno(semctl(semid, semnum, cmd, arg));
4067 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4068 if (err)
4069 return err;
ths3eb6b042007-06-03 14:26:27 +00004070 break;
aurel32e5289082009-04-18 16:16:12 +00004071 case IPC_INFO:
4072 case SEM_INFO:
4073 arg.__buf = &seminfo;
4074 ret = get_errno(semctl(semid, semnum, cmd, arg));
4075 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4076 if (err)
4077 return err;
4078 break;
4079 case IPC_RMID:
4080 case GETPID:
4081 case GETNCNT:
4082 case GETZCNT:
4083 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4084 break;
ths3eb6b042007-06-03 14:26:27 +00004085 }
4086
4087 return ret;
4088}
4089
aurel32e5289082009-04-18 16:16:12 +00004090struct target_sembuf {
4091 unsigned short sem_num;
4092 short sem_op;
4093 short sem_flg;
4094};
4095
4096static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4097 abi_ulong target_addr,
4098 unsigned nsops)
4099{
4100 struct target_sembuf *target_sembuf;
4101 int i;
4102
4103 target_sembuf = lock_user(VERIFY_READ, target_addr,
4104 nsops*sizeof(struct target_sembuf), 1);
4105 if (!target_sembuf)
4106 return -TARGET_EFAULT;
4107
4108 for(i=0; i<nsops; i++) {
4109 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4110 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4111 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4112 }
4113
4114 unlock_user(target_sembuf, target_addr, 0);
4115
4116 return 0;
4117}
4118
Matus Kyseld8c08b12020-06-26 14:46:11 +02004119#if defined(TARGET_NR_ipc) || defined(TARGET_NR_semop) || \
Filip Bozutacac46eb2020-08-25 00:30:50 +02004120 defined(TARGET_NR_semtimedop) || defined(TARGET_NR_semtimedop_time64)
Matus Kyseld8c08b12020-06-26 14:46:11 +02004121
4122/*
4123 * This macro is required to handle the s390 variants, which passes the
4124 * arguments in a different order than default.
4125 */
4126#ifdef __s390x__
4127#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \
4128 (__nsops), (__timeout), (__sops)
4129#else
4130#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \
4131 (__nsops), 0, (__sops), (__timeout)
4132#endif
4133
4134static inline abi_long do_semtimedop(int semid,
4135 abi_long ptr,
4136 unsigned nsops,
Filip Bozutacac46eb2020-08-25 00:30:50 +02004137 abi_long timeout, bool time64)
aurel32e5289082009-04-18 16:16:12 +00004138{
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004139 struct sembuf *sops;
Matus Kyseld8c08b12020-06-26 14:46:11 +02004140 struct timespec ts, *pts = NULL;
Laurent Vivier524fa342019-05-29 10:48:04 +02004141 abi_long ret;
aurel32e5289082009-04-18 16:16:12 +00004142
Matus Kyseld8c08b12020-06-26 14:46:11 +02004143 if (timeout) {
4144 pts = &ts;
Filip Bozutacac46eb2020-08-25 00:30:50 +02004145 if (time64) {
4146 if (target_to_host_timespec64(pts, timeout)) {
4147 return -TARGET_EFAULT;
4148 }
4149 } else {
4150 if (target_to_host_timespec(pts, timeout)) {
4151 return -TARGET_EFAULT;
4152 }
Matus Kyseld8c08b12020-06-26 14:46:11 +02004153 }
4154 }
4155
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004156 if (nsops > TARGET_SEMOPM) {
4157 return -TARGET_E2BIG;
4158 }
4159
4160 sops = g_new(struct sembuf, nsops);
4161
4162 if (target_to_host_sembuf(sops, ptr, nsops)) {
4163 g_free(sops);
aurel32e5289082009-04-18 16:16:12 +00004164 return -TARGET_EFAULT;
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004165 }
aurel32e5289082009-04-18 16:16:12 +00004166
Laurent Vivier524fa342019-05-29 10:48:04 +02004167 ret = -TARGET_ENOSYS;
4168#ifdef __NR_semtimedop
Matus Kyseld8c08b12020-06-26 14:46:11 +02004169 ret = get_errno(safe_semtimedop(semid, sops, nsops, pts));
Laurent Vivier524fa342019-05-29 10:48:04 +02004170#endif
4171#ifdef __NR_ipc
4172 if (ret == -TARGET_ENOSYS) {
Matus Kyseld8c08b12020-06-26 14:46:11 +02004173 ret = get_errno(safe_ipc(IPCOP_semtimedop, semid,
4174 SEMTIMEDOP_IPC_ARGS(nsops, sops, (long)pts)));
Laurent Vivier524fa342019-05-29 10:48:04 +02004175 }
4176#endif
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004177 g_free(sops);
Laurent Vivier524fa342019-05-29 10:48:04 +02004178 return ret;
aurel32e5289082009-04-18 16:16:12 +00004179}
Matus Kyseld8c08b12020-06-26 14:46:11 +02004180#endif
aurel32e5289082009-04-18 16:16:12 +00004181
ths1bc012f2007-06-03 14:27:49 +00004182struct target_msqid_ds
4183{
aurel321c54ff92008-10-13 21:08:44 +00004184 struct target_ipc_perm msg_perm;
4185 abi_ulong msg_stime;
4186#if TARGET_ABI_BITS == 32
4187 abi_ulong __unused1;
4188#endif
4189 abi_ulong msg_rtime;
4190#if TARGET_ABI_BITS == 32
4191 abi_ulong __unused2;
4192#endif
4193 abi_ulong msg_ctime;
4194#if TARGET_ABI_BITS == 32
4195 abi_ulong __unused3;
4196#endif
4197 abi_ulong __msg_cbytes;
4198 abi_ulong msg_qnum;
4199 abi_ulong msg_qbytes;
4200 abi_ulong msg_lspid;
4201 abi_ulong msg_lrpid;
4202 abi_ulong __unused4;
4203 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004204};
4205
bellard579a97f2007-11-11 14:26:47 +00004206static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4207 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004208{
4209 struct target_msqid_ds *target_md;
4210
bellard579a97f2007-11-11 14:26:47 +00004211 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4212 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004213 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4214 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004215 host_md->msg_stime = tswapal(target_md->msg_stime);
4216 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4217 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4218 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4219 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4220 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4221 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4222 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004223 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004224 return 0;
ths1bc012f2007-06-03 14:27:49 +00004225}
4226
bellard579a97f2007-11-11 14:26:47 +00004227static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4228 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004229{
4230 struct target_msqid_ds *target_md;
4231
bellard579a97f2007-11-11 14:26:47 +00004232 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4233 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004234 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4235 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004236 target_md->msg_stime = tswapal(host_md->msg_stime);
4237 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4238 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4239 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4240 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4241 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4242 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4243 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004244 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004245 return 0;
ths1bc012f2007-06-03 14:27:49 +00004246}
4247
aurel321c54ff92008-10-13 21:08:44 +00004248struct target_msginfo {
4249 int msgpool;
4250 int msgmap;
4251 int msgmax;
4252 int msgmnb;
4253 int msgmni;
4254 int msgssz;
4255 int msgtql;
4256 unsigned short int msgseg;
4257};
4258
4259static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4260 struct msginfo *host_msginfo)
4261{
4262 struct target_msginfo *target_msginfo;
4263 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4264 return -TARGET_EFAULT;
4265 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4266 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4267 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4268 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4269 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4270 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4271 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4272 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4273 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004274 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004275}
4276
4277static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004278{
4279 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004280 struct msginfo msginfo;
4281 abi_long ret = -TARGET_EINVAL;
4282
4283 cmd &= 0xff;
4284
4285 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004286 case IPC_STAT:
4287 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004288 case MSG_STAT:
4289 if (target_to_host_msqid_ds(&dsarg,ptr))
4290 return -TARGET_EFAULT;
4291 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4292 if (host_to_target_msqid_ds(ptr,&dsarg))
4293 return -TARGET_EFAULT;
4294 break;
4295 case IPC_RMID:
4296 ret = get_errno(msgctl(msgid, cmd, NULL));
4297 break;
4298 case IPC_INFO:
4299 case MSG_INFO:
4300 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4301 if (host_to_target_msginfo(ptr, &msginfo))
4302 return -TARGET_EFAULT;
4303 break;
ths1bc012f2007-06-03 14:27:49 +00004304 }
aurel321c54ff92008-10-13 21:08:44 +00004305
ths1bc012f2007-06-03 14:27:49 +00004306 return ret;
4307}
4308
4309struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004310 abi_long mtype;
4311 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004312};
4313
blueswir1992f48a2007-10-14 16:27:31 +00004314static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004315 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004316{
4317 struct target_msgbuf *target_mb;
4318 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004319 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004320
Tom Mustaedcc5f92014-08-12 13:53:37 -05004321 if (msgsz < 0) {
4322 return -TARGET_EINVAL;
4323 }
4324
bellard579a97f2007-11-11 14:26:47 +00004325 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4326 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304327 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004328 if (!host_mb) {
4329 unlock_user_struct(target_mb, msgp, 0);
4330 return -TARGET_ENOMEM;
4331 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004332 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004333 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Laurent Vivier524fa342019-05-29 10:48:04 +02004334 ret = -TARGET_ENOSYS;
4335#ifdef __NR_msgsnd
Peter Maydell89f9fe42016-06-06 19:58:05 +01004336 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02004337#endif
4338#ifdef __NR_ipc
4339 if (ret == -TARGET_ENOSYS) {
Matus Kyseld8c08b12020-06-26 14:46:11 +02004340#ifdef __s390x__
4341 ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
4342 host_mb));
4343#else
Laurent Vivier524fa342019-05-29 10:48:04 +02004344 ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
4345 host_mb, 0));
Matus Kyseld8c08b12020-06-26 14:46:11 +02004346#endif
Laurent Vivier524fa342019-05-29 10:48:04 +02004347 }
4348#endif
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304349 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004350 unlock_user_struct(target_mb, msgp, 0);
4351
4352 return ret;
4353}
4354
Matus Kyseld8c08b12020-06-26 14:46:11 +02004355#ifdef __NR_ipc
4356#if defined(__sparc__)
4357/* SPARC for msgrcv it does not use the kludge on final 2 arguments. */
4358#define MSGRCV_ARGS(__msgp, __msgtyp) __msgp, __msgtyp
4359#elif defined(__s390x__)
4360/* The s390 sys_ipc variant has only five parameters. */
4361#define MSGRCV_ARGS(__msgp, __msgtyp) \
4362 ((long int[]){(long int)__msgp, __msgtyp})
4363#else
4364#define MSGRCV_ARGS(__msgp, __msgtyp) \
4365 ((long int[]){(long int)__msgp, __msgtyp}), 0
4366#endif
4367#endif
4368
blueswir1992f48a2007-10-14 16:27:31 +00004369static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004370 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004371 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004372{
4373 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004374 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004375 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004376 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004377
Peter Maydell99874f62016-05-20 19:00:56 +01004378 if (msgsz < 0) {
4379 return -TARGET_EINVAL;
4380 }
4381
bellard579a97f2007-11-11 14:26:47 +00004382 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4383 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004384
Peter Maydell415d8472016-05-20 19:00:57 +01004385 host_mb = g_try_malloc(msgsz + sizeof(long));
4386 if (!host_mb) {
4387 ret = -TARGET_ENOMEM;
4388 goto end;
4389 }
Laurent Vivier524fa342019-05-29 10:48:04 +02004390 ret = -TARGET_ENOSYS;
4391#ifdef __NR_msgrcv
Peter Maydell89f9fe42016-06-06 19:58:05 +01004392 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02004393#endif
4394#ifdef __NR_ipc
4395 if (ret == -TARGET_ENOSYS) {
4396 ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz,
Matus Kyseld8c08b12020-06-26 14:46:11 +02004397 msgflg, MSGRCV_ARGS(host_mb, msgtyp)));
Laurent Vivier524fa342019-05-29 10:48:04 +02004398 }
4399#endif
aurel321c54ff92008-10-13 21:08:44 +00004400
bellard579a97f2007-11-11 14:26:47 +00004401 if (ret > 0) {
4402 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4403 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4404 if (!target_mtext) {
4405 ret = -TARGET_EFAULT;
4406 goto end;
4407 }
aurel321c54ff92008-10-13 21:08:44 +00004408 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004409 unlock_user(target_mtext, target_mtext_addr, ret);
4410 }
aurel321c54ff92008-10-13 21:08:44 +00004411
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004412 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004413
bellard579a97f2007-11-11 14:26:47 +00004414end:
4415 if (target_mb)
4416 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004417 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004418 return ret;
4419}
4420
Riku Voipio88a8c982009-04-03 10:42:00 +03004421static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4422 abi_ulong target_addr)
4423{
4424 struct target_shmid_ds *target_sd;
4425
4426 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4427 return -TARGET_EFAULT;
4428 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4429 return -TARGET_EFAULT;
4430 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4431 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4432 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4433 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4434 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4435 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4436 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4437 unlock_user_struct(target_sd, target_addr, 0);
4438 return 0;
4439}
4440
4441static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4442 struct shmid_ds *host_sd)
4443{
4444 struct target_shmid_ds *target_sd;
4445
4446 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4447 return -TARGET_EFAULT;
4448 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4449 return -TARGET_EFAULT;
4450 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4451 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4452 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4453 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4454 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4455 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4456 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4457 unlock_user_struct(target_sd, target_addr, 1);
4458 return 0;
4459}
4460
4461struct target_shminfo {
4462 abi_ulong shmmax;
4463 abi_ulong shmmin;
4464 abi_ulong shmmni;
4465 abi_ulong shmseg;
4466 abi_ulong shmall;
4467};
4468
4469static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4470 struct shminfo *host_shminfo)
4471{
4472 struct target_shminfo *target_shminfo;
4473 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4474 return -TARGET_EFAULT;
4475 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4476 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4477 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4478 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4479 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4480 unlock_user_struct(target_shminfo, target_addr, 1);
4481 return 0;
4482}
4483
4484struct target_shm_info {
4485 int used_ids;
4486 abi_ulong shm_tot;
4487 abi_ulong shm_rss;
4488 abi_ulong shm_swp;
4489 abi_ulong swap_attempts;
4490 abi_ulong swap_successes;
4491};
4492
4493static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4494 struct shm_info *host_shm_info)
4495{
4496 struct target_shm_info *target_shm_info;
4497 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4498 return -TARGET_EFAULT;
4499 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4500 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4501 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4502 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4503 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4504 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4505 unlock_user_struct(target_shm_info, target_addr, 1);
4506 return 0;
4507}
4508
4509static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4510{
4511 struct shmid_ds dsarg;
4512 struct shminfo shminfo;
4513 struct shm_info shm_info;
4514 abi_long ret = -TARGET_EINVAL;
4515
4516 cmd &= 0xff;
4517
4518 switch(cmd) {
4519 case IPC_STAT:
4520 case IPC_SET:
4521 case SHM_STAT:
4522 if (target_to_host_shmid_ds(&dsarg, buf))
4523 return -TARGET_EFAULT;
4524 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4525 if (host_to_target_shmid_ds(buf, &dsarg))
4526 return -TARGET_EFAULT;
4527 break;
4528 case IPC_INFO:
4529 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4530 if (host_to_target_shminfo(buf, &shminfo))
4531 return -TARGET_EFAULT;
4532 break;
4533 case SHM_INFO:
4534 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4535 if (host_to_target_shm_info(buf, &shm_info))
4536 return -TARGET_EFAULT;
4537 break;
4538 case IPC_RMID:
4539 case SHM_LOCK:
4540 case SHM_UNLOCK:
4541 ret = get_errno(shmctl(shmid, cmd, NULL));
4542 break;
4543 }
4544
4545 return ret;
4546}
4547
Peter Maydellee8e7612016-07-11 16:48:11 +01004548#ifndef TARGET_FORCE_SHMLBA
4549/* For most architectures, SHMLBA is the same as the page size;
4550 * some architectures have larger values, in which case they should
4551 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4552 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4553 * and defining its own value for SHMLBA.
4554 *
4555 * The kernel also permits SHMLBA to be set by the architecture to a
4556 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4557 * this means that addresses are rounded to the large size if
4558 * SHM_RND is set but addresses not aligned to that size are not rejected
4559 * as long as they are at least page-aligned. Since the only architecture
4560 * which uses this is ia64 this code doesn't provide for that oddity.
4561 */
4562static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4563{
4564 return TARGET_PAGE_SIZE;
4565}
4566#endif
4567
4568static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4569 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004570{
4571 abi_long raddr;
4572 void *host_raddr;
4573 struct shmid_ds shm_info;
4574 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004575 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004576
4577 /* find out the length of the shared memory segment */
4578 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4579 if (is_error(ret)) {
4580 /* can't get length, bail out */
4581 return ret;
4582 }
4583
Peter Maydellee8e7612016-07-11 16:48:11 +01004584 shmlba = target_shmlba(cpu_env);
4585
4586 if (shmaddr & (shmlba - 1)) {
4587 if (shmflg & SHM_RND) {
4588 shmaddr &= ~(shmlba - 1);
4589 } else {
4590 return -TARGET_EINVAL;
4591 }
4592 }
Max Filippovebf9a362018-03-07 13:50:10 -08004593 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
4594 return -TARGET_EINVAL;
4595 }
Peter Maydellee8e7612016-07-11 16:48:11 +01004596
Riku Voipio88a8c982009-04-03 10:42:00 +03004597 mmap_lock();
4598
4599 if (shmaddr)
4600 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4601 else {
4602 abi_ulong mmap_start;
4603
Richard Henderson30ab9ef2019-05-19 13:19:52 -07004604 /* In order to use the host shmat, we need to honor host SHMLBA. */
4605 mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
Riku Voipio88a8c982009-04-03 10:42:00 +03004606
4607 if (mmap_start == -1) {
4608 errno = ENOMEM;
4609 host_raddr = (void *)-1;
4610 } else
4611 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4612 }
4613
4614 if (host_raddr == (void *)-1) {
4615 mmap_unlock();
4616 return get_errno((long)host_raddr);
4617 }
4618 raddr=h2g((unsigned long)host_raddr);
4619
4620 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4621 PAGE_VALID | PAGE_READ |
4622 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4623
4624 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004625 if (!shm_regions[i].in_use) {
4626 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004627 shm_regions[i].start = raddr;
4628 shm_regions[i].size = shm_info.shm_segsz;
4629 break;
4630 }
4631 }
4632
4633 mmap_unlock();
4634 return raddr;
4635
4636}
4637
4638static inline abi_long do_shmdt(abi_ulong shmaddr)
4639{
4640 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08004641 abi_long rv;
4642
4643 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03004644
4645 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004646 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4647 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004648 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004649 break;
4650 }
4651 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08004652 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03004653
Max Filippov3c5f6a52018-02-28 14:16:04 -08004654 mmap_unlock();
4655
4656 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03004657}
4658
aurel321c54ff92008-10-13 21:08:44 +00004659#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004660/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004661/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004662static abi_long do_ipc(CPUArchState *cpu_env,
4663 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004664 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004665 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004666{
4667 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004668 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004669
4670 version = call >> 16;
4671 call &= 0xffff;
4672
4673 switch (call) {
thsfa294812007-02-02 22:05:00 +00004674 case IPCOP_semop:
Filip Bozutacac46eb2020-08-25 00:30:50 +02004675 ret = do_semtimedop(first, ptr, second, 0, false);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004676 break;
4677 case IPCOP_semtimedop:
4678 /*
4679 * The s390 sys_ipc variant has only five parameters instead of six
4680 * (as for default variant) and the only difference is the handling of
4681 * SEMTIMEDOP where on s390 the third parameter is used as a pointer
4682 * to a struct timespec where the generic variant uses fifth parameter.
4683 */
4684#if defined(TARGET_S390X)
Filip Bozutacac46eb2020-08-25 00:30:50 +02004685 ret = do_semtimedop(first, ptr, second, third, TARGET_ABI_BITS == 64);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004686#else
Filip Bozutacac46eb2020-08-25 00:30:50 +02004687 ret = do_semtimedop(first, ptr, second, fifth, TARGET_ABI_BITS == 64);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004688#endif
thsfa294812007-02-02 22:05:00 +00004689 break;
4690
4691 case IPCOP_semget:
4692 ret = get_errno(semget(first, second, third));
4693 break;
4694
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004695 case IPCOP_semctl: {
4696 /* The semun argument to semctl is passed by value, so dereference the
4697 * ptr argument. */
4698 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004699 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004700 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004701 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004702 }
thsd96372e2007-02-02 22:05:44 +00004703
aurel321c54ff92008-10-13 21:08:44 +00004704 case IPCOP_msgget:
4705 ret = get_errno(msgget(first, second));
4706 break;
thsd96372e2007-02-02 22:05:44 +00004707
aurel321c54ff92008-10-13 21:08:44 +00004708 case IPCOP_msgsnd:
4709 ret = do_msgsnd(first, ptr, second, third);
4710 break;
thsd96372e2007-02-02 22:05:44 +00004711
aurel321c54ff92008-10-13 21:08:44 +00004712 case IPCOP_msgctl:
4713 ret = do_msgctl(first, second, ptr);
4714 break;
thsd96372e2007-02-02 22:05:44 +00004715
aurel321c54ff92008-10-13 21:08:44 +00004716 case IPCOP_msgrcv:
4717 switch (version) {
4718 case 0:
4719 {
4720 struct target_ipc_kludge {
4721 abi_long msgp;
4722 abi_long msgtyp;
4723 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004724
aurel321c54ff92008-10-13 21:08:44 +00004725 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4726 ret = -TARGET_EFAULT;
4727 break;
ths1bc012f2007-06-03 14:27:49 +00004728 }
aurel321c54ff92008-10-13 21:08:44 +00004729
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004730 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004731
4732 unlock_user_struct(tmp, ptr, 0);
4733 break;
4734 }
4735 default:
4736 ret = do_msgrcv(first, ptr, second, fifth, third);
4737 }
4738 break;
thsd96372e2007-02-02 22:05:44 +00004739
bellard8853f862004-02-22 14:57:26 +00004740 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004741 switch (version) {
4742 default:
bellard5a4a8982007-11-11 17:39:18 +00004743 {
4744 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01004745 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03004746 if (is_error(raddr))
4747 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004748 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004749 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004750 break;
4751 }
4752 case 1:
4753 ret = -TARGET_EINVAL;
4754 break;
bellard5a4a8982007-11-11 17:39:18 +00004755 }
bellard8853f862004-02-22 14:57:26 +00004756 break;
4757 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004758 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004759 break;
4760
4761 case IPCOP_shmget:
4762 /* IPC_* flag values are the same on all linux platforms */
4763 ret = get_errno(shmget(first, second, third));
4764 break;
4765
4766 /* IPC_* and SHM_* command values are the same on all linux platforms */
4767 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004768 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004769 break;
4770 default:
Josh Kunz39be5352020-02-03 18:54:13 -08004771 qemu_log_mask(LOG_UNIMP, "Unsupported ipc call: %d (version %d)\n",
4772 call, version);
ths0da46a62007-10-20 20:23:07 +00004773 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004774 break;
4775 }
4776 return ret;
4777}
j_mayer32407102007-09-26 23:01:49 +00004778#endif
bellard8853f862004-02-22 14:57:26 +00004779
bellard31e31b82003-02-18 22:55:36 +00004780/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004781
Blue Swirl001faf32009-05-13 17:53:17 +00004782#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004783#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4784enum {
4785#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004786STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004787};
4788#undef STRUCT
4789#undef STRUCT_SPECIAL
4790
Blue Swirl001faf32009-05-13 17:53:17 +00004791#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004792#define STRUCT_SPECIAL(name)
4793#include "syscall_types.h"
4794#undef STRUCT
4795#undef STRUCT_SPECIAL
4796
bellard31e31b82003-02-18 22:55:36 +00004797#define MAX_STRUCT_SIZE 4096
4798
Peter Maydelldace20d2011-01-10 13:11:24 +00004799#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004800/* So fiemap access checks don't overflow on 32 bit systems.
4801 * This is very slightly smaller than the limit imposed by
4802 * the underlying kernel.
4803 */
4804#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4805 / sizeof(struct fiemap_extent))
4806
4807static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004808 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004809{
4810 /* The parameter for this ioctl is a struct fiemap followed
4811 * by an array of struct fiemap_extent whose size is set
4812 * in fiemap->fm_extent_count. The array is filled in by the
4813 * ioctl.
4814 */
4815 int target_size_in, target_size_out;
4816 struct fiemap *fm;
4817 const argtype *arg_type = ie->arg_type;
4818 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4819 void *argptr, *p;
4820 abi_long ret;
4821 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4822 uint32_t outbufsz;
4823 int free_fm = 0;
4824
4825 assert(arg_type[0] == TYPE_PTR);
4826 assert(ie->access == IOC_RW);
4827 arg_type++;
4828 target_size_in = thunk_type_size(arg_type, 0);
4829 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4830 if (!argptr) {
4831 return -TARGET_EFAULT;
4832 }
4833 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4834 unlock_user(argptr, arg, 0);
4835 fm = (struct fiemap *)buf_temp;
4836 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4837 return -TARGET_EINVAL;
4838 }
4839
4840 outbufsz = sizeof (*fm) +
4841 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4842
4843 if (outbufsz > MAX_STRUCT_SIZE) {
4844 /* We can't fit all the extents into the fixed size buffer.
4845 * Allocate one that is large enough and use it instead.
4846 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304847 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004848 if (!fm) {
4849 return -TARGET_ENOMEM;
4850 }
4851 memcpy(fm, buf_temp, sizeof(struct fiemap));
4852 free_fm = 1;
4853 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004854 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004855 if (!is_error(ret)) {
4856 target_size_out = target_size_in;
4857 /* An extent_count of 0 means we were only counting the extents
4858 * so there are no structs to copy
4859 */
4860 if (fm->fm_extent_count != 0) {
4861 target_size_out += fm->fm_mapped_extents * extent_size;
4862 }
4863 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4864 if (!argptr) {
4865 ret = -TARGET_EFAULT;
4866 } else {
4867 /* Convert the struct fiemap */
4868 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4869 if (fm->fm_extent_count != 0) {
4870 p = argptr + target_size_in;
4871 /* ...and then all the struct fiemap_extents */
4872 for (i = 0; i < fm->fm_mapped_extents; i++) {
4873 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4874 THUNK_TARGET);
4875 p += extent_size;
4876 }
4877 }
4878 unlock_user(argptr, arg, target_size_out);
4879 }
4880 }
4881 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304882 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004883 }
4884 return ret;
4885}
Peter Maydelldace20d2011-01-10 13:11:24 +00004886#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004887
Laurent Vivier059c2f22011-03-30 00:12:12 +02004888static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004889 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004890{
4891 const argtype *arg_type = ie->arg_type;
4892 int target_size;
4893 void *argptr;
4894 int ret;
4895 struct ifconf *host_ifconf;
4896 uint32_t outbufsz;
4897 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4898 int target_ifreq_size;
4899 int nb_ifreq;
4900 int free_buf = 0;
4901 int i;
4902 int target_ifc_len;
4903 abi_long target_ifc_buf;
4904 int host_ifc_len;
4905 char *host_ifc_buf;
4906
4907 assert(arg_type[0] == TYPE_PTR);
4908 assert(ie->access == IOC_RW);
4909
4910 arg_type++;
4911 target_size = thunk_type_size(arg_type, 0);
4912
4913 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4914 if (!argptr)
4915 return -TARGET_EFAULT;
4916 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4917 unlock_user(argptr, arg, 0);
4918
4919 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004920 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004921 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004922
Kan Li22e4a2672018-10-24 20:13:03 +00004923 if (target_ifc_buf != 0) {
4924 target_ifc_len = host_ifconf->ifc_len;
4925 nb_ifreq = target_ifc_len / target_ifreq_size;
4926 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4927
4928 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4929 if (outbufsz > MAX_STRUCT_SIZE) {
4930 /*
4931 * We can't fit all the extents into the fixed size buffer.
4932 * Allocate one that is large enough and use it instead.
4933 */
4934 host_ifconf = malloc(outbufsz);
4935 if (!host_ifconf) {
4936 return -TARGET_ENOMEM;
4937 }
4938 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4939 free_buf = 1;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004940 }
Kan Li22e4a2672018-10-24 20:13:03 +00004941 host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004942
Kan Li22e4a2672018-10-24 20:13:03 +00004943 host_ifconf->ifc_len = host_ifc_len;
4944 } else {
4945 host_ifc_buf = NULL;
4946 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004947 host_ifconf->ifc_buf = host_ifc_buf;
4948
Peter Maydell49ca6f32016-06-06 19:58:14 +01004949 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004950 if (!is_error(ret)) {
4951 /* convert host ifc_len to target ifc_len */
4952
4953 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4954 target_ifc_len = nb_ifreq * target_ifreq_size;
4955 host_ifconf->ifc_len = target_ifc_len;
4956
4957 /* restore target ifc_buf */
4958
4959 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4960
4961 /* copy struct ifconf to target user */
4962
4963 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4964 if (!argptr)
4965 return -TARGET_EFAULT;
4966 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4967 unlock_user(argptr, arg, target_size);
4968
Kan Li22e4a2672018-10-24 20:13:03 +00004969 if (target_ifc_buf != 0) {
4970 /* copy ifreq[] to target user */
4971 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4972 for (i = 0; i < nb_ifreq ; i++) {
4973 thunk_convert(argptr + i * target_ifreq_size,
4974 host_ifc_buf + i * sizeof(struct ifreq),
4975 ifreq_arg_type, THUNK_TARGET);
4976 }
4977 unlock_user(argptr, target_ifc_buf, target_ifc_len);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004978 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004979 }
4980
4981 if (free_buf) {
4982 free(host_ifconf);
4983 }
4984
4985 return ret;
4986}
4987
Cortland Tölvaa1333672018-10-08 09:35:21 -07004988#if defined(CONFIG_USBFS)
4989#if HOST_LONG_BITS > 64
4990#error USBDEVFS thunks do not support >64 bit hosts yet.
4991#endif
4992struct live_urb {
4993 uint64_t target_urb_adr;
4994 uint64_t target_buf_adr;
4995 char *target_buf_ptr;
4996 struct usbdevfs_urb host_urb;
4997};
4998
4999static GHashTable *usbdevfs_urb_hashtable(void)
5000{
5001 static GHashTable *urb_hashtable;
5002
5003 if (!urb_hashtable) {
5004 urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
5005 }
5006 return urb_hashtable;
5007}
5008
5009static void urb_hashtable_insert(struct live_urb *urb)
5010{
5011 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
5012 g_hash_table_insert(urb_hashtable, urb, urb);
5013}
5014
5015static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
5016{
5017 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
5018 return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
5019}
5020
5021static void urb_hashtable_remove(struct live_urb *urb)
5022{
5023 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
5024 g_hash_table_remove(urb_hashtable, urb);
5025}
5026
5027static abi_long
5028do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
5029 int fd, int cmd, abi_long arg)
5030{
5031 const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
5032 const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
5033 struct live_urb *lurb;
5034 void *argptr;
5035 uint64_t hurb;
5036 int target_size;
5037 uintptr_t target_urb_adr;
5038 abi_long ret;
5039
5040 target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
5041
5042 memset(buf_temp, 0, sizeof(uint64_t));
5043 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
5044 if (is_error(ret)) {
5045 return ret;
5046 }
5047
5048 memcpy(&hurb, buf_temp, sizeof(uint64_t));
5049 lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
5050 if (!lurb->target_urb_adr) {
5051 return -TARGET_EFAULT;
5052 }
5053 urb_hashtable_remove(lurb);
5054 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
5055 lurb->host_urb.buffer_length);
5056 lurb->target_buf_ptr = NULL;
5057
5058 /* restore the guest buffer pointer */
5059 lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
5060
5061 /* update the guest urb struct */
5062 argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
5063 if (!argptr) {
5064 g_free(lurb);
5065 return -TARGET_EFAULT;
5066 }
5067 thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
5068 unlock_user(argptr, lurb->target_urb_adr, target_size);
5069
5070 target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
5071 /* write back the urb handle */
5072 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5073 if (!argptr) {
5074 g_free(lurb);
5075 return -TARGET_EFAULT;
5076 }
5077
5078 /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
5079 target_urb_adr = lurb->target_urb_adr;
5080 thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
5081 unlock_user(argptr, arg, target_size);
5082
5083 g_free(lurb);
5084 return ret;
5085}
5086
5087static abi_long
5088do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
5089 uint8_t *buf_temp __attribute__((unused)),
5090 int fd, int cmd, abi_long arg)
5091{
5092 struct live_urb *lurb;
5093
5094 /* map target address back to host URB with metadata. */
5095 lurb = urb_hashtable_lookup(arg);
5096 if (!lurb) {
5097 return -TARGET_EFAULT;
5098 }
5099 return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
5100}
5101
5102static abi_long
5103do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
5104 int fd, int cmd, abi_long arg)
5105{
5106 const argtype *arg_type = ie->arg_type;
5107 int target_size;
5108 abi_long ret;
5109 void *argptr;
5110 int rw_dir;
5111 struct live_urb *lurb;
5112
5113 /*
5114 * each submitted URB needs to map to a unique ID for the
5115 * kernel, and that unique ID needs to be a pointer to
5116 * host memory. hence, we need to malloc for each URB.
5117 * isochronous transfers have a variable length struct.
5118 */
5119 arg_type++;
5120 target_size = thunk_type_size(arg_type, THUNK_TARGET);
5121
5122 /* construct host copy of urb and metadata */
5123 lurb = g_try_malloc0(sizeof(struct live_urb));
5124 if (!lurb) {
5125 return -TARGET_ENOMEM;
5126 }
5127
5128 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5129 if (!argptr) {
5130 g_free(lurb);
5131 return -TARGET_EFAULT;
5132 }
5133 thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
5134 unlock_user(argptr, arg, 0);
5135
5136 lurb->target_urb_adr = arg;
5137 lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
5138
5139 /* buffer space used depends on endpoint type so lock the entire buffer */
5140 /* control type urbs should check the buffer contents for true direction */
5141 rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
5142 lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
5143 lurb->host_urb.buffer_length, 1);
5144 if (lurb->target_buf_ptr == NULL) {
5145 g_free(lurb);
5146 return -TARGET_EFAULT;
5147 }
5148
5149 /* update buffer pointer in host copy */
5150 lurb->host_urb.buffer = lurb->target_buf_ptr;
5151
5152 ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
5153 if (is_error(ret)) {
5154 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
5155 g_free(lurb);
5156 } else {
5157 urb_hashtable_insert(lurb);
5158 }
5159
5160 return ret;
5161}
5162#endif /* CONFIG_USBFS */
5163
Alexander Graf56e904e2012-01-31 18:42:06 +01005164static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005165 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005166{
5167 void *argptr;
5168 struct dm_ioctl *host_dm;
5169 abi_long guest_data;
5170 uint32_t guest_data_size;
5171 int target_size;
5172 const argtype *arg_type = ie->arg_type;
5173 abi_long ret;
5174 void *big_buf = NULL;
5175 char *host_data;
5176
5177 arg_type++;
5178 target_size = thunk_type_size(arg_type, 0);
5179 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5180 if (!argptr) {
5181 ret = -TARGET_EFAULT;
5182 goto out;
5183 }
5184 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5185 unlock_user(argptr, arg, 0);
5186
5187 /* buf_temp is too small, so fetch things into a bigger buffer */
5188 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5189 memcpy(big_buf, buf_temp, target_size);
5190 buf_temp = big_buf;
5191 host_dm = big_buf;
5192
5193 guest_data = arg + host_dm->data_start;
5194 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005195 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005196 goto out;
5197 }
5198 guest_data_size = host_dm->data_size - host_dm->data_start;
5199 host_data = (char*)host_dm + host_dm->data_start;
5200
5201 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005202 if (!argptr) {
5203 ret = -TARGET_EFAULT;
5204 goto out;
5205 }
5206
Alexander Graf56e904e2012-01-31 18:42:06 +01005207 switch (ie->host_cmd) {
5208 case DM_REMOVE_ALL:
5209 case DM_LIST_DEVICES:
5210 case DM_DEV_CREATE:
5211 case DM_DEV_REMOVE:
5212 case DM_DEV_SUSPEND:
5213 case DM_DEV_STATUS:
5214 case DM_DEV_WAIT:
5215 case DM_TABLE_STATUS:
5216 case DM_TABLE_CLEAR:
5217 case DM_TABLE_DEPS:
5218 case DM_LIST_VERSIONS:
5219 /* no input data */
5220 break;
5221 case DM_DEV_RENAME:
5222 case DM_DEV_SET_GEOMETRY:
5223 /* data contains only strings */
5224 memcpy(host_data, argptr, guest_data_size);
5225 break;
5226 case DM_TARGET_MSG:
5227 memcpy(host_data, argptr, guest_data_size);
5228 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5229 break;
5230 case DM_TABLE_LOAD:
5231 {
5232 void *gspec = argptr;
5233 void *cur_data = host_data;
5234 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5235 int spec_size = thunk_type_size(arg_type, 0);
5236 int i;
5237
5238 for (i = 0; i < host_dm->target_count; i++) {
5239 struct dm_target_spec *spec = cur_data;
5240 uint32_t next;
5241 int slen;
5242
5243 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5244 slen = strlen((char*)gspec + spec_size) + 1;
5245 next = spec->next;
5246 spec->next = sizeof(*spec) + slen;
5247 strcpy((char*)&spec[1], gspec + spec_size);
5248 gspec += next;
5249 cur_data += spec->next;
5250 }
5251 break;
5252 }
5253 default:
5254 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005255 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005256 goto out;
5257 }
5258 unlock_user(argptr, guest_data, 0);
5259
Peter Maydell49ca6f32016-06-06 19:58:14 +01005260 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005261 if (!is_error(ret)) {
5262 guest_data = arg + host_dm->data_start;
5263 guest_data_size = host_dm->data_size - host_dm->data_start;
5264 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5265 switch (ie->host_cmd) {
5266 case DM_REMOVE_ALL:
5267 case DM_DEV_CREATE:
5268 case DM_DEV_REMOVE:
5269 case DM_DEV_RENAME:
5270 case DM_DEV_SUSPEND:
5271 case DM_DEV_STATUS:
5272 case DM_TABLE_LOAD:
5273 case DM_TABLE_CLEAR:
5274 case DM_TARGET_MSG:
5275 case DM_DEV_SET_GEOMETRY:
5276 /* no return data */
5277 break;
5278 case DM_LIST_DEVICES:
5279 {
5280 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5281 uint32_t remaining_data = guest_data_size;
5282 void *cur_data = argptr;
5283 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5284 int nl_size = 12; /* can't use thunk_size due to alignment */
5285
5286 while (1) {
5287 uint32_t next = nl->next;
5288 if (next) {
5289 nl->next = nl_size + (strlen(nl->name) + 1);
5290 }
5291 if (remaining_data < nl->next) {
5292 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5293 break;
5294 }
5295 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5296 strcpy(cur_data + nl_size, nl->name);
5297 cur_data += nl->next;
5298 remaining_data -= nl->next;
5299 if (!next) {
5300 break;
5301 }
5302 nl = (void*)nl + next;
5303 }
5304 break;
5305 }
5306 case DM_DEV_WAIT:
5307 case DM_TABLE_STATUS:
5308 {
5309 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5310 void *cur_data = argptr;
5311 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5312 int spec_size = thunk_type_size(arg_type, 0);
5313 int i;
5314
5315 for (i = 0; i < host_dm->target_count; i++) {
5316 uint32_t next = spec->next;
5317 int slen = strlen((char*)&spec[1]) + 1;
5318 spec->next = (cur_data - argptr) + spec_size + slen;
5319 if (guest_data_size < spec->next) {
5320 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5321 break;
5322 }
5323 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5324 strcpy(cur_data + spec_size, (char*)&spec[1]);
5325 cur_data = argptr + spec->next;
5326 spec = (void*)host_dm + host_dm->data_start + next;
5327 }
5328 break;
5329 }
5330 case DM_TABLE_DEPS:
5331 {
5332 void *hdata = (void*)host_dm + host_dm->data_start;
5333 int count = *(uint32_t*)hdata;
5334 uint64_t *hdev = hdata + 8;
5335 uint64_t *gdev = argptr + 8;
5336 int i;
5337
5338 *(uint32_t*)argptr = tswap32(count);
5339 for (i = 0; i < count; i++) {
5340 *gdev = tswap64(*hdev);
5341 gdev++;
5342 hdev++;
5343 }
5344 break;
5345 }
5346 case DM_LIST_VERSIONS:
5347 {
5348 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5349 uint32_t remaining_data = guest_data_size;
5350 void *cur_data = argptr;
5351 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5352 int vers_size = thunk_type_size(arg_type, 0);
5353
5354 while (1) {
5355 uint32_t next = vers->next;
5356 if (next) {
5357 vers->next = vers_size + (strlen(vers->name) + 1);
5358 }
5359 if (remaining_data < vers->next) {
5360 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5361 break;
5362 }
5363 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5364 strcpy(cur_data + vers_size, vers->name);
5365 cur_data += vers->next;
5366 remaining_data -= vers->next;
5367 if (!next) {
5368 break;
5369 }
5370 vers = (void*)vers + next;
5371 }
5372 break;
5373 }
5374 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005375 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005376 ret = -TARGET_EINVAL;
5377 goto out;
5378 }
5379 unlock_user(argptr, guest_data, guest_data_size);
5380
5381 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5382 if (!argptr) {
5383 ret = -TARGET_EFAULT;
5384 goto out;
5385 }
5386 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5387 unlock_user(argptr, arg, target_size);
5388 }
5389out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005390 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005391 return ret;
5392}
5393
Alexander Grafa59b5e32014-08-22 13:15:50 +02005394static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005395 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005396{
5397 void *argptr;
5398 int target_size;
5399 const argtype *arg_type = ie->arg_type;
5400 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5401 abi_long ret;
5402
5403 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5404 struct blkpg_partition host_part;
5405
5406 /* Read and convert blkpg */
5407 arg_type++;
5408 target_size = thunk_type_size(arg_type, 0);
5409 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5410 if (!argptr) {
5411 ret = -TARGET_EFAULT;
5412 goto out;
5413 }
5414 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5415 unlock_user(argptr, arg, 0);
5416
5417 switch (host_blkpg->op) {
5418 case BLKPG_ADD_PARTITION:
5419 case BLKPG_DEL_PARTITION:
5420 /* payload is struct blkpg_partition */
5421 break;
5422 default:
5423 /* Unknown opcode */
5424 ret = -TARGET_EINVAL;
5425 goto out;
5426 }
5427
5428 /* Read and convert blkpg->data */
5429 arg = (abi_long)(uintptr_t)host_blkpg->data;
5430 target_size = thunk_type_size(part_arg_type, 0);
5431 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5432 if (!argptr) {
5433 ret = -TARGET_EFAULT;
5434 goto out;
5435 }
5436 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5437 unlock_user(argptr, arg, 0);
5438
5439 /* Swizzle the data pointer to our local copy and call! */
5440 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005441 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005442
5443out:
5444 return ret;
5445}
5446
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005447static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005448 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005449{
5450 const argtype *arg_type = ie->arg_type;
5451 const StructEntry *se;
5452 const argtype *field_types;
5453 const int *dst_offsets, *src_offsets;
5454 int target_size;
5455 void *argptr;
Marc-André Lureaub78c5222019-03-05 16:15:00 +01005456 abi_ulong *target_rt_dev_ptr = NULL;
5457 unsigned long *host_rt_dev_ptr = NULL;
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005458 abi_long ret;
5459 int i;
5460
5461 assert(ie->access == IOC_W);
5462 assert(*arg_type == TYPE_PTR);
5463 arg_type++;
5464 assert(*arg_type == TYPE_STRUCT);
5465 target_size = thunk_type_size(arg_type, 0);
5466 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5467 if (!argptr) {
5468 return -TARGET_EFAULT;
5469 }
5470 arg_type++;
5471 assert(*arg_type == (int)STRUCT_rtentry);
5472 se = struct_entries + *arg_type++;
5473 assert(se->convert[0] == NULL);
5474 /* convert struct here to be able to catch rt_dev string */
5475 field_types = se->field_types;
5476 dst_offsets = se->field_offsets[THUNK_HOST];
5477 src_offsets = se->field_offsets[THUNK_TARGET];
5478 for (i = 0; i < se->nb_fields; i++) {
5479 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5480 assert(*field_types == TYPE_PTRVOID);
5481 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5482 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5483 if (*target_rt_dev_ptr != 0) {
5484 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5485 tswapal(*target_rt_dev_ptr));
5486 if (!*host_rt_dev_ptr) {
5487 unlock_user(argptr, arg, 0);
5488 return -TARGET_EFAULT;
5489 }
5490 } else {
5491 *host_rt_dev_ptr = 0;
5492 }
5493 field_types++;
5494 continue;
5495 }
5496 field_types = thunk_convert(buf_temp + dst_offsets[i],
5497 argptr + src_offsets[i],
5498 field_types, THUNK_HOST);
5499 }
5500 unlock_user(argptr, arg, 0);
5501
Peter Maydell49ca6f32016-06-06 19:58:14 +01005502 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Marc-André Lureaub78c5222019-03-05 16:15:00 +01005503
5504 assert(host_rt_dev_ptr != NULL);
5505 assert(target_rt_dev_ptr != NULL);
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005506 if (*host_rt_dev_ptr != 0) {
5507 unlock_user((void *)*host_rt_dev_ptr,
5508 *target_rt_dev_ptr, 0);
5509 }
5510 return ret;
5511}
5512
Paul Burtonca56f5b2014-06-22 11:25:47 +01005513static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005514 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005515{
5516 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005517 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005518}
5519
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02005520static abi_long do_ioctl_SIOCGSTAMP(const IOCTLEntry *ie, uint8_t *buf_temp,
5521 int fd, int cmd, abi_long arg)
5522{
5523 struct timeval tv;
5524 abi_long ret;
5525
5526 ret = get_errno(safe_ioctl(fd, SIOCGSTAMP, &tv));
5527 if (is_error(ret)) {
5528 return ret;
5529 }
5530
5531 if (cmd == (int)TARGET_SIOCGSTAMP_OLD) {
5532 if (copy_to_user_timeval(arg, &tv)) {
5533 return -TARGET_EFAULT;
5534 }
5535 } else {
5536 if (copy_to_user_timeval64(arg, &tv)) {
5537 return -TARGET_EFAULT;
5538 }
5539 }
5540
5541 return ret;
5542}
5543
5544static abi_long do_ioctl_SIOCGSTAMPNS(const IOCTLEntry *ie, uint8_t *buf_temp,
5545 int fd, int cmd, abi_long arg)
5546{
5547 struct timespec ts;
5548 abi_long ret;
5549
5550 ret = get_errno(safe_ioctl(fd, SIOCGSTAMPNS, &ts));
5551 if (is_error(ret)) {
5552 return ret;
5553 }
5554
5555 if (cmd == (int)TARGET_SIOCGSTAMPNS_OLD) {
5556 if (host_to_target_timespec(arg, &ts)) {
5557 return -TARGET_EFAULT;
5558 }
5559 } else{
5560 if (host_to_target_timespec64(arg, &ts)) {
5561 return -TARGET_EFAULT;
5562 }
5563 }
5564
5565 return ret;
5566}
5567
Andreas Schwab2b74f622018-01-29 11:47:06 +01005568#ifdef TIOCGPTPEER
5569static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5570 int fd, int cmd, abi_long arg)
5571{
5572 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5573 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5574}
5575#endif
5576
Chen Gange865b972020-06-05 09:32:21 +08005577#ifdef HAVE_DRM_H
5578
5579static void unlock_drm_version(struct drm_version *host_ver,
5580 struct target_drm_version *target_ver,
5581 bool copy)
5582{
5583 unlock_user(host_ver->name, target_ver->name,
5584 copy ? host_ver->name_len : 0);
5585 unlock_user(host_ver->date, target_ver->date,
5586 copy ? host_ver->date_len : 0);
5587 unlock_user(host_ver->desc, target_ver->desc,
5588 copy ? host_ver->desc_len : 0);
5589}
5590
5591static inline abi_long target_to_host_drmversion(struct drm_version *host_ver,
5592 struct target_drm_version *target_ver)
5593{
5594 memset(host_ver, 0, sizeof(*host_ver));
5595
5596 __get_user(host_ver->name_len, &target_ver->name_len);
5597 if (host_ver->name_len) {
5598 host_ver->name = lock_user(VERIFY_WRITE, target_ver->name,
5599 target_ver->name_len, 0);
5600 if (!host_ver->name) {
5601 return -EFAULT;
5602 }
5603 }
5604
5605 __get_user(host_ver->date_len, &target_ver->date_len);
5606 if (host_ver->date_len) {
5607 host_ver->date = lock_user(VERIFY_WRITE, target_ver->date,
5608 target_ver->date_len, 0);
5609 if (!host_ver->date) {
5610 goto err;
5611 }
5612 }
5613
5614 __get_user(host_ver->desc_len, &target_ver->desc_len);
5615 if (host_ver->desc_len) {
5616 host_ver->desc = lock_user(VERIFY_WRITE, target_ver->desc,
5617 target_ver->desc_len, 0);
5618 if (!host_ver->desc) {
5619 goto err;
5620 }
5621 }
5622
5623 return 0;
5624err:
5625 unlock_drm_version(host_ver, target_ver, false);
5626 return -EFAULT;
5627}
5628
5629static inline void host_to_target_drmversion(
5630 struct target_drm_version *target_ver,
5631 struct drm_version *host_ver)
5632{
5633 __put_user(host_ver->version_major, &target_ver->version_major);
5634 __put_user(host_ver->version_minor, &target_ver->version_minor);
5635 __put_user(host_ver->version_patchlevel, &target_ver->version_patchlevel);
5636 __put_user(host_ver->name_len, &target_ver->name_len);
5637 __put_user(host_ver->date_len, &target_ver->date_len);
5638 __put_user(host_ver->desc_len, &target_ver->desc_len);
5639 unlock_drm_version(host_ver, target_ver, true);
5640}
5641
5642static abi_long do_ioctl_drm(const IOCTLEntry *ie, uint8_t *buf_temp,
5643 int fd, int cmd, abi_long arg)
5644{
5645 struct drm_version *ver;
5646 struct target_drm_version *target_ver;
5647 abi_long ret;
5648
5649 switch (ie->host_cmd) {
5650 case DRM_IOCTL_VERSION:
5651 if (!lock_user_struct(VERIFY_WRITE, target_ver, arg, 0)) {
5652 return -TARGET_EFAULT;
5653 }
5654 ver = (struct drm_version *)buf_temp;
5655 ret = target_to_host_drmversion(ver, target_ver);
5656 if (!is_error(ret)) {
5657 ret = get_errno(safe_ioctl(fd, ie->host_cmd, ver));
5658 if (is_error(ret)) {
5659 unlock_drm_version(ver, target_ver, false);
5660 } else {
5661 host_to_target_drmversion(target_ver, ver);
5662 }
5663 }
5664 unlock_user_struct(target_ver, arg, 0);
5665 return ret;
5666 }
5667 return -TARGET_ENOSYS;
5668}
5669
Chen Gang913b03c2020-08-02 21:39:38 +08005670static abi_long do_ioctl_drm_i915_getparam(const IOCTLEntry *ie,
5671 struct drm_i915_getparam *gparam,
5672 int fd, abi_long arg)
5673{
5674 abi_long ret;
5675 int value;
5676 struct target_drm_i915_getparam *target_gparam;
5677
5678 if (!lock_user_struct(VERIFY_READ, target_gparam, arg, 0)) {
5679 return -TARGET_EFAULT;
5680 }
5681
5682 __get_user(gparam->param, &target_gparam->param);
5683 gparam->value = &value;
5684 ret = get_errno(safe_ioctl(fd, ie->host_cmd, gparam));
5685 put_user_s32(value, target_gparam->value);
5686
5687 unlock_user_struct(target_gparam, arg, 0);
5688 return ret;
5689}
5690
5691static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp,
5692 int fd, int cmd, abi_long arg)
5693{
5694 switch (ie->host_cmd) {
5695 case DRM_IOCTL_I915_GETPARAM:
5696 return do_ioctl_drm_i915_getparam(ie,
5697 (struct drm_i915_getparam *)buf_temp,
5698 fd, arg);
5699 default:
5700 return -TARGET_ENOSYS;
5701 }
5702}
5703
Chen Gange865b972020-06-05 09:32:21 +08005704#endif
5705
Filip Bozuta79482e592020-06-19 14:47:27 +02005706IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005707#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005708 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5709#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5710 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005711#define IOCTL_IGNORE(cmd) \
5712 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005713#include "ioctls.h"
5714 { 0, 0, },
5715};
5716
pbrook53a59602006-03-25 19:31:22 +00005717/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005718/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005719static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005720{
5721 const IOCTLEntry *ie;
5722 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005723 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005724 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005725 int target_size;
5726 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005727
5728 ie = ioctl_entries;
5729 for(;;) {
5730 if (ie->target_cmd == 0) {
Josh Kunz39be5352020-02-03 18:54:13 -08005731 qemu_log_mask(
5732 LOG_UNIMP, "Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005733 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005734 }
5735 if (ie->target_cmd == cmd)
5736 break;
5737 ie++;
5738 }
5739 arg_type = ie->arg_type;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005740 if (ie->do_ioctl) {
5741 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005742 } else if (!ie->host_cmd) {
5743 /* Some architectures define BSD ioctls in their headers
5744 that are not implemented in Linux. */
5745 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005746 }
5747
bellard31e31b82003-02-18 22:55:36 +00005748 switch(arg_type[0]) {
5749 case TYPE_NULL:
5750 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005751 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005752 break;
5753 case TYPE_PTRVOID:
5754 case TYPE_INT:
Filip Bozutac858e532020-01-15 20:36:47 +01005755 case TYPE_LONG:
5756 case TYPE_ULONG:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005757 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005758 break;
5759 case TYPE_PTR:
5760 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005761 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005762 switch(ie->access) {
5763 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005764 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005765 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005766 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5767 if (!argptr)
5768 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005769 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5770 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005771 }
5772 break;
5773 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005774 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5775 if (!argptr)
5776 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005777 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5778 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005779 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005780 break;
5781 default:
5782 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005783 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5784 if (!argptr)
5785 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005786 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5787 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005788 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005789 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005790 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5791 if (!argptr)
5792 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005793 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5794 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005795 }
5796 break;
5797 }
5798 break;
5799 default:
Josh Kunz39be5352020-02-03 18:54:13 -08005800 qemu_log_mask(LOG_UNIMP,
5801 "Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5802 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005803 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005804 break;
5805 }
5806 return ret;
5807}
5808
blueswir1b39bc502008-10-05 10:51:10 +00005809static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005810 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5811 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5812 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5813 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5814 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5815 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5816 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5817 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5818 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5819 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5820 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5821 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5822 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5823 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
Filip Bozutac218b4e2020-07-23 23:02:32 +02005824 { TARGET_IUTF8, TARGET_IUTF8, IUTF8, IUTF8},
bellard31e31b82003-02-18 22:55:36 +00005825 { 0, 0, 0, 0 }
5826};
5827
blueswir1b39bc502008-10-05 10:51:10 +00005828static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005829 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5830 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5831 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5832 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5833 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5834 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5835 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5836 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5837 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5838 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5839 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5840 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5841 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5842 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5843 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5844 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5845 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5846 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5847 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5848 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5849 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5850 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5851 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5852 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5853 { 0, 0, 0, 0 }
5854};
5855
blueswir1b39bc502008-10-05 10:51:10 +00005856static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005857 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5858 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5859 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5860 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5861 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5862 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5863 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5864 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5865 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5866 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5867 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5868 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5869 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5870 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5871 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5872 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5873 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5874 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5875 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5876 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5877 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5878 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5879 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5880 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5881 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5882 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5883 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5884 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5885 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5886 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5887 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5888 { 0, 0, 0, 0 }
5889};
5890
blueswir1b39bc502008-10-05 10:51:10 +00005891static const bitmask_transtbl lflag_tbl[] = {
Filip Bozutac218b4e2020-07-23 23:02:32 +02005892 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5893 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5894 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5895 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5896 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5897 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5898 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5899 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5900 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5901 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5902 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5903 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5904 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5905 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5906 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5907 { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC},
5908 { 0, 0, 0, 0 }
bellard31e31b82003-02-18 22:55:36 +00005909};
5910
5911static void target_to_host_termios (void *dst, const void *src)
5912{
5913 struct host_termios *host = dst;
5914 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005915
ths5fafdf22007-09-16 21:08:06 +00005916 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005917 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005918 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005919 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005920 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005921 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005922 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005923 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5924 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005925
Arnaud Patard44607122009-04-21 17:39:08 +03005926 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005927 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5928 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005929 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005930 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005931 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005932 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005933 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005934 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005935 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005936 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5937 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005938 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5939 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5940 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5941 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5942 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005943 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005944}
ths3b46e622007-09-17 08:09:54 +00005945
bellard31e31b82003-02-18 22:55:36 +00005946static void host_to_target_termios (void *dst, const void *src)
5947{
5948 struct target_termios *target = dst;
5949 const struct host_termios *host = src;
5950
ths5fafdf22007-09-16 21:08:06 +00005951 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005952 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005953 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005954 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005955 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005956 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005957 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005958 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5959 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005960
Arnaud Patard44607122009-04-21 17:39:08 +03005961 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005962 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5963 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5964 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5965 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5966 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5967 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5968 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5969 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5970 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5971 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5972 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5973 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5974 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5975 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5976 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5977 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5978 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5979}
5980
blueswir18e853dc2008-10-05 10:49:32 +00005981static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005982 .convert = { host_to_target_termios, target_to_host_termios },
5983 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5984 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
Filip Bozuta888468d2020-07-23 23:02:33 +02005985 .print = print_termios,
bellard31e31b82003-02-18 22:55:36 +00005986};
5987
bellard5286db72003-06-05 00:57:30 +00005988static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005989 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5990 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5991 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5992 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5993 MAP_ANONYMOUS, MAP_ANONYMOUS },
5994 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5995 MAP_GROWSDOWN, MAP_GROWSDOWN },
5996 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5997 MAP_DENYWRITE, MAP_DENYWRITE },
5998 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5999 MAP_EXECUTABLE, MAP_EXECUTABLE },
6000 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
6001 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
6002 MAP_NORESERVE, MAP_NORESERVE },
6003 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
6004 /* MAP_STACK had been ignored by the kernel for quite some time.
6005 Recognize it for the target insofar as we do not want to pass
6006 it through to the host. */
6007 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
6008 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00006009};
6010
Laurent Vivier9d12f792020-03-10 11:33:55 +01006011/*
6012 * NOTE: TARGET_ABI32 is defined for TARGET_I386 (but not for TARGET_X86_64)
6013 * TARGET_I386 is defined if TARGET_X86_64 is defined
6014 */
bellard2ab83ea2003-06-15 19:56:46 +00006015#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00006016
6017/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00006018static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00006019
bellard03acab62007-11-11 14:57:14 +00006020static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006021{
6022 int size;
pbrook53a59602006-03-25 19:31:22 +00006023 void *p;
bellard6dbad632003-03-16 18:05:05 +00006024
6025 if (!ldt_table)
6026 return 0;
6027 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
6028 if (size > bytecount)
6029 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00006030 p = lock_user(VERIFY_WRITE, ptr, size, 0);
6031 if (!p)
bellard03acab62007-11-11 14:57:14 +00006032 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00006033 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00006034 memcpy(p, ldt_table, size);
6035 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00006036 return size;
6037}
6038
6039/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00006040static abi_long write_ldt(CPUX86State *env,
6041 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00006042{
6043 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00006044 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00006045 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00006046 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00006047 uint32_t *lp, entry_1, entry_2;
6048
6049 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00006050 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00006051 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00006052 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00006053 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006054 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00006055 ldt_info.limit = tswap32(target_ldt_info->limit);
6056 ldt_info.flags = tswap32(target_ldt_info->flags);
6057 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00006058
bellard6dbad632003-03-16 18:05:05 +00006059 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00006060 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006061 seg_32bit = ldt_info.flags & 1;
6062 contents = (ldt_info.flags >> 1) & 3;
6063 read_exec_only = (ldt_info.flags >> 3) & 1;
6064 limit_in_pages = (ldt_info.flags >> 4) & 1;
6065 seg_not_present = (ldt_info.flags >> 5) & 1;
6066 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00006067#ifdef TARGET_ABI32
6068 lm = 0;
6069#else
6070 lm = (ldt_info.flags >> 7) & 1;
6071#endif
bellard6dbad632003-03-16 18:05:05 +00006072 if (contents == 3) {
6073 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00006074 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006075 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00006076 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006077 }
6078 /* allocate the LDT */
6079 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006080 env->ldt.base = target_mmap(0,
6081 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6082 PROT_READ|PROT_WRITE,
6083 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6084 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006085 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00006086 memset(g2h(env->ldt.base), 0,
6087 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006088 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006089 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006090 }
6091
6092 /* NOTE: same code as Linux kernel */
6093 /* Allow LDTs to be cleared by the user. */
6094 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6095 if (oldmode ||
6096 (contents == 0 &&
6097 read_exec_only == 1 &&
6098 seg_32bit == 0 &&
6099 limit_in_pages == 0 &&
6100 seg_not_present == 1 &&
6101 useable == 0 )) {
6102 entry_1 = 0;
6103 entry_2 = 0;
6104 goto install;
6105 }
6106 }
ths3b46e622007-09-17 08:09:54 +00006107
bellard6dbad632003-03-16 18:05:05 +00006108 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6109 (ldt_info.limit & 0x0ffff);
6110 entry_2 = (ldt_info.base_addr & 0xff000000) |
6111 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6112 (ldt_info.limit & 0xf0000) |
6113 ((read_exec_only ^ 1) << 9) |
6114 (contents << 10) |
6115 ((seg_not_present ^ 1) << 15) |
6116 (seg_32bit << 22) |
6117 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006118 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006119 0x7000;
6120 if (!oldmode)
6121 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006122
bellard6dbad632003-03-16 18:05:05 +00006123 /* Install the new entry ... */
6124install:
6125 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6126 lp[0] = tswap32(entry_1);
6127 lp[1] = tswap32(entry_2);
6128 return 0;
6129}
6130
6131/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006132static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6133 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006134{
bellard03acab62007-11-11 14:57:14 +00006135 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006136
bellard6dbad632003-03-16 18:05:05 +00006137 switch (func) {
6138 case 0:
6139 ret = read_ldt(ptr, bytecount);
6140 break;
6141 case 1:
6142 ret = write_ldt(env, ptr, bytecount, 1);
6143 break;
6144 case 0x11:
6145 ret = write_ldt(env, ptr, bytecount, 0);
6146 break;
bellard03acab62007-11-11 14:57:14 +00006147 default:
6148 ret = -TARGET_ENOSYS;
6149 break;
bellard6dbad632003-03-16 18:05:05 +00006150 }
6151 return ret;
6152}
bellard1b6b0292003-03-22 17:31:38 +00006153
Laurent Vivier9d12f792020-03-10 11:33:55 +01006154#if defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006155abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006156{
6157 uint64_t *gdt_table = g2h(env->gdt.base);
6158 struct target_modify_ldt_ldt_s ldt_info;
6159 struct target_modify_ldt_ldt_s *target_ldt_info;
6160 int seg_32bit, contents, read_exec_only, limit_in_pages;
6161 int seg_not_present, useable, lm;
6162 uint32_t *lp, entry_1, entry_2;
6163 int i;
6164
6165 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6166 if (!target_ldt_info)
6167 return -TARGET_EFAULT;
6168 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006169 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006170 ldt_info.limit = tswap32(target_ldt_info->limit);
6171 ldt_info.flags = tswap32(target_ldt_info->flags);
6172 if (ldt_info.entry_number == -1) {
6173 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6174 if (gdt_table[i] == 0) {
6175 ldt_info.entry_number = i;
6176 target_ldt_info->entry_number = tswap32(i);
6177 break;
6178 }
6179 }
6180 }
6181 unlock_user_struct(target_ldt_info, ptr, 1);
6182
6183 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6184 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6185 return -TARGET_EINVAL;
6186 seg_32bit = ldt_info.flags & 1;
6187 contents = (ldt_info.flags >> 1) & 3;
6188 read_exec_only = (ldt_info.flags >> 3) & 1;
6189 limit_in_pages = (ldt_info.flags >> 4) & 1;
6190 seg_not_present = (ldt_info.flags >> 5) & 1;
6191 useable = (ldt_info.flags >> 6) & 1;
6192#ifdef TARGET_ABI32
6193 lm = 0;
6194#else
6195 lm = (ldt_info.flags >> 7) & 1;
6196#endif
6197
6198 if (contents == 3) {
6199 if (seg_not_present == 0)
6200 return -TARGET_EINVAL;
6201 }
6202
6203 /* NOTE: same code as Linux kernel */
6204 /* Allow LDTs to be cleared by the user. */
6205 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6206 if ((contents == 0 &&
6207 read_exec_only == 1 &&
6208 seg_32bit == 0 &&
6209 limit_in_pages == 0 &&
6210 seg_not_present == 1 &&
6211 useable == 0 )) {
6212 entry_1 = 0;
6213 entry_2 = 0;
6214 goto install;
6215 }
6216 }
6217
6218 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6219 (ldt_info.limit & 0x0ffff);
6220 entry_2 = (ldt_info.base_addr & 0xff000000) |
6221 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6222 (ldt_info.limit & 0xf0000) |
6223 ((read_exec_only ^ 1) << 9) |
6224 (contents << 10) |
6225 ((seg_not_present ^ 1) << 15) |
6226 (seg_32bit << 22) |
6227 (limit_in_pages << 23) |
6228 (useable << 20) |
6229 (lm << 21) |
6230 0x7000;
6231
6232 /* Install the new entry ... */
6233install:
6234 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6235 lp[0] = tswap32(entry_1);
6236 lp[1] = tswap32(entry_2);
6237 return 0;
6238}
6239
blueswir18fcd3692008-08-17 20:26:25 +00006240static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006241{
6242 struct target_modify_ldt_ldt_s *target_ldt_info;
6243 uint64_t *gdt_table = g2h(env->gdt.base);
6244 uint32_t base_addr, limit, flags;
6245 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6246 int seg_not_present, useable, lm;
6247 uint32_t *lp, entry_1, entry_2;
6248
6249 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6250 if (!target_ldt_info)
6251 return -TARGET_EFAULT;
6252 idx = tswap32(target_ldt_info->entry_number);
6253 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6254 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6255 unlock_user_struct(target_ldt_info, ptr, 1);
6256 return -TARGET_EINVAL;
6257 }
6258 lp = (uint32_t *)(gdt_table + idx);
6259 entry_1 = tswap32(lp[0]);
6260 entry_2 = tswap32(lp[1]);
6261
6262 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6263 contents = (entry_2 >> 10) & 3;
6264 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6265 seg_32bit = (entry_2 >> 22) & 1;
6266 limit_in_pages = (entry_2 >> 23) & 1;
6267 useable = (entry_2 >> 20) & 1;
6268#ifdef TARGET_ABI32
6269 lm = 0;
6270#else
6271 lm = (entry_2 >> 21) & 1;
6272#endif
6273 flags = (seg_32bit << 0) | (contents << 1) |
6274 (read_exec_only << 3) | (limit_in_pages << 4) |
6275 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6276 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6277 base_addr = (entry_1 >> 16) |
6278 (entry_2 & 0xff000000) |
6279 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006280 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006281 target_ldt_info->limit = tswap32(limit);
6282 target_ldt_info->flags = tswap32(flags);
6283 unlock_user_struct(target_ldt_info, ptr, 1);
6284 return 0;
6285}
6286
Laurent Vivier9d12f792020-03-10 11:33:55 +01006287abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
6288{
Helge Deller538fabc2020-04-25 00:00:33 +02006289 return -TARGET_ENOSYS;
Laurent Vivier9d12f792020-03-10 11:33:55 +01006290}
6291#else
Peter Maydell2667e712013-07-16 18:44:59 +01006292abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006293{
Juan Quintela1add8692011-06-16 17:37:09 +01006294 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006295 abi_ulong val;
6296 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006297
bellardd2fd1af2007-11-14 18:08:56 +00006298 switch(code) {
6299 case TARGET_ARCH_SET_GS:
6300 case TARGET_ARCH_SET_FS:
6301 if (code == TARGET_ARCH_SET_GS)
6302 idx = R_GS;
6303 else
6304 idx = R_FS;
6305 cpu_x86_load_seg(env, idx, 0);
6306 env->segs[idx].base = addr;
6307 break;
6308 case TARGET_ARCH_GET_GS:
6309 case TARGET_ARCH_GET_FS:
6310 if (code == TARGET_ARCH_GET_GS)
6311 idx = R_GS;
6312 else
6313 idx = R_FS;
6314 val = env->segs[idx].base;
6315 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006316 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006317 break;
6318 default:
6319 ret = -TARGET_EINVAL;
6320 break;
6321 }
Juan Quintela1add8692011-06-16 17:37:09 +01006322 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006323}
Laurent Vivier9d12f792020-03-10 11:33:55 +01006324#endif /* defined(TARGET_ABI32 */
bellardd2fd1af2007-11-14 18:08:56 +00006325
bellard2ab83ea2003-06-15 19:56:46 +00006326#endif /* defined(TARGET_I386) */
6327
Riku Voipio05098a92011-03-04 15:27:29 +02006328#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006329
pbrookd865bab2008-06-07 22:12:17 +00006330
6331static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6332typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006333 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006334 pthread_mutex_t mutex;
6335 pthread_cond_t cond;
6336 pthread_t thread;
6337 uint32_t tid;
6338 abi_ulong child_tidptr;
6339 abi_ulong parent_tidptr;
6340 sigset_t sigmask;
6341} new_thread_info;
6342
6343static void *clone_func(void *arg)
6344{
6345 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006346 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006347 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006348 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006349
Emilio G. Cota70903762015-08-23 20:23:41 -04006350 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006351 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006352 env = info->env;
Richard Henderson29a0af62019-03-22 16:07:18 -07006353 cpu = env_cpu(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006354 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006355 ts = (TaskState *)cpu->opaque;
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006356 info->tid = sys_gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006357 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006358 if (info->child_tidptr)
6359 put_user_u32(info->tid, info->child_tidptr);
6360 if (info->parent_tidptr)
6361 put_user_u32(info->tid, info->parent_tidptr);
Richard Henderson5ebdd772019-03-14 13:10:53 -07006362 qemu_guest_random_seed_thread_part2(cpu->random_seed);
pbrookd865bab2008-06-07 22:12:17 +00006363 /* Enable signals. */
6364 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6365 /* Signal to the parent that we're ready. */
6366 pthread_mutex_lock(&info->mutex);
6367 pthread_cond_broadcast(&info->cond);
6368 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006369 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006370 pthread_mutex_lock(&clone_lock);
6371 pthread_mutex_unlock(&clone_lock);
6372 cpu_loop(env);
6373 /* never exits */
6374 return NULL;
6375}
bellard1b6b0292003-03-22 17:31:38 +00006376
ths0da46a62007-10-20 20:23:07 +00006377/* do_fork() Must return host values and target errnos (unlike most
6378 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006379static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006380 abi_ulong parent_tidptr, target_ulong newtls,
6381 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006382{
Richard Henderson29a0af62019-03-22 16:07:18 -07006383 CPUState *cpu = env_cpu(env);
bellard1b6b0292003-03-22 17:31:38 +00006384 int ret;
bellard5cd43932003-03-29 16:54:36 +00006385 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006386 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006387 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006388 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006389
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006390 flags &= ~CLONE_IGNORED_FLAGS;
6391
balrog436d1242008-09-21 02:39:45 +00006392 /* Emulate vfork() with fork() */
6393 if (flags & CLONE_VFORK)
6394 flags &= ~(CLONE_VFORK | CLONE_VM);
6395
bellard1b6b0292003-03-22 17:31:38 +00006396 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006397 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006398 new_thread_info info;
6399 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006400
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006401 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6402 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6403 return -TARGET_EINVAL;
6404 }
6405
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006406 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006407 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006408
6409 /* Grab a mutex so that thread setup appears atomic. */
6410 pthread_mutex_lock(&clone_lock);
6411
bellard1b6b0292003-03-22 17:31:38 +00006412 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006413 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006414 /* Init regs that differ from the parent. */
Richard Henderson608999d2019-11-06 12:33:15 +01006415 cpu_clone_regs_child(new_env, newsp, flags);
Richard Henderson07a6ecf2019-11-06 12:33:16 +01006416 cpu_clone_regs_parent(env, flags);
Richard Henderson29a0af62019-03-22 16:07:18 -07006417 new_cpu = env_cpu(new_env);
Andreas Färber0429a972013-08-26 18:14:44 +02006418 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006419 ts->bprm = parent_ts->bprm;
6420 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006421 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006422
Peter Maydell7cfbd382016-08-02 18:41:26 +01006423 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006424 ts->child_tidptr = child_tidptr;
6425 }
6426
Peter Maydell7cfbd382016-08-02 18:41:26 +01006427 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006428 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006429 }
pbrookd865bab2008-06-07 22:12:17 +00006430
pbrookd865bab2008-06-07 22:12:17 +00006431 memset(&info, 0, sizeof(info));
6432 pthread_mutex_init(&info.mutex, NULL);
6433 pthread_mutex_lock(&info.mutex);
6434 pthread_cond_init(&info.cond, NULL);
6435 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006436 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006437 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006438 }
6439 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006440 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006441 }
pbrookd865bab2008-06-07 22:12:17 +00006442
6443 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006444 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6445 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006446 /* It is not safe to deliver signals until the child has finished
6447 initializing, so temporarily block all signals. */
6448 sigfillset(&sigmask);
6449 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
Richard Henderson5ebdd772019-03-14 13:10:53 -07006450 cpu->random_seed = qemu_guest_random_seed_thread_part1();
pbrookd865bab2008-06-07 22:12:17 +00006451
Alex Bennéeb67cb682016-10-05 11:13:04 -07006452 /* If this is our first additional thread, we need to ensure we
6453 * generate code for parallel execution and flush old translations.
6454 */
6455 if (!parallel_cpus) {
6456 parallel_cpus = true;
6457 tb_flush(cpu);
6458 }
6459
pbrookd865bab2008-06-07 22:12:17 +00006460 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006461 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006462
6463 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6464 pthread_attr_destroy(&attr);
6465 if (ret == 0) {
6466 /* Wait for the child to initialize. */
6467 pthread_cond_wait(&info.cond, &info.mutex);
6468 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006469 } else {
6470 ret = -1;
6471 }
6472 pthread_mutex_unlock(&info.mutex);
6473 pthread_cond_destroy(&info.cond);
6474 pthread_mutex_destroy(&info.mutex);
6475 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006476 } else {
6477 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006478 if (flags & CLONE_INVALID_FORK_FLAGS) {
6479 return -TARGET_EINVAL;
6480 }
6481
6482 /* We can't support custom termination signals */
6483 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006484 return -TARGET_EINVAL;
6485 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006486
6487 if (block_signals()) {
6488 return -TARGET_ERESTARTSYS;
6489 }
6490
pbrookd865bab2008-06-07 22:12:17 +00006491 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006492 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006493 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006494 /* Child Process. */
Richard Henderson608999d2019-11-06 12:33:15 +01006495 cpu_clone_regs_child(env, newsp, flags);
pbrookd865bab2008-06-07 22:12:17 +00006496 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006497 /* There is a race condition here. The parent process could
6498 theoretically read the TID in the child process before the child
6499 tid is set. This would require using either ptrace
6500 (not implemented) or having *_tidptr to point at a shared memory
6501 mapping. We can't repeat the spinlock hack used above because
6502 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006503 if (flags & CLONE_CHILD_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006504 put_user_u32(sys_gettid(), child_tidptr);
pbrookd865bab2008-06-07 22:12:17 +00006505 if (flags & CLONE_PARENT_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006506 put_user_u32(sys_gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006507 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006508 if (flags & CLONE_SETTLS)
6509 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006510 if (flags & CLONE_CHILD_CLEARTID)
6511 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006512 } else {
Richard Henderson07a6ecf2019-11-06 12:33:16 +01006513 cpu_clone_regs_parent(env, flags);
pbrookd865bab2008-06-07 22:12:17 +00006514 fork_end(0);
6515 }
bellard1b6b0292003-03-22 17:31:38 +00006516 }
6517 return ret;
6518}
6519
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006520/* warning : doesn't handle linux specific flags... */
6521static int target_to_host_fcntl_cmd(int cmd)
6522{
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006523 int ret;
6524
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006525 switch(cmd) {
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006526 case TARGET_F_DUPFD:
6527 case TARGET_F_GETFD:
6528 case TARGET_F_SETFD:
6529 case TARGET_F_GETFL:
6530 case TARGET_F_SETFL:
Andreas Schwab2d92c682020-05-25 09:59:28 +02006531 case TARGET_F_OFD_GETLK:
6532 case TARGET_F_OFD_SETLK:
6533 case TARGET_F_OFD_SETLKW:
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006534 ret = cmd;
6535 break;
6536 case TARGET_F_GETLK:
6537 ret = F_GETLK64;
6538 break;
6539 case TARGET_F_SETLK:
6540 ret = F_SETLK64;
6541 break;
6542 case TARGET_F_SETLKW:
6543 ret = F_SETLKW64;
6544 break;
6545 case TARGET_F_GETOWN:
6546 ret = F_GETOWN;
6547 break;
6548 case TARGET_F_SETOWN:
6549 ret = F_SETOWN;
6550 break;
6551 case TARGET_F_GETSIG:
6552 ret = F_GETSIG;
6553 break;
6554 case TARGET_F_SETSIG:
6555 ret = F_SETSIG;
6556 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006557#if TARGET_ABI_BITS == 32
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006558 case TARGET_F_GETLK64:
6559 ret = F_GETLK64;
6560 break;
6561 case TARGET_F_SETLK64:
6562 ret = F_SETLK64;
6563 break;
6564 case TARGET_F_SETLKW64:
6565 ret = F_SETLKW64;
6566 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006567#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006568 case TARGET_F_SETLEASE:
6569 ret = F_SETLEASE;
6570 break;
6571 case TARGET_F_GETLEASE:
6572 ret = F_GETLEASE;
6573 break;
malcfbd5de92009-09-06 06:31:59 +04006574#ifdef F_DUPFD_CLOEXEC
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006575 case TARGET_F_DUPFD_CLOEXEC:
6576 ret = F_DUPFD_CLOEXEC;
6577 break;
malcfbd5de92009-09-06 06:31:59 +04006578#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006579 case TARGET_F_NOTIFY:
6580 ret = F_NOTIFY;
6581 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006582#ifdef F_GETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006583 case TARGET_F_GETOWN_EX:
6584 ret = F_GETOWN_EX;
6585 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006586#endif
6587#ifdef F_SETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006588 case TARGET_F_SETOWN_EX:
6589 ret = F_SETOWN_EX;
6590 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006591#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006592#ifdef F_SETPIPE_SZ
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006593 case TARGET_F_SETPIPE_SZ:
6594 ret = F_SETPIPE_SZ;
6595 break;
6596 case TARGET_F_GETPIPE_SZ:
6597 ret = F_GETPIPE_SZ;
6598 break;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006599#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006600 default:
6601 ret = -TARGET_EINVAL;
6602 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006603 }
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006604
6605#if defined(__powerpc64__)
6606 /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
6607 * is not supported by kernel. The glibc fcntl call actually adjusts
6608 * them to 5, 6 and 7 before making the syscall(). Since we make the
6609 * syscall directly, adjust to what is supported by the kernel.
6610 */
6611 if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
6612 ret -= F_GETLK64 - 5;
6613 }
6614#endif
6615
6616 return ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006617}
6618
Laurent Vivierae68ad92018-05-10 01:11:21 +02006619#define FLOCK_TRANSTBL \
6620 switch (type) { \
6621 TRANSTBL_CONVERT(F_RDLCK); \
6622 TRANSTBL_CONVERT(F_WRLCK); \
6623 TRANSTBL_CONVERT(F_UNLCK); \
6624 TRANSTBL_CONVERT(F_EXLCK); \
6625 TRANSTBL_CONVERT(F_SHLCK); \
6626 }
6627
6628static int target_to_host_flock(int type)
6629{
6630#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
6631 FLOCK_TRANSTBL
6632#undef TRANSTBL_CONVERT
6633 return -TARGET_EINVAL;
6634}
6635
6636static int host_to_target_flock(int type)
6637{
6638#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
6639 FLOCK_TRANSTBL
6640#undef TRANSTBL_CONVERT
6641 /* if we don't know how to convert the value coming
6642 * from the host we copy to the target field as-is
6643 */
6644 return type;
6645}
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006646
Peter Maydell213d3e92016-06-13 11:22:05 +01006647static inline abi_long copy_from_user_flock(struct flock64 *fl,
6648 abi_ulong target_flock_addr)
6649{
6650 struct target_flock *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006651 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006652
6653 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6654 return -TARGET_EFAULT;
6655 }
6656
6657 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006658 l_type = target_to_host_flock(l_type);
6659 if (l_type < 0) {
6660 return l_type;
6661 }
6662 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006663 __get_user(fl->l_whence, &target_fl->l_whence);
6664 __get_user(fl->l_start, &target_fl->l_start);
6665 __get_user(fl->l_len, &target_fl->l_len);
6666 __get_user(fl->l_pid, &target_fl->l_pid);
6667 unlock_user_struct(target_fl, target_flock_addr, 0);
6668 return 0;
6669}
6670
6671static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6672 const struct flock64 *fl)
6673{
6674 struct target_flock *target_fl;
6675 short l_type;
6676
6677 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6678 return -TARGET_EFAULT;
6679 }
6680
Laurent Vivierae68ad92018-05-10 01:11:21 +02006681 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006682 __put_user(l_type, &target_fl->l_type);
6683 __put_user(fl->l_whence, &target_fl->l_whence);
6684 __put_user(fl->l_start, &target_fl->l_start);
6685 __put_user(fl->l_len, &target_fl->l_len);
6686 __put_user(fl->l_pid, &target_fl->l_pid);
6687 unlock_user_struct(target_fl, target_flock_addr, 1);
6688 return 0;
6689}
6690
6691typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6692typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6693
6694#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
Laurent Vivier7f254c52018-05-02 23:57:30 +02006695static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006696 abi_ulong target_flock_addr)
6697{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006698 struct target_oabi_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006699 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006700
6701 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6702 return -TARGET_EFAULT;
6703 }
6704
6705 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006706 l_type = target_to_host_flock(l_type);
6707 if (l_type < 0) {
6708 return l_type;
6709 }
6710 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006711 __get_user(fl->l_whence, &target_fl->l_whence);
6712 __get_user(fl->l_start, &target_fl->l_start);
6713 __get_user(fl->l_len, &target_fl->l_len);
6714 __get_user(fl->l_pid, &target_fl->l_pid);
6715 unlock_user_struct(target_fl, target_flock_addr, 0);
6716 return 0;
6717}
6718
Laurent Vivier7f254c52018-05-02 23:57:30 +02006719static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
Peter Maydell213d3e92016-06-13 11:22:05 +01006720 const struct flock64 *fl)
6721{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006722 struct target_oabi_flock64 *target_fl;
Peter Maydell213d3e92016-06-13 11:22:05 +01006723 short l_type;
6724
6725 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6726 return -TARGET_EFAULT;
6727 }
6728
Laurent Vivierae68ad92018-05-10 01:11:21 +02006729 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006730 __put_user(l_type, &target_fl->l_type);
6731 __put_user(fl->l_whence, &target_fl->l_whence);
6732 __put_user(fl->l_start, &target_fl->l_start);
6733 __put_user(fl->l_len, &target_fl->l_len);
6734 __put_user(fl->l_pid, &target_fl->l_pid);
6735 unlock_user_struct(target_fl, target_flock_addr, 1);
6736 return 0;
6737}
6738#endif
6739
6740static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6741 abi_ulong target_flock_addr)
6742{
6743 struct target_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006744 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006745
6746 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6747 return -TARGET_EFAULT;
6748 }
6749
6750 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006751 l_type = target_to_host_flock(l_type);
6752 if (l_type < 0) {
6753 return l_type;
6754 }
6755 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006756 __get_user(fl->l_whence, &target_fl->l_whence);
6757 __get_user(fl->l_start, &target_fl->l_start);
6758 __get_user(fl->l_len, &target_fl->l_len);
6759 __get_user(fl->l_pid, &target_fl->l_pid);
6760 unlock_user_struct(target_fl, target_flock_addr, 0);
6761 return 0;
6762}
6763
6764static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6765 const struct flock64 *fl)
6766{
6767 struct target_flock64 *target_fl;
6768 short l_type;
6769
6770 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6771 return -TARGET_EFAULT;
6772 }
6773
Laurent Vivierae68ad92018-05-10 01:11:21 +02006774 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006775 __put_user(l_type, &target_fl->l_type);
6776 __put_user(fl->l_whence, &target_fl->l_whence);
6777 __put_user(fl->l_start, &target_fl->l_start);
6778 __put_user(fl->l_len, &target_fl->l_len);
6779 __put_user(fl->l_pid, &target_fl->l_pid);
6780 unlock_user_struct(target_fl, target_flock_addr, 1);
6781 return 0;
6782}
6783
blueswir1992f48a2007-10-14 16:27:31 +00006784static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006785{
ths43f238d2007-01-05 20:55:49 +00006786 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006787#ifdef F_GETOWN_EX
6788 struct f_owner_ex fox;
6789 struct target_f_owner_ex *target_fox;
6790#endif
blueswir1992f48a2007-10-14 16:27:31 +00006791 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006792 int host_cmd = target_to_host_fcntl_cmd(cmd);
6793
6794 if (host_cmd == -TARGET_EINVAL)
6795 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006796
bellard7775e9e2003-05-14 22:46:48 +00006797 switch(cmd) {
6798 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006799 ret = copy_from_user_flock(&fl64, arg);
6800 if (ret) {
6801 return ret;
6802 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006803 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006804 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006805 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006806 }
6807 break;
ths3b46e622007-09-17 08:09:54 +00006808
bellard7775e9e2003-05-14 22:46:48 +00006809 case TARGET_F_SETLK:
6810 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006811 ret = copy_from_user_flock(&fl64, arg);
6812 if (ret) {
6813 return ret;
6814 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006815 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006816 break;
ths3b46e622007-09-17 08:09:54 +00006817
bellard7775e9e2003-05-14 22:46:48 +00006818 case TARGET_F_GETLK64:
Andreas Schwab2d92c682020-05-25 09:59:28 +02006819 case TARGET_F_OFD_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006820 ret = copy_from_user_flock64(&fl64, arg);
6821 if (ret) {
6822 return ret;
6823 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006824 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006825 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006826 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006827 }
bellard9ee1fa22007-11-11 15:11:19 +00006828 break;
bellard7775e9e2003-05-14 22:46:48 +00006829 case TARGET_F_SETLK64:
6830 case TARGET_F_SETLKW64:
Andreas Schwab2d92c682020-05-25 09:59:28 +02006831 case TARGET_F_OFD_SETLK:
6832 case TARGET_F_OFD_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006833 ret = copy_from_user_flock64(&fl64, arg);
6834 if (ret) {
6835 return ret;
6836 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006837 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006838 break;
6839
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006840 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006841 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006842 if (ret >= 0) {
6843 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6844 }
bellardffa65c32004-01-04 23:57:22 +00006845 break;
6846
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006847 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006848 ret = get_errno(safe_fcntl(fd, host_cmd,
6849 target_to_host_bitmask(arg,
6850 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006851 break;
6852
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006853#ifdef F_GETOWN_EX
6854 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006855 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006856 if (ret >= 0) {
6857 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6858 return -TARGET_EFAULT;
6859 target_fox->type = tswap32(fox.type);
6860 target_fox->pid = tswap32(fox.pid);
6861 unlock_user_struct(target_fox, arg, 1);
6862 }
6863 break;
6864#endif
6865
6866#ifdef F_SETOWN_EX
6867 case TARGET_F_SETOWN_EX:
6868 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6869 return -TARGET_EFAULT;
6870 fox.type = tswap32(target_fox->type);
6871 fox.pid = tswap32(target_fox->pid);
6872 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006873 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006874 break;
6875#endif
6876
Timothy Baldwina7b4c9b2020-07-29 21:06:44 +01006877 case TARGET_F_SETSIG:
6878 ret = get_errno(safe_fcntl(fd, host_cmd, target_to_host_signal(arg)));
6879 break;
6880
6881 case TARGET_F_GETSIG:
6882 ret = host_to_target_signal(get_errno(safe_fcntl(fd, host_cmd, arg)));
6883 break;
6884
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006885 case TARGET_F_SETOWN:
6886 case TARGET_F_GETOWN:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006887 case TARGET_F_SETLEASE:
6888 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006889 case TARGET_F_SETPIPE_SZ:
6890 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006891 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006892 break;
6893
bellard7775e9e2003-05-14 22:46:48 +00006894 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006895 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006896 break;
6897 }
6898 return ret;
6899}
6900
bellard67867302003-11-23 17:05:30 +00006901#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006902
bellard67867302003-11-23 17:05:30 +00006903static inline int high2lowuid(int uid)
6904{
6905 if (uid > 65535)
6906 return 65534;
6907 else
6908 return uid;
6909}
6910
6911static inline int high2lowgid(int gid)
6912{
6913 if (gid > 65535)
6914 return 65534;
6915 else
6916 return gid;
6917}
6918
6919static inline int low2highuid(int uid)
6920{
6921 if ((int16_t)uid == -1)
6922 return -1;
6923 else
6924 return uid;
6925}
6926
6927static inline int low2highgid(int gid)
6928{
6929 if ((int16_t)gid == -1)
6930 return -1;
6931 else
6932 return gid;
6933}
Riku Voipio0c866a72011-04-18 15:23:06 +03006934static inline int tswapid(int id)
6935{
6936 return tswap16(id);
6937}
Peter Maydell76ca3102014-03-02 19:36:41 +00006938
6939#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6940
Riku Voipio0c866a72011-04-18 15:23:06 +03006941#else /* !USE_UID16 */
6942static inline int high2lowuid(int uid)
6943{
6944 return uid;
6945}
6946static inline int high2lowgid(int gid)
6947{
6948 return gid;
6949}
6950static inline int low2highuid(int uid)
6951{
6952 return uid;
6953}
6954static inline int low2highgid(int gid)
6955{
6956 return gid;
6957}
6958static inline int tswapid(int id)
6959{
6960 return tswap32(id);
6961}
Peter Maydell76ca3102014-03-02 19:36:41 +00006962
6963#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6964
bellard67867302003-11-23 17:05:30 +00006965#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006966
Peter Maydellfd6f7792016-03-01 16:33:02 +00006967/* We must do direct syscalls for setting UID/GID, because we want to
6968 * implement the Linux system call semantics of "change only for this thread",
6969 * not the libc/POSIX semantics of "change for all threads in process".
6970 * (See http://ewontfix.com/17/ for more details.)
6971 * We use the 32-bit version of the syscalls if present; if it is not
6972 * then either the host architecture supports 32-bit UIDs natively with
6973 * the standard syscall, or the 16-bit UID is the best we can do.
6974 */
6975#ifdef __NR_setuid32
6976#define __NR_sys_setuid __NR_setuid32
6977#else
6978#define __NR_sys_setuid __NR_setuid
6979#endif
6980#ifdef __NR_setgid32
6981#define __NR_sys_setgid __NR_setgid32
6982#else
6983#define __NR_sys_setgid __NR_setgid
6984#endif
6985#ifdef __NR_setresuid32
6986#define __NR_sys_setresuid __NR_setresuid32
6987#else
6988#define __NR_sys_setresuid __NR_setresuid
6989#endif
6990#ifdef __NR_setresgid32
6991#define __NR_sys_setresgid __NR_setresgid32
6992#else
6993#define __NR_sys_setresgid __NR_setresgid
6994#endif
6995
6996_syscall1(int, sys_setuid, uid_t, uid)
6997_syscall1(int, sys_setgid, gid_t, gid)
6998_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6999_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
7000
bellard31e31b82003-02-18 22:55:36 +00007001void syscall_init(void)
7002{
bellard2ab83ea2003-06-15 19:56:46 +00007003 IOCTLEntry *ie;
7004 const argtype *arg_type;
7005 int size;
thsb92c47c2007-11-01 00:07:38 +00007006 int i;
bellard2ab83ea2003-06-15 19:56:46 +00007007
Alexander Graf8be656b2015-05-06 23:47:32 +02007008 thunk_init(STRUCT_MAX);
7009
Blue Swirl001faf32009-05-13 17:53:17 +00007010#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00007011#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00007012#include "syscall_types.h"
7013#undef STRUCT
7014#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00007015
Peter Maydelldd6e9572012-07-23 08:07:22 +00007016 /* Build target_to_host_errno_table[] table from
7017 * host_to_target_errno_table[]. */
7018 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
7019 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
7020 }
7021
bellard2ab83ea2003-06-15 19:56:46 +00007022 /* we patch the ioctl size if necessary. We rely on the fact that
7023 no ioctl has all the bits at '1' in the size field */
7024 ie = ioctl_entries;
7025 while (ie->target_cmd != 0) {
7026 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
7027 TARGET_IOC_SIZEMASK) {
7028 arg_type = ie->arg_type;
7029 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00007030 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00007031 ie->target_cmd);
7032 exit(1);
7033 }
7034 arg_type++;
7035 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00007036 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00007037 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
7038 (size << TARGET_IOC_SIZESHIFT);
7039 }
thsb92c47c2007-11-01 00:07:38 +00007040
bellard2ab83ea2003-06-15 19:56:46 +00007041 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00007042#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7043 (defined(__x86_64__) && defined(TARGET_X86_64))
7044 if (unlikely(ie->target_cmd != ie->host_cmd)) {
7045 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
7046 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00007047 }
7048#endif
7049 ie++;
7050 }
bellard31e31b82003-02-18 22:55:36 +00007051}
bellardc573ff62004-01-04 15:51:36 +00007052
pbrookce4defa2006-02-09 16:49:55 +00007053#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00007054static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
7055 abi_long arg2,
7056 abi_long arg3,
7057 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007058{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007059 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007060 arg2 = arg3;
7061 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007062 }
pbrookce4defa2006-02-09 16:49:55 +00007063 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
7064}
7065#endif
7066
7067#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00007068static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
7069 abi_long arg2,
7070 abi_long arg3,
7071 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007072{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007073 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007074 arg2 = arg3;
7075 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007076 }
pbrookce4defa2006-02-09 16:49:55 +00007077 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
7078}
7079#endif
7080
Alistair Francis859e8a82020-03-12 15:13:49 -07007081#if defined(TARGET_NR_timer_settime) || \
7082 (defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD))
Filip Bozuta2c86c902020-07-22 17:34:20 +02007083static inline abi_long target_to_host_itimerspec(struct itimerspec *host_its,
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007084 abi_ulong target_addr)
7085{
Filip Bozuta2c86c902020-07-22 17:34:20 +02007086 if (target_to_host_timespec(&host_its->it_interval, target_addr +
7087 offsetof(struct target_itimerspec,
7088 it_interval)) ||
7089 target_to_host_timespec(&host_its->it_value, target_addr +
7090 offsetof(struct target_itimerspec,
7091 it_value))) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007092 return -TARGET_EFAULT;
7093 }
7094
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007095 return 0;
7096}
Alistair Francis859e8a82020-03-12 15:13:49 -07007097#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007098
Filip Bozuta828cb3a2020-07-22 17:34:21 +02007099#if defined(TARGET_NR_timer_settime64) || \
7100 (defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD))
7101static inline abi_long target_to_host_itimerspec64(struct itimerspec *host_its,
7102 abi_ulong target_addr)
7103{
7104 if (target_to_host_timespec64(&host_its->it_interval, target_addr +
7105 offsetof(struct target__kernel_itimerspec,
7106 it_interval)) ||
7107 target_to_host_timespec64(&host_its->it_value, target_addr +
7108 offsetof(struct target__kernel_itimerspec,
7109 it_value))) {
7110 return -TARGET_EFAULT;
7111 }
7112
7113 return 0;
7114}
7115#endif
7116
Alistair Francis859e8a82020-03-12 15:13:49 -07007117#if ((defined(TARGET_NR_timerfd_gettime) || \
7118 defined(TARGET_NR_timerfd_settime)) && defined(CONFIG_TIMERFD)) || \
Filip Bozuta2c86c902020-07-22 17:34:20 +02007119 defined(TARGET_NR_timer_gettime) || defined(TARGET_NR_timer_settime)
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007120static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
Filip Bozuta2c86c902020-07-22 17:34:20 +02007121 struct itimerspec *host_its)
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007122{
Filip Bozuta2c86c902020-07-22 17:34:20 +02007123 if (host_to_target_timespec(target_addr + offsetof(struct target_itimerspec,
7124 it_interval),
7125 &host_its->it_interval) ||
7126 host_to_target_timespec(target_addr + offsetof(struct target_itimerspec,
7127 it_value),
7128 &host_its->it_value)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007129 return -TARGET_EFAULT;
7130 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007131 return 0;
7132}
Alistair Francis859e8a82020-03-12 15:13:49 -07007133#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007134
Filip Bozuta828cb3a2020-07-22 17:34:21 +02007135#if ((defined(TARGET_NR_timerfd_gettime64) || \
7136 defined(TARGET_NR_timerfd_settime64)) && defined(CONFIG_TIMERFD)) || \
7137 defined(TARGET_NR_timer_gettime64) || defined(TARGET_NR_timer_settime64)
7138static inline abi_long host_to_target_itimerspec64(abi_ulong target_addr,
7139 struct itimerspec *host_its)
7140{
7141 if (host_to_target_timespec64(target_addr +
7142 offsetof(struct target__kernel_itimerspec,
7143 it_interval),
7144 &host_its->it_interval) ||
7145 host_to_target_timespec64(target_addr +
7146 offsetof(struct target__kernel_itimerspec,
7147 it_value),
7148 &host_its->it_value)) {
7149 return -TARGET_EFAULT;
7150 }
7151 return 0;
7152}
7153#endif
7154
Alistair Francis859e8a82020-03-12 15:13:49 -07007155#if defined(TARGET_NR_adjtimex) || \
7156 (defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME))
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007157static inline abi_long target_to_host_timex(struct timex *host_tx,
7158 abi_long target_addr)
7159{
7160 struct target_timex *target_tx;
7161
7162 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7163 return -TARGET_EFAULT;
7164 }
7165
7166 __get_user(host_tx->modes, &target_tx->modes);
7167 __get_user(host_tx->offset, &target_tx->offset);
7168 __get_user(host_tx->freq, &target_tx->freq);
7169 __get_user(host_tx->maxerror, &target_tx->maxerror);
7170 __get_user(host_tx->esterror, &target_tx->esterror);
7171 __get_user(host_tx->status, &target_tx->status);
7172 __get_user(host_tx->constant, &target_tx->constant);
7173 __get_user(host_tx->precision, &target_tx->precision);
7174 __get_user(host_tx->tolerance, &target_tx->tolerance);
7175 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7176 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7177 __get_user(host_tx->tick, &target_tx->tick);
7178 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7179 __get_user(host_tx->jitter, &target_tx->jitter);
7180 __get_user(host_tx->shift, &target_tx->shift);
7181 __get_user(host_tx->stabil, &target_tx->stabil);
7182 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7183 __get_user(host_tx->calcnt, &target_tx->calcnt);
7184 __get_user(host_tx->errcnt, &target_tx->errcnt);
7185 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7186 __get_user(host_tx->tai, &target_tx->tai);
7187
7188 unlock_user_struct(target_tx, target_addr, 0);
7189 return 0;
7190}
7191
7192static inline abi_long host_to_target_timex(abi_long target_addr,
7193 struct timex *host_tx)
7194{
7195 struct target_timex *target_tx;
7196
7197 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7198 return -TARGET_EFAULT;
7199 }
7200
7201 __put_user(host_tx->modes, &target_tx->modes);
7202 __put_user(host_tx->offset, &target_tx->offset);
7203 __put_user(host_tx->freq, &target_tx->freq);
7204 __put_user(host_tx->maxerror, &target_tx->maxerror);
7205 __put_user(host_tx->esterror, &target_tx->esterror);
7206 __put_user(host_tx->status, &target_tx->status);
7207 __put_user(host_tx->constant, &target_tx->constant);
7208 __put_user(host_tx->precision, &target_tx->precision);
7209 __put_user(host_tx->tolerance, &target_tx->tolerance);
7210 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7211 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7212 __put_user(host_tx->tick, &target_tx->tick);
7213 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7214 __put_user(host_tx->jitter, &target_tx->jitter);
7215 __put_user(host_tx->shift, &target_tx->shift);
7216 __put_user(host_tx->stabil, &target_tx->stabil);
7217 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7218 __put_user(host_tx->calcnt, &target_tx->calcnt);
7219 __put_user(host_tx->errcnt, &target_tx->errcnt);
7220 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7221 __put_user(host_tx->tai, &target_tx->tai);
7222
7223 unlock_user_struct(target_tx, target_addr, 1);
7224 return 0;
7225}
Alistair Francis859e8a82020-03-12 15:13:49 -07007226#endif
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007227
Filip Bozuta6ac03b22020-08-24 21:21:15 +02007228
7229#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
7230static inline abi_long target_to_host_timex64(struct timex *host_tx,
7231 abi_long target_addr)
7232{
7233 struct target__kernel_timex *target_tx;
7234
7235 if (copy_from_user_timeval64(&host_tx->time, target_addr +
7236 offsetof(struct target__kernel_timex,
7237 time))) {
7238 return -TARGET_EFAULT;
7239 }
7240
7241 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7242 return -TARGET_EFAULT;
7243 }
7244
7245 __get_user(host_tx->modes, &target_tx->modes);
7246 __get_user(host_tx->offset, &target_tx->offset);
7247 __get_user(host_tx->freq, &target_tx->freq);
7248 __get_user(host_tx->maxerror, &target_tx->maxerror);
7249 __get_user(host_tx->esterror, &target_tx->esterror);
7250 __get_user(host_tx->status, &target_tx->status);
7251 __get_user(host_tx->constant, &target_tx->constant);
7252 __get_user(host_tx->precision, &target_tx->precision);
7253 __get_user(host_tx->tolerance, &target_tx->tolerance);
7254 __get_user(host_tx->tick, &target_tx->tick);
7255 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7256 __get_user(host_tx->jitter, &target_tx->jitter);
7257 __get_user(host_tx->shift, &target_tx->shift);
7258 __get_user(host_tx->stabil, &target_tx->stabil);
7259 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7260 __get_user(host_tx->calcnt, &target_tx->calcnt);
7261 __get_user(host_tx->errcnt, &target_tx->errcnt);
7262 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7263 __get_user(host_tx->tai, &target_tx->tai);
7264
7265 unlock_user_struct(target_tx, target_addr, 0);
7266 return 0;
7267}
7268
7269static inline abi_long host_to_target_timex64(abi_long target_addr,
7270 struct timex *host_tx)
7271{
7272 struct target__kernel_timex *target_tx;
7273
7274 if (copy_to_user_timeval64(target_addr +
7275 offsetof(struct target__kernel_timex, time),
7276 &host_tx->time)) {
7277 return -TARGET_EFAULT;
7278 }
7279
7280 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7281 return -TARGET_EFAULT;
7282 }
7283
7284 __put_user(host_tx->modes, &target_tx->modes);
7285 __put_user(host_tx->offset, &target_tx->offset);
7286 __put_user(host_tx->freq, &target_tx->freq);
7287 __put_user(host_tx->maxerror, &target_tx->maxerror);
7288 __put_user(host_tx->esterror, &target_tx->esterror);
7289 __put_user(host_tx->status, &target_tx->status);
7290 __put_user(host_tx->constant, &target_tx->constant);
7291 __put_user(host_tx->precision, &target_tx->precision);
7292 __put_user(host_tx->tolerance, &target_tx->tolerance);
7293 __put_user(host_tx->tick, &target_tx->tick);
7294 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7295 __put_user(host_tx->jitter, &target_tx->jitter);
7296 __put_user(host_tx->shift, &target_tx->shift);
7297 __put_user(host_tx->stabil, &target_tx->stabil);
7298 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7299 __put_user(host_tx->calcnt, &target_tx->calcnt);
7300 __put_user(host_tx->errcnt, &target_tx->errcnt);
7301 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7302 __put_user(host_tx->tai, &target_tx->tai);
7303
7304 unlock_user_struct(target_tx, target_addr, 1);
7305 return 0;
7306}
7307#endif
7308
Peter Maydellc0659762014-08-09 15:42:32 +01007309static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7310 abi_ulong target_addr)
7311{
7312 struct target_sigevent *target_sevp;
7313
7314 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7315 return -TARGET_EFAULT;
7316 }
7317
7318 /* This union is awkward on 64 bit systems because it has a 32 bit
7319 * integer and a pointer in it; we follow the conversion approach
7320 * used for handling sigval types in signal.c so the guest should get
7321 * the correct value back even if we did a 64 bit byteswap and it's
7322 * using the 32 bit integer.
7323 */
7324 host_sevp->sigev_value.sival_ptr =
7325 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7326 host_sevp->sigev_signo =
7327 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7328 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7329 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7330
7331 unlock_user_struct(target_sevp, target_addr, 1);
7332 return 0;
7333}
7334
Tom Musta6f6a4032014-08-12 13:53:42 -05007335#if defined(TARGET_NR_mlockall)
7336static inline int target_to_host_mlockall_arg(int arg)
7337{
7338 int result = 0;
7339
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007340 if (arg & TARGET_MCL_CURRENT) {
Tom Musta6f6a4032014-08-12 13:53:42 -05007341 result |= MCL_CURRENT;
7342 }
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007343 if (arg & TARGET_MCL_FUTURE) {
Tom Musta6f6a4032014-08-12 13:53:42 -05007344 result |= MCL_FUTURE;
7345 }
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007346#ifdef MCL_ONFAULT
7347 if (arg & TARGET_MCL_ONFAULT) {
7348 result |= MCL_ONFAULT;
7349 }
7350#endif
7351
Tom Musta6f6a4032014-08-12 13:53:42 -05007352 return result;
7353}
7354#endif
7355
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007356#if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \
7357 defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \
7358 defined(TARGET_NR_newfstatat))
balrog6a24a772008-09-20 02:23:36 +00007359static inline abi_long host_to_target_stat64(void *cpu_env,
7360 abi_ulong target_addr,
7361 struct stat *host_st)
7362{
Alexander Graf09701192013-09-03 20:12:15 +01007363#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007364 if (((CPUARMState *)cpu_env)->eabi) {
7365 struct target_eabi_stat64 *target_st;
7366
7367 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7368 return -TARGET_EFAULT;
7369 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7370 __put_user(host_st->st_dev, &target_st->st_dev);
7371 __put_user(host_st->st_ino, &target_st->st_ino);
7372#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7373 __put_user(host_st->st_ino, &target_st->__st_ino);
7374#endif
7375 __put_user(host_st->st_mode, &target_st->st_mode);
7376 __put_user(host_st->st_nlink, &target_st->st_nlink);
7377 __put_user(host_st->st_uid, &target_st->st_uid);
7378 __put_user(host_st->st_gid, &target_st->st_gid);
7379 __put_user(host_st->st_rdev, &target_st->st_rdev);
7380 __put_user(host_st->st_size, &target_st->st_size);
7381 __put_user(host_st->st_blksize, &target_st->st_blksize);
7382 __put_user(host_st->st_blocks, &target_st->st_blocks);
7383 __put_user(host_st->st_atime, &target_st->target_st_atime);
7384 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7385 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08007386#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
7387 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
7388 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
7389 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
7390#endif
balrog6a24a772008-09-20 02:23:36 +00007391 unlock_user_struct(target_st, target_addr, 1);
7392 } else
7393#endif
7394 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007395#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007396 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007397#else
7398 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007399#endif
balrog6a24a772008-09-20 02:23:36 +00007400
7401 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7402 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007403 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007404 __put_user(host_st->st_dev, &target_st->st_dev);
7405 __put_user(host_st->st_ino, &target_st->st_ino);
7406#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7407 __put_user(host_st->st_ino, &target_st->__st_ino);
7408#endif
7409 __put_user(host_st->st_mode, &target_st->st_mode);
7410 __put_user(host_st->st_nlink, &target_st->st_nlink);
7411 __put_user(host_st->st_uid, &target_st->st_uid);
7412 __put_user(host_st->st_gid, &target_st->st_gid);
7413 __put_user(host_st->st_rdev, &target_st->st_rdev);
7414 /* XXX: better use of kernel struct */
7415 __put_user(host_st->st_size, &target_st->st_size);
7416 __put_user(host_st->st_blksize, &target_st->st_blksize);
7417 __put_user(host_st->st_blocks, &target_st->st_blocks);
7418 __put_user(host_st->st_atime, &target_st->target_st_atime);
7419 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7420 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08007421#if _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
7422 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
7423 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
7424 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
7425#endif
balrog6a24a772008-09-20 02:23:36 +00007426 unlock_user_struct(target_st, target_addr, 1);
7427 }
7428
7429 return 0;
7430}
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007431#endif
balrog6a24a772008-09-20 02:23:36 +00007432
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007433#if defined(TARGET_NR_statx) && defined(__NR_statx)
7434static inline abi_long host_to_target_statx(struct target_statx *host_stx,
7435 abi_ulong target_addr)
7436{
7437 struct target_statx *target_stx;
7438
7439 if (!lock_user_struct(VERIFY_WRITE, target_stx, target_addr, 0)) {
7440 return -TARGET_EFAULT;
7441 }
7442 memset(target_stx, 0, sizeof(*target_stx));
7443
7444 __put_user(host_stx->stx_mask, &target_stx->stx_mask);
7445 __put_user(host_stx->stx_blksize, &target_stx->stx_blksize);
7446 __put_user(host_stx->stx_attributes, &target_stx->stx_attributes);
7447 __put_user(host_stx->stx_nlink, &target_stx->stx_nlink);
7448 __put_user(host_stx->stx_uid, &target_stx->stx_uid);
7449 __put_user(host_stx->stx_gid, &target_stx->stx_gid);
7450 __put_user(host_stx->stx_mode, &target_stx->stx_mode);
7451 __put_user(host_stx->stx_ino, &target_stx->stx_ino);
7452 __put_user(host_stx->stx_size, &target_stx->stx_size);
7453 __put_user(host_stx->stx_blocks, &target_stx->stx_blocks);
7454 __put_user(host_stx->stx_attributes_mask, &target_stx->stx_attributes_mask);
7455 __put_user(host_stx->stx_atime.tv_sec, &target_stx->stx_atime.tv_sec);
7456 __put_user(host_stx->stx_atime.tv_nsec, &target_stx->stx_atime.tv_nsec);
Ariadne Conilld1e26702019-11-22 11:40:40 -06007457 __put_user(host_stx->stx_btime.tv_sec, &target_stx->stx_btime.tv_sec);
7458 __put_user(host_stx->stx_btime.tv_nsec, &target_stx->stx_btime.tv_nsec);
7459 __put_user(host_stx->stx_ctime.tv_sec, &target_stx->stx_ctime.tv_sec);
7460 __put_user(host_stx->stx_ctime.tv_nsec, &target_stx->stx_ctime.tv_nsec);
7461 __put_user(host_stx->stx_mtime.tv_sec, &target_stx->stx_mtime.tv_sec);
7462 __put_user(host_stx->stx_mtime.tv_nsec, &target_stx->stx_mtime.tv_nsec);
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007463 __put_user(host_stx->stx_rdev_major, &target_stx->stx_rdev_major);
7464 __put_user(host_stx->stx_rdev_minor, &target_stx->stx_rdev_minor);
7465 __put_user(host_stx->stx_dev_major, &target_stx->stx_dev_major);
7466 __put_user(host_stx->stx_dev_minor, &target_stx->stx_dev_minor);
7467
7468 unlock_user_struct(target_stx, target_addr, 1);
7469
7470 return 0;
7471}
7472#endif
7473
Alistair Francis14690292020-03-18 15:47:01 -07007474static int do_sys_futex(int *uaddr, int op, int val,
7475 const struct timespec *timeout, int *uaddr2,
7476 int val3)
7477{
7478#if HOST_LONG_BITS == 64
7479#if defined(__NR_futex)
7480 /* always a 64-bit time_t, it doesn't define _time64 version */
7481 return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
7482
7483#endif
7484#else /* HOST_LONG_BITS == 64 */
7485#if defined(__NR_futex_time64)
7486 if (sizeof(timeout->tv_sec) == 8) {
7487 /* _time64 function on 32bit arch */
7488 return sys_futex_time64(uaddr, op, val, timeout, uaddr2, val3);
7489 }
7490#endif
7491#if defined(__NR_futex)
7492 /* old function on 32bit arch */
7493 return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
7494#endif
7495#endif /* HOST_LONG_BITS == 64 */
7496 g_assert_not_reached();
7497}
7498
7499static int do_safe_futex(int *uaddr, int op, int val,
7500 const struct timespec *timeout, int *uaddr2,
7501 int val3)
7502{
7503#if HOST_LONG_BITS == 64
7504#if defined(__NR_futex)
7505 /* always a 64-bit time_t, it doesn't define _time64 version */
7506 return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
7507#endif
7508#else /* HOST_LONG_BITS == 64 */
7509#if defined(__NR_futex_time64)
7510 if (sizeof(timeout->tv_sec) == 8) {
7511 /* _time64 function on 32bit arch */
7512 return get_errno(safe_futex_time64(uaddr, op, val, timeout, uaddr2,
7513 val3));
7514 }
7515#endif
7516#if defined(__NR_futex)
7517 /* old function on 32bit arch */
7518 return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
7519#endif
7520#endif /* HOST_LONG_BITS == 64 */
7521 return -TARGET_ENOSYS;
7522}
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007523
pbrookbd0c5662008-05-29 14:34:11 +00007524/* ??? Using host futex calls even when target atomic operations
7525 are not really atomic probably breaks things. However implementing
7526 futexes locally would make futexes shared between multiple processes
7527 tricky. However they're probably useless because guest atomic
7528 operations won't work either. */
Alistair Francis859e8a82020-03-12 15:13:49 -07007529#if defined(TARGET_NR_futex)
blueswir18fcd3692008-08-17 20:26:25 +00007530static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7531 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007532{
7533 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007534 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007535
7536 /* ??? We assume FUTEX_* constants are the same on both host
7537 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007538#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007539 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007540#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007541 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007542#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007543 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007544 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007545 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007546 if (timeout) {
7547 pts = &ts;
7548 target_to_host_timespec(pts, timeout);
7549 } else {
7550 pts = NULL;
7551 }
Alistair Francis14690292020-03-18 15:47:01 -07007552 return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
pbrookbd0c5662008-05-29 14:34:11 +00007553 case FUTEX_WAKE:
Alistair Francis14690292020-03-18 15:47:01 -07007554 return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
pbrookbd0c5662008-05-29 14:34:11 +00007555 case FUTEX_FD:
Alistair Francis14690292020-03-18 15:47:01 -07007556 return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
pbrookbd0c5662008-05-29 14:34:11 +00007557 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007558 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007559 case FUTEX_WAKE_OP:
7560 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7561 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7562 But the prototype takes a `struct timespec *'; insert casts
7563 to satisfy the compiler. We do not need to tswap TIMEOUT
7564 since it's not compared to guest memory. */
7565 pts = (struct timespec *)(uintptr_t) timeout;
Alistair Francis14690292020-03-18 15:47:01 -07007566 return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
7567 (base_op == FUTEX_CMP_REQUEUE
7568 ? tswap32(val3)
7569 : val3));
pbrookbd0c5662008-05-29 14:34:11 +00007570 default:
7571 return -TARGET_ENOSYS;
7572 }
7573}
Alistair Francis859e8a82020-03-12 15:13:49 -07007574#endif
Alistair Francis14690292020-03-18 15:47:01 -07007575
7576#if defined(TARGET_NR_futex_time64)
7577static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong timeout,
7578 target_ulong uaddr2, int val3)
7579{
7580 struct timespec ts, *pts;
7581 int base_op;
7582
7583 /* ??? We assume FUTEX_* constants are the same on both host
7584 and target. */
7585#ifdef FUTEX_CMD_MASK
7586 base_op = op & FUTEX_CMD_MASK;
7587#else
7588 base_op = op;
7589#endif
7590 switch (base_op) {
7591 case FUTEX_WAIT:
7592 case FUTEX_WAIT_BITSET:
7593 if (timeout) {
7594 pts = &ts;
7595 target_to_host_timespec64(pts, timeout);
7596 } else {
7597 pts = NULL;
7598 }
7599 return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
7600 case FUTEX_WAKE:
7601 return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
7602 case FUTEX_FD:
7603 return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
7604 case FUTEX_REQUEUE:
7605 case FUTEX_CMP_REQUEUE:
7606 case FUTEX_WAKE_OP:
7607 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7608 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7609 But the prototype takes a `struct timespec *'; insert casts
7610 to satisfy the compiler. We do not need to tswap TIMEOUT
7611 since it's not compared to guest memory. */
7612 pts = (struct timespec *)(uintptr_t) timeout;
7613 return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
7614 (base_op == FUTEX_CMP_REQUEUE
7615 ? tswap32(val3)
7616 : val3));
7617 default:
7618 return -TARGET_ENOSYS;
7619 }
7620}
7621#endif
7622
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007623#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7624static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7625 abi_long handle, abi_long mount_id,
7626 abi_long flags)
7627{
7628 struct file_handle *target_fh;
7629 struct file_handle *fh;
7630 int mid = 0;
7631 abi_long ret;
7632 char *name;
7633 unsigned int size, total_size;
7634
7635 if (get_user_s32(size, handle)) {
7636 return -TARGET_EFAULT;
7637 }
7638
7639 name = lock_user_string(pathname);
7640 if (!name) {
7641 return -TARGET_EFAULT;
7642 }
7643
7644 total_size = sizeof(struct file_handle) + size;
7645 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7646 if (!target_fh) {
7647 unlock_user(name, pathname, 0);
7648 return -TARGET_EFAULT;
7649 }
7650
7651 fh = g_malloc0(total_size);
7652 fh->handle_bytes = size;
7653
7654 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7655 unlock_user(name, pathname, 0);
7656
7657 /* man name_to_handle_at(2):
7658 * Other than the use of the handle_bytes field, the caller should treat
7659 * the file_handle structure as an opaque data type
7660 */
7661
7662 memcpy(target_fh, fh, total_size);
7663 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7664 target_fh->handle_type = tswap32(fh->handle_type);
7665 g_free(fh);
7666 unlock_user(target_fh, handle, total_size);
7667
7668 if (put_user_s32(mid, mount_id)) {
7669 return -TARGET_EFAULT;
7670 }
7671
7672 return ret;
7673
7674}
7675#endif
7676
7677#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7678static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7679 abi_long flags)
7680{
7681 struct file_handle *target_fh;
7682 struct file_handle *fh;
7683 unsigned int size, total_size;
7684 abi_long ret;
7685
7686 if (get_user_s32(size, handle)) {
7687 return -TARGET_EFAULT;
7688 }
7689
7690 total_size = sizeof(struct file_handle) + size;
7691 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7692 if (!target_fh) {
7693 return -TARGET_EFAULT;
7694 }
7695
Thomas Huthe9d49d52015-10-09 17:56:38 +02007696 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007697 fh->handle_bytes = size;
7698 fh->handle_type = tswap32(target_fh->handle_type);
7699
7700 ret = get_errno(open_by_handle_at(mount_fd, fh,
7701 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7702
7703 g_free(fh);
7704
7705 unlock_user(target_fh, handle, total_size);
7706
7707 return ret;
7708}
7709#endif
pbrookbd0c5662008-05-29 14:34:11 +00007710
Laurent Viviere36800c2015-10-02 14:48:09 +02007711#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7712
Laurent Viviere36800c2015-10-02 14:48:09 +02007713static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7714{
7715 int host_flags;
7716 target_sigset_t *target_mask;
7717 sigset_t host_mask;
7718 abi_long ret;
7719
7720 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7721 return -TARGET_EINVAL;
7722 }
7723 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7724 return -TARGET_EFAULT;
7725 }
7726
7727 target_to_host_sigset(&host_mask, target_mask);
7728
7729 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7730
7731 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7732 if (ret >= 0) {
7733 fd_trans_register(ret, &target_signalfd_trans);
7734 }
7735
7736 unlock_user_struct(target_mask, mask, 0);
7737
7738 return ret;
7739}
7740#endif
7741
pbrook1d9d8b52009-04-16 15:17:02 +00007742/* Map host to target signal numbers for the wait family of syscalls.
7743 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007744int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007745{
7746 if (WIFSIGNALED(status)) {
7747 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7748 }
7749 if (WIFSTOPPED(status)) {
7750 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7751 | (status & 0xff);
7752 }
7753 return status;
7754}
7755
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007756static int open_self_cmdline(void *cpu_env, int fd)
7757{
Richard Henderson29a0af62019-03-22 16:07:18 -07007758 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Schwab58de8b92017-03-20 12:31:55 +01007759 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7760 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007761
Andreas Schwab58de8b92017-03-20 12:31:55 +01007762 for (i = 0; i < bprm->argc; i++) {
7763 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007764
Andreas Schwab58de8b92017-03-20 12:31:55 +01007765 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007766 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007767 }
7768 }
7769
Andreas Schwab58de8b92017-03-20 12:31:55 +01007770 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007771}
7772
Alexander Graf36c08d42011-11-02 20:23:24 +01007773static int open_self_maps(void *cpu_env, int fd)
7774{
Richard Henderson29a0af62019-03-22 16:07:18 -07007775 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02007776 TaskState *ts = cpu->opaque;
Alex Bennée01ef6b92020-04-03 20:11:46 +01007777 GSList *map_info = read_self_maps();
7778 GSList *s;
Alex Bennéebb551732020-04-03 20:11:47 +01007779 int count;
Alexander Graf36c08d42011-11-02 20:23:24 +01007780
Alex Bennée01ef6b92020-04-03 20:11:46 +01007781 for (s = map_info; s; s = g_slist_next(s)) {
7782 MapInfo *e = (MapInfo *) s->data;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007783
Alex Bennée01ef6b92020-04-03 20:11:46 +01007784 if (h2g_valid(e->start)) {
7785 unsigned long min = e->start;
7786 unsigned long max = e->end;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007787 int flags = page_get_flags(h2g(min));
Alex Bennée01ef6b92020-04-03 20:11:46 +01007788 const char *path;
7789
7790 max = h2g_valid(max - 1) ?
7791 max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1;
7792
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007793 if (page_check_range(h2g(min), max - min, flags) == -1) {
7794 continue;
7795 }
Alex Bennée01ef6b92020-04-03 20:11:46 +01007796
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007797 if (h2g(min) == ts->info->stack_limit) {
Alex Bennéebb551732020-04-03 20:11:47 +01007798 path = "[stack]";
Alex Bennée01ef6b92020-04-03 20:11:46 +01007799 } else {
7800 path = e->path;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007801 }
Alex Bennée01ef6b92020-04-03 20:11:46 +01007802
Alex Bennéebb551732020-04-03 20:11:47 +01007803 count = dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
7804 " %c%c%c%c %08" PRIx64 " %s %"PRId64,
7805 h2g(min), h2g(max - 1) + 1,
7806 e->is_read ? 'r' : '-',
7807 e->is_write ? 'w' : '-',
7808 e->is_exec ? 'x' : '-',
7809 e->is_priv ? 'p' : '-',
7810 (uint64_t) e->offset, e->dev, e->inode);
7811 if (path) {
7812 dprintf(fd, "%*s%s\n", 73 - count, "", path);
7813 } else {
7814 dprintf(fd, "\n");
7815 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007816 }
7817 }
7818
Alex Bennée01ef6b92020-04-03 20:11:46 +01007819 free_self_maps(map_info);
7820
Richard Hendersonbf02adc2020-02-12 19:22:22 -08007821#ifdef TARGET_VSYSCALL_PAGE
7822 /*
7823 * We only support execution from the vsyscall page.
7824 * This is as if CONFIG_LEGACY_VSYSCALL_XONLY=y from v5.3.
7825 */
Alex Bennéebb551732020-04-03 20:11:47 +01007826 count = dprintf(fd, TARGET_FMT_lx "-" TARGET_FMT_lx
7827 " --xp 00000000 00:00 0",
7828 TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE);
7829 dprintf(fd, "%*s%s\n", 73 - count, "", "[vsyscall]");
Richard Hendersonbf02adc2020-02-12 19:22:22 -08007830#endif
7831
Alexander Graf36c08d42011-11-02 20:23:24 +01007832 return 0;
7833}
7834
Alexander Graf480b8e72011-11-02 20:23:25 +01007835static int open_self_stat(void *cpu_env, int fd)
7836{
Richard Henderson29a0af62019-03-22 16:07:18 -07007837 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02007838 TaskState *ts = cpu->opaque;
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01007839 g_autoptr(GString) buf = g_string_new(NULL);
Alexander Graf480b8e72011-11-02 20:23:25 +01007840 int i;
7841
7842 for (i = 0; i < 44; i++) {
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01007843 if (i == 0) {
7844 /* pid */
7845 g_string_printf(buf, FMT_pid " ", getpid());
7846 } else if (i == 1) {
7847 /* app name */
7848 gchar *bin = g_strrstr(ts->bprm->argv[0], "/");
7849 bin = bin ? bin + 1 : ts->bprm->argv[0];
7850 g_string_printf(buf, "(%.15s) ", bin);
7851 } else if (i == 27) {
7852 /* stack bottom */
7853 g_string_printf(buf, TARGET_ABI_FMT_ld " ", ts->info->start_stack);
7854 } else {
7855 /* for the rest, there is MasterCard */
7856 g_string_printf(buf, "0%c", i == 43 ? '\n' : ' ');
7857 }
Alexander Graf480b8e72011-11-02 20:23:25 +01007858
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01007859 if (write(fd, buf->str, buf->len) != buf->len) {
7860 return -1;
7861 }
Alexander Graf480b8e72011-11-02 20:23:25 +01007862 }
7863
7864 return 0;
7865}
7866
Alexander Graf257450e2011-11-02 20:23:26 +01007867static int open_self_auxv(void *cpu_env, int fd)
7868{
Richard Henderson29a0af62019-03-22 16:07:18 -07007869 CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
Andreas Färber0429a972013-08-26 18:14:44 +02007870 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007871 abi_ulong auxv = ts->info->saved_auxv;
7872 abi_ulong len = ts->info->auxv_len;
7873 char *ptr;
7874
7875 /*
7876 * Auxiliary vector is stored in target process stack.
7877 * read in whole auxv vector and copy it to file
7878 */
7879 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7880 if (ptr != NULL) {
7881 while (len > 0) {
7882 ssize_t r;
7883 r = write(fd, ptr, len);
7884 if (r <= 0) {
7885 break;
7886 }
7887 len -= r;
7888 ptr += r;
7889 }
7890 lseek(fd, 0, SEEK_SET);
7891 unlock_user(ptr, auxv, len);
7892 }
7893
7894 return 0;
7895}
7896
Andreas Schwab463d8e72013-07-02 14:04:12 +01007897static int is_proc_myself(const char *filename, const char *entry)
7898{
7899 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7900 filename += strlen("/proc/");
7901 if (!strncmp(filename, "self/", strlen("self/"))) {
7902 filename += strlen("self/");
7903 } else if (*filename >= '1' && *filename <= '9') {
7904 char myself[80];
7905 snprintf(myself, sizeof(myself), "%d/", getpid());
7906 if (!strncmp(filename, myself, strlen(myself))) {
7907 filename += strlen(myself);
7908 } else {
7909 return 0;
7910 }
7911 } else {
7912 return 0;
7913 }
7914 if (!strcmp(filename, entry)) {
7915 return 1;
7916 }
7917 }
7918 return 0;
7919}
7920
Laurent Vivierfff69382019-05-17 15:31:48 +02007921#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \
Helge Deller93a56612020-04-24 23:06:48 +02007922 defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA)
Laurent Vivierde6b9932013-08-30 01:46:40 +02007923static int is_proc(const char *filename, const char *entry)
7924{
7925 return strcmp(filename, entry) == 0;
7926}
Laurent Vivierfff69382019-05-17 15:31:48 +02007927#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02007928
Laurent Vivierfff69382019-05-17 15:31:48 +02007929#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
Laurent Vivierde6b9932013-08-30 01:46:40 +02007930static int open_net_route(void *cpu_env, int fd)
7931{
7932 FILE *fp;
7933 char *line = NULL;
7934 size_t len = 0;
7935 ssize_t read;
7936
7937 fp = fopen("/proc/net/route", "r");
7938 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007939 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007940 }
7941
7942 /* read header */
7943
7944 read = getline(&line, &len, fp);
7945 dprintf(fd, "%s", line);
7946
7947 /* read routes */
7948
7949 while ((read = getline(&line, &len, fp)) != -1) {
7950 char iface[16];
7951 uint32_t dest, gw, mask;
7952 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
Peter Maydell9d0bd0c2019-02-05 17:42:07 +00007953 int fields;
7954
7955 fields = sscanf(line,
7956 "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7957 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7958 &mask, &mtu, &window, &irtt);
7959 if (fields != 11) {
7960 continue;
7961 }
Laurent Vivierde6b9932013-08-30 01:46:40 +02007962 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7963 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7964 metric, tswap32(mask), mtu, window, irtt);
7965 }
7966
7967 free(line);
7968 fclose(fp);
7969
7970 return 0;
7971}
7972#endif
7973
Laurent Vivierfff69382019-05-17 15:31:48 +02007974#if defined(TARGET_SPARC)
7975static int open_cpuinfo(void *cpu_env, int fd)
7976{
7977 dprintf(fd, "type\t\t: sun4u\n");
7978 return 0;
7979}
7980#endif
7981
Helge Deller93a56612020-04-24 23:06:48 +02007982#if defined(TARGET_HPPA)
7983static int open_cpuinfo(void *cpu_env, int fd)
7984{
7985 dprintf(fd, "cpu family\t: PA-RISC 1.1e\n");
7986 dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n");
7987 dprintf(fd, "capabilities\t: os32\n");
7988 dprintf(fd, "model\t\t: 9000/778/B160L\n");
7989 dprintf(fd, "model name\t: Merlin L2 160 QEMU (9000/778/B160L)\n");
7990 return 0;
7991}
7992#endif
7993
Laurent Vivier4ab67132019-05-17 15:31:49 +02007994#if defined(TARGET_M68K)
7995static int open_hardware(void *cpu_env, int fd)
7996{
7997 dprintf(fd, "Model:\t\tqemu-m68k\n");
7998 return 0;
7999}
8000#endif
8001
Riku Voipio0b2effd2014-08-06 10:36:37 +03008002static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01008003{
8004 struct fake_open {
8005 const char *filename;
8006 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02008007 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01008008 };
8009 const struct fake_open *fake_open;
8010 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02008011 { "maps", open_self_maps, is_proc_myself },
8012 { "stat", open_self_stat, is_proc_myself },
8013 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02008014 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02008015#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
8016 { "/proc/net/route", open_net_route, is_proc },
8017#endif
Helge Deller93a56612020-04-24 23:06:48 +02008018#if defined(TARGET_SPARC) || defined(TARGET_HPPA)
Laurent Vivierfff69382019-05-17 15:31:48 +02008019 { "/proc/cpuinfo", open_cpuinfo, is_proc },
8020#endif
Laurent Vivier4ab67132019-05-17 15:31:49 +02008021#if defined(TARGET_M68K)
8022 { "/proc/hardware", open_hardware, is_proc },
8023#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02008024 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01008025 };
8026
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03008027 if (is_proc_myself(pathname, "exe")) {
8028 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01008029 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03008030 }
8031
Alexander Graf3be14d02011-11-02 20:23:23 +01008032 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02008033 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01008034 break;
8035 }
8036 }
8037
8038 if (fake_open->filename) {
8039 const char *tmpdir;
8040 char filename[PATH_MAX];
8041 int fd, r;
8042
8043 /* create temporary file to map stat to */
8044 tmpdir = getenv("TMPDIR");
8045 if (!tmpdir)
8046 tmpdir = "/tmp";
8047 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
8048 fd = mkstemp(filename);
8049 if (fd < 0) {
8050 return fd;
8051 }
8052 unlink(filename);
8053
8054 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01008055 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01008056 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01008057 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01008058 return r;
8059 }
8060 lseek(fd, 0, SEEK_SET);
8061
8062 return fd;
8063 }
8064
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01008065 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01008066}
8067
Alexander Grafaecc8862014-11-10 21:33:03 +01008068#define TIMER_MAGIC 0x0caf0000
8069#define TIMER_MAGIC_MASK 0xffff0000
8070
8071/* Convert QEMU provided timer ID back to internal 16bit index format */
8072static target_timer_t get_timer_id(abi_long arg)
8073{
8074 target_timer_t timerid = arg;
8075
8076 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
8077 return -TARGET_EINVAL;
8078 }
8079
8080 timerid &= 0xffff;
8081
8082 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
8083 return -TARGET_EINVAL;
8084 }
8085
8086 return timerid;
8087}
8088
Samuel Thibault2e0a8712018-01-09 21:16:43 +01008089static int target_to_host_cpu_mask(unsigned long *host_mask,
8090 size_t host_size,
8091 abi_ulong target_addr,
8092 size_t target_size)
8093{
8094 unsigned target_bits = sizeof(abi_ulong) * 8;
8095 unsigned host_bits = sizeof(*host_mask) * 8;
8096 abi_ulong *target_mask;
8097 unsigned i, j;
8098
8099 assert(host_size >= target_size);
8100
8101 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
8102 if (!target_mask) {
8103 return -TARGET_EFAULT;
8104 }
8105 memset(host_mask, 0, host_size);
8106
8107 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
8108 unsigned bit = i * target_bits;
8109 abi_ulong val;
8110
8111 __get_user(val, &target_mask[i]);
8112 for (j = 0; j < target_bits; j++, bit++) {
8113 if (val & (1UL << j)) {
8114 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
8115 }
8116 }
8117 }
8118
8119 unlock_user(target_mask, target_addr, 0);
8120 return 0;
8121}
8122
8123static int host_to_target_cpu_mask(const unsigned long *host_mask,
8124 size_t host_size,
8125 abi_ulong target_addr,
8126 size_t target_size)
8127{
8128 unsigned target_bits = sizeof(abi_ulong) * 8;
8129 unsigned host_bits = sizeof(*host_mask) * 8;
8130 abi_ulong *target_mask;
8131 unsigned i, j;
8132
8133 assert(host_size >= target_size);
8134
8135 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
8136 if (!target_mask) {
8137 return -TARGET_EFAULT;
8138 }
8139
8140 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
8141 unsigned bit = i * target_bits;
8142 abi_ulong val = 0;
8143
8144 for (j = 0; j < target_bits; j++, bit++) {
8145 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
8146 val |= 1UL << j;
8147 }
8148 }
8149 __put_user(val, &target_mask[i]);
8150 }
8151
8152 unlock_user(target_mask, target_addr, target_size);
8153 return 0;
8154}
8155
Richard Hendersondc1ce182018-08-18 12:01:04 -07008156/* This is an internal helper for do_syscall so that it is easier
8157 * to have a single return point, so that actions, such as logging
8158 * of syscall results, can be performed.
8159 * All errnos that do_syscall() returns must be -TARGET_<errcode>.
8160 */
8161static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
8162 abi_long arg2, abi_long arg3, abi_long arg4,
8163 abi_long arg5, abi_long arg6, abi_long arg7,
8164 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00008165{
Richard Henderson29a0af62019-03-22 16:07:18 -07008166 CPUState *cpu = env_cpu(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00008167 abi_long ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008168#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
8169 || defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02008170 || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) \
8171 || defined(TARGET_NR_statx)
bellard31e31b82003-02-18 22:55:36 +00008172 struct stat st;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008173#endif
8174#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
8175 || defined(TARGET_NR_fstatfs)
bellard56c8f682005-11-28 22:28:41 +00008176 struct statfs stfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008177#endif
pbrook53a59602006-03-25 19:31:22 +00008178 void *p;
ths3b46e622007-09-17 08:09:54 +00008179
bellard31e31b82003-02-18 22:55:36 +00008180 switch(num) {
8181 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02008182 /* In old applications this may be used to implement _exit(2).
zhaolichang6f9ff552020-09-17 15:50:25 +08008183 However in threaded applications it is used for thread termination,
Andreas Färber9b056fc2013-06-24 23:53:10 +02008184 and _exit_group is used for application termination.
8185 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01008186
8187 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008188 return -TARGET_ERESTARTSYS;
Timothy E Baldwina0995882016-05-27 15:51:56 +01008189 }
8190
Alex Bennée1f81ce92020-05-20 15:05:39 +01008191 pthread_mutex_lock(&clone_lock);
Alex Bennéedd1f6342016-09-30 22:31:01 +01008192
Andreas Färberbdc44642013-06-24 23:50:24 +02008193 if (CPU_NEXT(first_cpu)) {
Alex Bennée1f81ce92020-05-20 15:05:39 +01008194 TaskState *ts = cpu->opaque;
pbrookc2764712009-03-07 15:24:59 +00008195
Markus Armbruster5325cc32020-07-07 18:05:54 +02008196 object_property_set_bool(OBJECT(cpu), "realized", false, NULL);
Alex Bennée1f81ce92020-05-20 15:05:39 +01008197 object_unref(OBJECT(cpu));
8198 /*
8199 * At this point the CPU should be unrealized and removed
8200 * from cpu lists. We can clean-up the rest of the thread
8201 * data without the lock held.
8202 */
Alex Bennéedd1f6342016-09-30 22:31:01 +01008203
Alex Bennée1f81ce92020-05-20 15:05:39 +01008204 pthread_mutex_unlock(&clone_lock);
Alex Bennéedd1f6342016-09-30 22:31:01 +01008205
Andreas Färber9b056fc2013-06-24 23:53:10 +02008206 if (ts->child_tidptr) {
8207 put_user_u32(0, ts->child_tidptr);
Alistair Francis14690292020-03-18 15:47:01 -07008208 do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
Andreas Färber9b056fc2013-06-24 23:53:10 +02008209 NULL, NULL, 0);
8210 }
Andreas Färbera2247f82013-06-09 19:47:04 +02008211 thread_cpu = NULL;
Andreas Färber9b056fc2013-06-24 23:53:10 +02008212 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04008213 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02008214 pthread_exit(NULL);
8215 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01008216
Alex Bennée1f81ce92020-05-20 15:05:39 +01008217 pthread_mutex_unlock(&clone_lock);
Alex Bennée708b6a62018-06-22 17:09:10 +01008218 preexit_cleanup(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00008219 _exit(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008220 return 0; /* avoid warning */
bellard31e31b82003-02-18 22:55:36 +00008221 case TARGET_NR_read:
Andreas Schwabba584f12019-03-05 17:45:05 +01008222 if (arg2 == 0 && arg3 == 0) {
8223 return get_errno(safe_read(arg1, 0, 0));
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008224 } else {
aurel3238d840e2009-01-30 19:48:17 +00008225 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008226 return -TARGET_EFAULT;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01008227 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008228 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01008229 fd_trans_host_to_target_data(arg1)) {
8230 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02008231 }
aurel3238d840e2009-01-30 19:48:17 +00008232 unlock_user(p, arg2, ret);
8233 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008234 return ret;
bellard31e31b82003-02-18 22:55:36 +00008235 case TARGET_NR_write:
Tony Garnock-Jones58cfa6c2018-09-08 19:22:05 +01008236 if (arg2 == 0 && arg3 == 0) {
8237 return get_errno(safe_write(arg1, 0, 0));
8238 }
bellard579a97f2007-11-11 14:26:47 +00008239 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008240 return -TARGET_EFAULT;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01008241 if (fd_trans_target_to_host_data(arg1)) {
8242 void *copy = g_malloc(arg3);
8243 memcpy(copy, p, arg3);
8244 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
8245 if (ret >= 0) {
8246 ret = get_errno(safe_write(arg1, copy, ret));
8247 }
8248 g_free(copy);
8249 } else {
8250 ret = get_errno(safe_write(arg1, p, arg3));
8251 }
pbrook53a59602006-03-25 19:31:22 +00008252 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008253 return ret;
8254
Chen Gang704eff62015-08-21 05:37:33 +08008255#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00008256 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00008257 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008258 return -TARGET_EFAULT;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008259 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
8260 target_to_host_bitmask(arg2, fcntl_flags_tbl),
8261 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008262 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008263 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008264 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008265#endif
ths82424832007-09-24 09:21:55 +00008266 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00008267 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008268 return -TARGET_EFAULT;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008269 ret = get_errno(do_openat(cpu_env, arg1, p,
8270 target_to_host_bitmask(arg3, fcntl_flags_tbl),
8271 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02008272 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00008273 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008274 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008275#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8276 case TARGET_NR_name_to_handle_at:
8277 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008278 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008279#endif
8280#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8281 case TARGET_NR_open_by_handle_at:
8282 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008283 fd_trans_unregister(ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008284 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008285#endif
bellard31e31b82003-02-18 22:55:36 +00008286 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02008287 fd_trans_unregister(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008288 return get_errno(close(arg1));
8289
bellard31e31b82003-02-18 22:55:36 +00008290 case TARGET_NR_brk:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008291 return do_brk(arg1);
Chen Gang704eff62015-08-21 05:37:33 +08008292#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00008293 case TARGET_NR_fork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008294 return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
Chen Gang704eff62015-08-21 05:37:33 +08008295#endif
thse5febef2007-04-01 18:31:35 +00008296#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00008297 case TARGET_NR_waitpid:
8298 {
pbrook53a59602006-03-25 19:31:22 +00008299 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008300 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01008301 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00008302 && put_user_s32(host_to_target_waitstatus(status), arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008303 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00008304 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008305 return ret;
thse5febef2007-04-01 18:31:35 +00008306#endif
pbrookf0cbb612008-05-30 18:20:05 +00008307#ifdef TARGET_NR_waitid
8308 case TARGET_NR_waitid:
8309 {
8310 siginfo_t info;
8311 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008312 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00008313 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008314 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008315 return -TARGET_EFAULT;
pbrookf0cbb612008-05-30 18:20:05 +00008316 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05008317 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00008318 }
8319 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008320 return ret;
pbrookf0cbb612008-05-30 18:20:05 +00008321#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008322#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008323 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00008324 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008325 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008326 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008327 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008328 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008329 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00008330#endif
Chen Gang704eff62015-08-21 05:37:33 +08008331#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00008332 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00008333 {
8334 void * p2;
8335 p = lock_user_string(arg1);
8336 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008337 if (!p || !p2)
8338 ret = -TARGET_EFAULT;
8339 else
8340 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008341 unlock_user(p2, arg2, 0);
8342 unlock_user(p, arg1, 0);
8343 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008344 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008345#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008346#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008347 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008348 {
8349 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008350 if (!arg2 || !arg4)
Richard Henderson2852aaf2018-08-18 12:01:06 -07008351 return -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008352 p = lock_user_string(arg2);
8353 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008354 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008355 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008356 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008357 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008358 unlock_user(p, arg2, 0);
8359 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008360 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008361 return ret;
ths64f0ce42007-09-24 09:25:06 +00008362#endif
Chen Gang704eff62015-08-21 05:37:33 +08008363#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008364 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008365 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008366 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008367 ret = get_errno(unlink(p));
8368 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008369 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008370#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008371#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008372 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008373 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008374 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008375 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008376 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008377 return ret;
balrogb7d35e62007-12-12 00:40:24 +00008378#endif
bellard31e31b82003-02-18 22:55:36 +00008379 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008380 {
8381 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008382 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008383 abi_ulong gp;
8384 abi_ulong guest_argp;
8385 abi_ulong guest_envp;
8386 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008387 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008388 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008389
bellardf7341ff2003-03-30 21:00:25 +00008390 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008391 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008392 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008393 if (get_user_ual(addr, gp))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008394 return -TARGET_EFAULT;
ths03aa1972007-12-02 06:28:08 +00008395 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008396 break;
bellard7854b052003-03-29 17:22:23 +00008397 argc++;
bellard2f619692007-11-16 10:46:05 +00008398 }
bellardf7341ff2003-03-30 21:00:25 +00008399 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008400 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008401 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008402 if (get_user_ual(addr, gp))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008403 return -TARGET_EFAULT;
ths03aa1972007-12-02 06:28:08 +00008404 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008405 break;
bellard7854b052003-03-29 17:22:23 +00008406 envc++;
bellard2f619692007-11-16 10:46:05 +00008407 }
bellard7854b052003-03-29 17:22:23 +00008408
Prasad J Panditb936cb52017-03-07 12:51:47 +05308409 argp = g_new0(char *, argc + 1);
8410 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008411
pbrookda94d262008-05-30 18:24:00 +00008412 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008413 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008414 if (get_user_ual(addr, gp))
8415 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008416 if (!addr)
8417 break;
bellard2f619692007-11-16 10:46:05 +00008418 if (!(*q = lock_user_string(addr)))
8419 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008420 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008421 }
bellardf7341ff2003-03-30 21:00:25 +00008422 *q = NULL;
8423
pbrookda94d262008-05-30 18:24:00 +00008424 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008425 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008426 if (get_user_ual(addr, gp))
8427 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008428 if (!addr)
8429 break;
bellard2f619692007-11-16 10:46:05 +00008430 if (!(*q = lock_user_string(addr)))
8431 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008432 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008433 }
bellardf7341ff2003-03-30 21:00:25 +00008434 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008435
bellard2f619692007-11-16 10:46:05 +00008436 if (!(p = lock_user_string(arg1)))
8437 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008438 /* Although execve() is not an interruptible syscall it is
8439 * a special case where we must use the safe_syscall wrapper:
8440 * if we allow a signal to happen before we make the host
8441 * syscall then we will 'lose' it, because at the point of
8442 * execve the process leaves QEMU's control. So we use the
8443 * safe syscall wrapper to ensure that we either take the
8444 * signal as a guest signal, or else it does not happen
8445 * before the execve completes and makes it the other
8446 * program's problem.
8447 */
8448 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008449 unlock_user(p, arg1, 0);
8450
bellard2f619692007-11-16 10:46:05 +00008451 goto execve_end;
8452
8453 execve_efault:
8454 ret = -TARGET_EFAULT;
8455
8456 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008457 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008458 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008459 if (get_user_ual(addr, gp)
8460 || !addr)
8461 break;
pbrook53a59602006-03-25 19:31:22 +00008462 unlock_user(*q, addr, 0);
8463 }
8464 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008465 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008466 if (get_user_ual(addr, gp)
8467 || !addr)
8468 break;
pbrook53a59602006-03-25 19:31:22 +00008469 unlock_user(*q, addr, 0);
8470 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308471
8472 g_free(argp);
8473 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008474 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008475 return ret;
bellard31e31b82003-02-18 22:55:36 +00008476 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008477 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008478 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008479 ret = get_errno(chdir(p));
8480 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008481 return ret;
bellarda315a142005-01-30 22:59:18 +00008482#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008483 case TARGET_NR_time:
8484 {
pbrook53a59602006-03-25 19:31:22 +00008485 time_t host_time;
8486 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008487 if (!is_error(ret)
8488 && arg1
8489 && put_user_sal(host_time, arg1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008490 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00008491 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008492 return ret;
bellarda315a142005-01-30 22:59:18 +00008493#endif
Chen Gang704eff62015-08-21 05:37:33 +08008494#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008495 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008496 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008497 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008498 ret = get_errno(mknod(p, arg2, arg3));
8499 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008500 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008501#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008502#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008503 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008504 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008505 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008506 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008507 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008508 return ret;
ths75ac37a2007-09-24 09:23:05 +00008509#endif
Chen Gang704eff62015-08-21 05:37:33 +08008510#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008511 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008512 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008513 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008514 ret = get_errno(chmod(p, arg2));
8515 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008516 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008517#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008518#ifdef TARGET_NR_lseek
bellard31e31b82003-02-18 22:55:36 +00008519 case TARGET_NR_lseek:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008520 return get_errno(lseek(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008521#endif
Richard Henderson92317332010-05-03 10:07:53 -07008522#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8523 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008524 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008525 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008526 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07008527#endif
8528#ifdef TARGET_NR_getpid
8529 case TARGET_NR_getpid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008530 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07008531#endif
bellard31e31b82003-02-18 22:55:36 +00008532 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008533 {
8534 /* need to look at the data field */
8535 void *p2, *p3;
8536
8537 if (arg1) {
8538 p = lock_user_string(arg1);
8539 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008540 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01008541 }
8542 } else {
8543 p = NULL;
8544 }
8545
8546 p2 = lock_user_string(arg2);
8547 if (!p2) {
8548 if (arg1) {
8549 unlock_user(p, arg1, 0);
8550 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07008551 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01008552 }
8553
8554 if (arg3) {
8555 p3 = lock_user_string(arg3);
8556 if (!p3) {
8557 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008558 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008559 }
8560 unlock_user(p2, arg2, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07008561 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01008562 }
8563 } else {
8564 p3 = NULL;
8565 }
8566
8567 /* FIXME - arg5 should be locked, but it isn't clear how to
8568 * do that since it's not guaranteed to be a NULL-terminated
8569 * string.
8570 */
8571 if (!arg5) {
8572 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8573 } else {
8574 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8575 }
8576 ret = get_errno(ret);
8577
8578 if (arg1) {
8579 unlock_user(p, arg1, 0);
8580 }
8581 unlock_user(p2, arg2, 0);
8582 if (arg3) {
8583 unlock_user(p3, arg3, 0);
8584 }
8585 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008586 return ret;
Laurent Vivier6eb9dbf2020-05-02 21:46:42 +02008587#if defined(TARGET_NR_umount) || defined(TARGET_NR_oldumount)
8588#if defined(TARGET_NR_umount)
bellard31e31b82003-02-18 22:55:36 +00008589 case TARGET_NR_umount:
Laurent Vivier6eb9dbf2020-05-02 21:46:42 +02008590#endif
8591#if defined(TARGET_NR_oldumount)
8592 case TARGET_NR_oldumount:
8593#endif
bellard579a97f2007-11-11 14:26:47 +00008594 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008595 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008596 ret = get_errno(umount(p));
8597 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008598 return ret;
thse5febef2007-04-01 18:31:35 +00008599#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008600#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008601 case TARGET_NR_stime:
8602 {
Laurent Vivier0f1f2d42019-11-12 15:25:56 +01008603 struct timespec ts;
8604 ts.tv_nsec = 0;
8605 if (get_user_sal(ts.tv_sec, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008606 return -TARGET_EFAULT;
Laurent Vivier0f1f2d42019-11-12 15:25:56 +01008607 }
8608 return get_errno(clock_settime(CLOCK_REALTIME, &ts));
bellard31e31b82003-02-18 22:55:36 +00008609 }
j_mayer7a3148a2007-04-05 07:13:51 +00008610#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008611#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008612 case TARGET_NR_alarm:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008613 return alarm(arg1);
j_mayer7a3148a2007-04-05 07:13:51 +00008614#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008615#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008616 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008617 if (!block_signals()) {
8618 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8619 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008620 return -TARGET_EINTR;
j_mayer7a3148a2007-04-05 07:13:51 +00008621#endif
thse5febef2007-04-01 18:31:35 +00008622#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008623 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008624 {
pbrook53a59602006-03-25 19:31:22 +00008625 struct utimbuf tbuf, *host_tbuf;
8626 struct target_utimbuf *target_tbuf;
8627 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008628 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008629 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008630 tbuf.actime = tswapal(target_tbuf->actime);
8631 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008632 unlock_user_struct(target_tbuf, arg2, 0);
8633 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008634 } else {
pbrook53a59602006-03-25 19:31:22 +00008635 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008636 }
bellard579a97f2007-11-11 14:26:47 +00008637 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008638 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008639 ret = get_errno(utime(p, host_tbuf));
8640 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008641 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008642 return ret;
thse5febef2007-04-01 18:31:35 +00008643#endif
Chen Gang704eff62015-08-21 05:37:33 +08008644#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008645 case TARGET_NR_utimes:
8646 {
bellard978a66f2004-12-06 22:58:05 +00008647 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008648 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008649 if (copy_from_user_timeval(&tv[0], arg2)
8650 || copy_from_user_timeval(&tv[1],
8651 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008652 return -TARGET_EFAULT;
bellard978a66f2004-12-06 22:58:05 +00008653 tvp = tv;
8654 } else {
8655 tvp = NULL;
8656 }
bellard579a97f2007-11-11 14:26:47 +00008657 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008658 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008659 ret = get_errno(utimes(p, tvp));
8660 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008661 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008662 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008663#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008664#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008665 case TARGET_NR_futimesat:
8666 {
8667 struct timeval *tvp, tv[2];
8668 if (arg3) {
8669 if (copy_from_user_timeval(&tv[0], arg3)
8670 || copy_from_user_timeval(&tv[1],
8671 arg3 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008672 return -TARGET_EFAULT;
balrogac8a6552008-09-20 02:25:39 +00008673 tvp = tv;
8674 } else {
8675 tvp = NULL;
8676 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07008677 if (!(p = lock_user_string(arg2))) {
8678 return -TARGET_EFAULT;
8679 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01008680 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008681 unlock_user(p, arg2, 0);
8682 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008683 return ret;
balrogac8a6552008-09-20 02:25:39 +00008684#endif
Chen Gang704eff62015-08-21 05:37:33 +08008685#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008686 case TARGET_NR_access:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008687 if (!(p = lock_user_string(arg1))) {
8688 return -TARGET_EFAULT;
8689 }
Ulrich Hecht719f9082009-07-03 17:09:29 +02008690 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008691 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008692 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008693#endif
ths92a34c12007-09-24 09:27:49 +00008694#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8695 case TARGET_NR_faccessat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07008696 if (!(p = lock_user_string(arg2))) {
8697 return -TARGET_EFAULT;
8698 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01008699 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008700 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008701 return ret;
ths92a34c12007-09-24 09:27:49 +00008702#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008703#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008704 case TARGET_NR_nice:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008705 return get_errno(nice(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00008706#endif
bellard31e31b82003-02-18 22:55:36 +00008707 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008708 sync();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008709 return 0;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008710#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8711 case TARGET_NR_syncfs:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008712 return get_errno(syncfs(arg1));
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008713#endif
bellard31e31b82003-02-18 22:55:36 +00008714 case TARGET_NR_kill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008715 return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
Chen Gang704eff62015-08-21 05:37:33 +08008716#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008717 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008718 {
8719 void *p2;
8720 p = lock_user_string(arg1);
8721 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008722 if (!p || !p2)
8723 ret = -TARGET_EFAULT;
8724 else
8725 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008726 unlock_user(p2, arg2, 0);
8727 unlock_user(p, arg1, 0);
8728 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008729 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008730#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008731#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008732 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008733 {
bellard579a97f2007-11-11 14:26:47 +00008734 void *p2;
ths722183f2007-09-24 09:24:37 +00008735 p = lock_user_string(arg2);
8736 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008737 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008738 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008739 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008740 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008741 unlock_user(p2, arg4, 0);
8742 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008743 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008744 return ret;
ths722183f2007-09-24 09:24:37 +00008745#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01008746#if defined(TARGET_NR_renameat2)
8747 case TARGET_NR_renameat2:
8748 {
8749 void *p2;
8750 p = lock_user_string(arg2);
8751 p2 = lock_user_string(arg4);
8752 if (!p || !p2) {
8753 ret = -TARGET_EFAULT;
8754 } else {
8755 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
8756 }
8757 unlock_user(p2, arg4, 0);
8758 unlock_user(p, arg2, 0);
8759 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008760 return ret;
Andreas Schwab95d03072018-01-23 11:53:31 +01008761#endif
Chen Gang704eff62015-08-21 05:37:33 +08008762#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008763 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008764 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008765 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008766 ret = get_errno(mkdir(p, arg2));
8767 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008768 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008769#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008770#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008771 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008772 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008773 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008774 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008775 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008776 return ret;
ths4472ad02007-09-24 09:22:32 +00008777#endif
Chen Gang704eff62015-08-21 05:37:33 +08008778#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008779 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008780 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008781 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008782 ret = get_errno(rmdir(p));
8783 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008784 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008785#endif
bellard31e31b82003-02-18 22:55:36 +00008786 case TARGET_NR_dup:
8787 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008788 if (ret >= 0) {
8789 fd_trans_dup(arg1, ret);
8790 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008791 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008792#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008793 case TARGET_NR_pipe:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008794 return do_pipe(cpu_env, arg1, 0, 0);
Chen Gang704eff62015-08-21 05:37:33 +08008795#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008796#ifdef TARGET_NR_pipe2
8797 case TARGET_NR_pipe2:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008798 return do_pipe(cpu_env, arg1,
8799 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008800#endif
bellard31e31b82003-02-18 22:55:36 +00008801 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008802 {
pbrook53a59602006-03-25 19:31:22 +00008803 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008804 struct tms tms;
8805 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008806 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008807 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8808 if (!tmsp)
Richard Henderson2852aaf2018-08-18 12:01:06 -07008809 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008810 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8811 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8812 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8813 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008814 }
bellardc596ed12003-07-13 17:32:31 +00008815 if (!is_error(ret))
8816 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008817 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008818 return ret;
bellard31e31b82003-02-18 22:55:36 +00008819 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008820 if (arg1 == 0) {
8821 ret = get_errno(acct(NULL));
8822 } else {
Richard Henderson2852aaf2018-08-18 12:01:06 -07008823 if (!(p = lock_user_string(arg1))) {
8824 return -TARGET_EFAULT;
8825 }
aurel3238d840e2009-01-30 19:48:17 +00008826 ret = get_errno(acct(path(p)));
8827 unlock_user(p, arg1, 0);
8828 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008829 return ret;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008830#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008831 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008832 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008833 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008834 ret = get_errno(umount2(p, arg2));
8835 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008836 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00008837#endif
bellard31e31b82003-02-18 22:55:36 +00008838 case TARGET_NR_ioctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008839 return do_ioctl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13008840#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00008841 case TARGET_NR_fcntl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008842 return do_fcntl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13008843#endif
bellard31e31b82003-02-18 22:55:36 +00008844 case TARGET_NR_setpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008845 return get_errno(setpgid(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008846 case TARGET_NR_umask:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008847 return get_errno(umask(arg1));
bellard31e31b82003-02-18 22:55:36 +00008848 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008849 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008850 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008851 ret = get_errno(chroot(p));
8852 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008853 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008854#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008855 case TARGET_NR_dup2:
8856 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008857 if (ret >= 0) {
8858 fd_trans_dup(arg1, arg2);
8859 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008860 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08008861#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008862#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8863 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008864 {
8865 int host_flags;
8866
8867 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8868 return -EINVAL;
8869 }
8870 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8871 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008872 if (ret >= 0) {
8873 fd_trans_dup(arg1, arg2);
8874 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008875 return ret;
Peter Maydell10fa9932017-12-15 15:18:00 +00008876 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008877#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008878#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008879 case TARGET_NR_getppid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008880 return get_errno(getppid());
j_mayer7a3148a2007-04-05 07:13:51 +00008881#endif
Chen Gang704eff62015-08-21 05:37:33 +08008882#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008883 case TARGET_NR_getpgrp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008884 return get_errno(getpgrp());
Chen Gang704eff62015-08-21 05:37:33 +08008885#endif
bellard31e31b82003-02-18 22:55:36 +00008886 case TARGET_NR_setsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008887 return get_errno(setsid());
thse5febef2007-04-01 18:31:35 +00008888#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008889 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008890 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008891#if defined(TARGET_ALPHA)
8892 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008893 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008894 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008895 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008896 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00008897 act._sa_handler = old_act->_sa_handler;
8898 target_siginitset(&act.sa_mask, old_act->sa_mask);
8899 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008900 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008901 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008902 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008903 }
8904 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008905 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008906 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008907 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00008908 old_act->_sa_handler = oact._sa_handler;
8909 old_act->sa_mask = oact.sa_mask.sig[0];
8910 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008911 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008912 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008913#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008914 struct target_sigaction act, oact, *pact, *old_act;
8915
8916 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008917 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008918 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00008919 act._sa_handler = old_act->_sa_handler;
8920 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8921 act.sa_flags = old_act->sa_flags;
8922 unlock_user_struct(old_act, arg2, 0);
8923 pact = &act;
8924 } else {
8925 pact = NULL;
8926 }
8927
8928 ret = get_errno(do_sigaction(arg1, pact, &oact));
8929
8930 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008931 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008932 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00008933 old_act->_sa_handler = oact._sa_handler;
8934 old_act->sa_flags = oact.sa_flags;
8935 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8936 old_act->sa_mask.sig[1] = 0;
8937 old_act->sa_mask.sig[2] = 0;
8938 old_act->sa_mask.sig[3] = 0;
8939 unlock_user_struct(old_act, arg3, 1);
8940 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008941#else
8942 struct target_old_sigaction *old_act;
8943 struct target_sigaction act, oact, *pact;
8944 if (arg2) {
8945 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008946 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008947 act._sa_handler = old_act->_sa_handler;
8948 target_siginitset(&act.sa_mask, old_act->sa_mask);
8949 act.sa_flags = old_act->sa_flags;
8950 act.sa_restorer = old_act->sa_restorer;
Laurent Vivier5de154e2018-04-02 12:24:52 +02008951#ifdef TARGET_ARCH_HAS_KA_RESTORER
8952 act.ka_restorer = 0;
8953#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08008954 unlock_user_struct(old_act, arg2, 0);
8955 pact = &act;
8956 } else {
8957 pact = NULL;
8958 }
8959 ret = get_errno(do_sigaction(arg1, pact, &oact));
8960 if (!is_error(ret) && arg3) {
8961 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008962 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008963 old_act->_sa_handler = oact._sa_handler;
8964 old_act->sa_mask = oact.sa_mask.sig[0];
8965 old_act->sa_flags = oact.sa_flags;
8966 old_act->sa_restorer = oact.sa_restorer;
8967 unlock_user_struct(old_act, arg3, 1);
8968 }
ths388bb212007-05-13 13:58:00 +00008969#endif
bellard31e31b82003-02-18 22:55:36 +00008970 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008971 return ret;
thse5febef2007-04-01 18:31:35 +00008972#endif
bellard66fb9762003-03-23 01:06:05 +00008973 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008974 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008975#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008976 /* For Alpha and SPARC this is a 5 argument syscall, with
8977 * a 'restorer' parameter which must be copied into the
8978 * sa_restorer field of the sigaction struct.
8979 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8980 * and arg5 is the sigsetsize.
8981 * Alpha also has a separate rt_sigaction struct that it uses
8982 * here; SPARC uses the usual sigaction struct.
8983 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008984 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008985 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008986
8987 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07008988 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01008989 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008990 if (arg2) {
8991 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07008992 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008993 act._sa_handler = rt_act->_sa_handler;
8994 act.sa_mask = rt_act->sa_mask;
8995 act.sa_flags = rt_act->sa_flags;
8996 act.sa_restorer = arg5;
8997 unlock_user_struct(rt_act, arg2, 0);
8998 pact = &act;
8999 }
9000 ret = get_errno(do_sigaction(arg1, pact, &oact));
9001 if (!is_error(ret) && arg3) {
9002 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009003 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08009004 rt_act->_sa_handler = oact._sa_handler;
9005 rt_act->sa_mask = oact.sa_mask;
9006 rt_act->sa_flags = oact.sa_flags;
9007 unlock_user_struct(rt_act, arg3, 1);
9008 }
9009#else
Peter Maydell78bfef72017-11-06 18:33:26 +00009010#ifdef TARGET_SPARC
9011 target_ulong restorer = arg4;
9012 target_ulong sigsetsize = arg5;
9013#else
9014 target_ulong sigsetsize = arg4;
9015#endif
pbrook53a59602006-03-25 19:31:22 +00009016 struct target_sigaction *act;
9017 struct target_sigaction *oact;
9018
Peter Maydell78bfef72017-11-06 18:33:26 +00009019 if (sigsetsize != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009020 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009021 }
bellard579a97f2007-11-11 14:26:47 +00009022 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00009023 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009024 return -TARGET_EFAULT;
Peter Maydell78bfef72017-11-06 18:33:26 +00009025 }
Laurent Vivier5de154e2018-04-02 12:24:52 +02009026#ifdef TARGET_ARCH_HAS_KA_RESTORER
9027 act->ka_restorer = restorer;
Peter Maydell78bfef72017-11-06 18:33:26 +00009028#endif
9029 } else {
pbrook53a59602006-03-25 19:31:22 +00009030 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00009031 }
bellard579a97f2007-11-11 14:26:47 +00009032 if (arg3) {
9033 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
9034 ret = -TARGET_EFAULT;
9035 goto rt_sigaction_fail;
9036 }
9037 } else
pbrook53a59602006-03-25 19:31:22 +00009038 oact = NULL;
9039 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00009040 rt_sigaction_fail:
9041 if (act)
pbrook53a59602006-03-25 19:31:22 +00009042 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009043 if (oact)
pbrook53a59602006-03-25 19:31:22 +00009044 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08009045#endif
pbrook53a59602006-03-25 19:31:22 +00009046 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009047 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009048#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009049 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00009050 {
9051 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00009052 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009053 ret = do_sigprocmask(0, NULL, &cur_set);
9054 if (!ret) {
9055 host_to_target_old_sigset(&target_set, &cur_set);
9056 ret = target_set;
9057 }
bellard66fb9762003-03-23 01:06:05 +00009058 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009059 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009060#endif
9061#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009062 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00009063 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02009064 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00009065 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00009066 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009067 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
9068 if (!ret) {
9069 host_to_target_old_sigset(&target_set, &oset);
9070 ret = target_set;
9071 }
bellard66fb9762003-03-23 01:06:05 +00009072 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009073 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009074#endif
thse5febef2007-04-01 18:31:35 +00009075#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00009076 case TARGET_NR_sigprocmask:
9077 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07009078#if defined(TARGET_ALPHA)
9079 sigset_t set, oldset;
9080 abi_ulong mask;
9081 int how;
9082
9083 switch (arg1) {
9084 case TARGET_SIG_BLOCK:
9085 how = SIG_BLOCK;
9086 break;
9087 case TARGET_SIG_UNBLOCK:
9088 how = SIG_UNBLOCK;
9089 break;
9090 case TARGET_SIG_SETMASK:
9091 how = SIG_SETMASK;
9092 break;
9093 default:
Richard Henderson259841c2018-08-18 12:01:09 -07009094 return -TARGET_EINVAL;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009095 }
9096 mask = arg2;
9097 target_to_host_old_sigset(&set, &mask);
9098
Peter Maydell3d3efba2016-05-27 15:51:49 +01009099 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07009100 if (!is_error(ret)) {
9101 host_to_target_old_sigset(&mask, &oldset);
9102 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07009103 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07009104 }
9105#else
bellard66fb9762003-03-23 01:06:05 +00009106 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009107 int how;
ths3b46e622007-09-17 08:09:54 +00009108
pbrook53a59602006-03-25 19:31:22 +00009109 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07009110 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00009111 case TARGET_SIG_BLOCK:
9112 how = SIG_BLOCK;
9113 break;
9114 case TARGET_SIG_UNBLOCK:
9115 how = SIG_UNBLOCK;
9116 break;
9117 case TARGET_SIG_SETMASK:
9118 how = SIG_SETMASK;
9119 break;
9120 default:
Richard Henderson259841c2018-08-18 12:01:09 -07009121 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009122 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009123 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009124 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009125 target_to_host_old_sigset(&set, p);
9126 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009127 set_ptr = &set;
9128 } else {
9129 how = 0;
9130 set_ptr = NULL;
9131 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009132 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009133 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009134 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009135 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009136 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009137 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009138 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07009139#endif
bellard66fb9762003-03-23 01:06:05 +00009140 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009141 return ret;
thse5febef2007-04-01 18:31:35 +00009142#endif
bellard66fb9762003-03-23 01:06:05 +00009143 case TARGET_NR_rt_sigprocmask:
9144 {
9145 int how = arg1;
9146 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00009147
Peter Maydellc8157012016-06-30 14:23:24 +01009148 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009149 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009150 }
9151
pbrook53a59602006-03-25 19:31:22 +00009152 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009153 switch(how) {
9154 case TARGET_SIG_BLOCK:
9155 how = SIG_BLOCK;
9156 break;
9157 case TARGET_SIG_UNBLOCK:
9158 how = SIG_UNBLOCK;
9159 break;
9160 case TARGET_SIG_SETMASK:
9161 how = SIG_SETMASK;
9162 break;
9163 default:
Richard Henderson259841c2018-08-18 12:01:09 -07009164 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009165 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009166 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009167 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009168 target_to_host_sigset(&set, p);
9169 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009170 set_ptr = &set;
9171 } else {
9172 how = 0;
9173 set_ptr = NULL;
9174 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009175 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009176 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009177 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009178 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009179 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009180 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009181 }
9182 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009183 return ret;
thse5febef2007-04-01 18:31:35 +00009184#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00009185 case TARGET_NR_sigpending:
9186 {
9187 sigset_t set;
9188 ret = get_errno(sigpending(&set));
9189 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009190 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009191 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009192 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009193 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009194 }
9195 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009196 return ret;
thse5febef2007-04-01 18:31:35 +00009197#endif
bellard66fb9762003-03-23 01:06:05 +00009198 case TARGET_NR_rt_sigpending:
9199 {
9200 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01009201
9202 /* Yes, this check is >, not != like most. We follow the kernel's
9203 * logic and it does it like this because it implements
9204 * NR_sigpending through the same code path, and in that case
9205 * the old_sigset_t is smaller in size.
9206 */
9207 if (arg2 > sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009208 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009209 }
9210
bellard66fb9762003-03-23 01:06:05 +00009211 ret = get_errno(sigpending(&set));
9212 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009213 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009214 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009215 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009216 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009217 }
9218 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009219 return ret;
thse5febef2007-04-01 18:31:35 +00009220#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00009221 case TARGET_NR_sigsuspend:
9222 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009223 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07009224#if defined(TARGET_ALPHA)
9225 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009226 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009227#else
Anthony Liguoric227f092009-10-01 16:12:16 -05009228 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009229 return -TARGET_EFAULT;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009230 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009231 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009232#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01009233 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9234 SIGSET_T_SIZE));
9235 if (ret != -TARGET_ERESTARTSYS) {
9236 ts->in_sigsuspend = 1;
9237 }
bellard66fb9762003-03-23 01:06:05 +00009238 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009239 return ret;
thse5febef2007-04-01 18:31:35 +00009240#endif
bellard66fb9762003-03-23 01:06:05 +00009241 case TARGET_NR_rt_sigsuspend:
9242 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009243 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01009244
9245 if (arg2 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009246 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009247 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009248 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009249 return -TARGET_EFAULT;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009250 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009251 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009252 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9253 SIGSET_T_SIZE));
9254 if (ret != -TARGET_ERESTARTSYS) {
9255 ts->in_sigsuspend = 1;
9256 }
bellard66fb9762003-03-23 01:06:05 +00009257 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009258 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -07009259#ifdef TARGET_NR_rt_sigtimedwait
bellard66fb9762003-03-23 01:06:05 +00009260 case TARGET_NR_rt_sigtimedwait:
9261 {
bellard66fb9762003-03-23 01:06:05 +00009262 sigset_t set;
9263 struct timespec uts, *puts;
9264 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00009265
Peter Maydellc8157012016-06-30 14:23:24 +01009266 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009267 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009268 }
9269
Anthony Liguoric227f092009-10-01 16:12:16 -05009270 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009271 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009272 target_to_host_sigset(&set, p);
9273 unlock_user(p, arg1, 0);
9274 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00009275 puts = &uts;
Filip Bozuta4d213002020-07-24 20:16:51 +02009276 if (target_to_host_timespec(puts, arg3)) {
9277 return -TARGET_EFAULT;
9278 }
bellard66fb9762003-03-23 01:06:05 +00009279 } else {
9280 puts = NULL;
9281 }
Peter Maydellb3f82332016-06-06 19:58:08 +01009282 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9283 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01009284 if (!is_error(ret)) {
9285 if (arg2) {
9286 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
9287 0);
9288 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009289 return -TARGET_EFAULT;
Petar Jovanovic974a1962014-03-03 15:07:41 +01009290 }
9291 host_to_target_siginfo(p, &uinfo);
9292 unlock_user(p, arg2, sizeof(target_siginfo_t));
9293 }
9294 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00009295 }
9296 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009297 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -07009298#endif
Filip Bozutaddcbde12020-08-24 21:21:16 +02009299#ifdef TARGET_NR_rt_sigtimedwait_time64
9300 case TARGET_NR_rt_sigtimedwait_time64:
9301 {
9302 sigset_t set;
9303 struct timespec uts, *puts;
9304 siginfo_t uinfo;
9305
9306 if (arg4 != sizeof(target_sigset_t)) {
9307 return -TARGET_EINVAL;
9308 }
9309
9310 p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
9311 if (!p) {
9312 return -TARGET_EFAULT;
9313 }
9314 target_to_host_sigset(&set, p);
9315 unlock_user(p, arg1, 0);
9316 if (arg3) {
9317 puts = &uts;
9318 if (target_to_host_timespec64(puts, arg3)) {
9319 return -TARGET_EFAULT;
9320 }
9321 } else {
9322 puts = NULL;
9323 }
9324 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9325 SIGSET_T_SIZE));
9326 if (!is_error(ret)) {
9327 if (arg2) {
9328 p = lock_user(VERIFY_WRITE, arg2,
9329 sizeof(target_siginfo_t), 0);
9330 if (!p) {
9331 return -TARGET_EFAULT;
9332 }
9333 host_to_target_siginfo(p, &uinfo);
9334 unlock_user(p, arg2, sizeof(target_siginfo_t));
9335 }
9336 ret = host_to_target_signal(ret);
9337 }
9338 }
9339 return ret;
9340#endif
bellard66fb9762003-03-23 01:06:05 +00009341 case TARGET_NR_rt_sigqueueinfo:
9342 {
9343 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009344
9345 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9346 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009347 return -TARGET_EFAULT;
Peter Maydell4debae62016-06-20 15:50:36 +01009348 }
pbrook53a59602006-03-25 19:31:22 +00009349 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009350 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009351 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9352 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009353 return ret;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009354 case TARGET_NR_rt_tgsigqueueinfo:
9355 {
9356 siginfo_t uinfo;
9357
9358 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9359 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009360 return -TARGET_EFAULT;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009361 }
9362 target_to_host_siginfo(&uinfo, p);
9363 unlock_user(p, arg4, 0);
9364 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9365 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009366 return ret;
thse5febef2007-04-01 18:31:35 +00009367#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009368 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009369 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009370 return -TARGET_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009371 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009372 return do_sigreturn(cpu_env);
thse5febef2007-04-01 18:31:35 +00009373#endif
bellard66fb9762003-03-23 01:06:05 +00009374 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009375 if (block_signals()) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009376 return -TARGET_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009377 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009378 return do_rt_sigreturn(cpu_env);
bellard31e31b82003-02-18 22:55:36 +00009379 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009380 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009381 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009382 ret = get_errno(sethostname(p, arg2));
9383 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009384 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009385#ifdef TARGET_NR_setrlimit
bellard31e31b82003-02-18 22:55:36 +00009386 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009387 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009388 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009389 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009390 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009391 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009392 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009393 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9394 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009395 unlock_user_struct(target_rlim, arg2, 0);
Max Filippov5dfa88f2018-09-17 11:13:14 -07009396 /*
9397 * If we just passed through resource limit settings for memory then
9398 * they would also apply to QEMU's own allocations, and QEMU will
9399 * crash or hang or die if its allocations fail. Ideally we would
9400 * track the guest allocations in QEMU and apply the limits ourselves.
9401 * For now, just tell the guest the call succeeded but don't actually
9402 * limit anything.
9403 */
9404 if (resource != RLIMIT_AS &&
9405 resource != RLIMIT_DATA &&
9406 resource != RLIMIT_STACK) {
9407 return get_errno(setrlimit(resource, &rlim));
9408 } else {
9409 return 0;
9410 }
bellard9de5e442003-03-23 16:49:39 +00009411 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009412#endif
9413#ifdef TARGET_NR_getrlimit
bellard31e31b82003-02-18 22:55:36 +00009414 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009415 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009416 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009417 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009418 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009419
bellard9de5e442003-03-23 16:49:39 +00009420 ret = get_errno(getrlimit(resource, &rlim));
9421 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009422 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009423 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009424 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9425 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009426 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009427 }
9428 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009429 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009430#endif
bellard31e31b82003-02-18 22:55:36 +00009431 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009432 {
9433 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009434 ret = get_errno(getrusage(arg1, &rusage));
9435 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009436 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009437 }
9438 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009439 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -07009440#if defined(TARGET_NR_gettimeofday)
bellard31e31b82003-02-18 22:55:36 +00009441 case TARGET_NR_gettimeofday:
9442 {
bellard31e31b82003-02-18 22:55:36 +00009443 struct timeval tv;
Richard Hendersona52f5f82020-02-12 19:22:23 -08009444 struct timezone tz;
9445
9446 ret = get_errno(gettimeofday(&tv, &tz));
bellard31e31b82003-02-18 22:55:36 +00009447 if (!is_error(ret)) {
Richard Hendersona52f5f82020-02-12 19:22:23 -08009448 if (arg1 && copy_to_user_timeval(arg1, &tv)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009449 return -TARGET_EFAULT;
Richard Hendersona52f5f82020-02-12 19:22:23 -08009450 }
9451 if (arg2 && copy_to_user_timezone(arg2, &tz)) {
9452 return -TARGET_EFAULT;
9453 }
bellard31e31b82003-02-18 22:55:36 +00009454 }
9455 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009456 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -07009457#endif
9458#if defined(TARGET_NR_settimeofday)
bellard31e31b82003-02-18 22:55:36 +00009459 case TARGET_NR_settimeofday:
9460 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009461 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009462 struct timezone tz, *ptz = NULL;
9463
Paul Burtonb67d8032014-06-22 11:25:41 +01009464 if (arg1) {
9465 if (copy_from_user_timeval(&tv, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009466 return -TARGET_EFAULT;
Paul Burtonb67d8032014-06-22 11:25:41 +01009467 }
9468 ptv = &tv;
9469 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009470
9471 if (arg2) {
9472 if (copy_from_user_timezone(&tz, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009473 return -TARGET_EFAULT;
Paul Burtonef4467e2014-06-22 11:25:40 +01009474 }
9475 ptz = &tz;
9476 }
9477
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009478 return get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009479 }
Alistair Francis859e8a82020-03-12 15:13:49 -07009480#endif
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009481#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009482 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009483#if defined(TARGET_WANT_NI_OLD_SELECT)
9484 /* some architectures used to have old_select here
9485 * but now ENOSYS it.
9486 */
9487 ret = -TARGET_ENOSYS;
9488#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9489 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009490#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009491 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009492#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009493 return ret;
bellard048f6b42005-11-26 18:47:20 +00009494#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009495#ifdef TARGET_NR_pselect6
9496 case TARGET_NR_pselect6:
Filip Bozutae5ce9682020-08-25 00:30:49 +02009497 return do_pselect6(arg1, arg2, arg3, arg4, arg5, arg6, false);
9498#endif
9499#ifdef TARGET_NR_pselect6_time64
9500 case TARGET_NR_pselect6_time64:
9501 return do_pselect6(arg1, arg2, arg3, arg4, arg5, arg6, true);
Riku Voipio9e423822010-05-07 12:28:05 +00009502#endif
Chen Gang704eff62015-08-21 05:37:33 +08009503#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009504 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009505 {
9506 void *p2;
9507 p = lock_user_string(arg1);
9508 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009509 if (!p || !p2)
9510 ret = -TARGET_EFAULT;
9511 else
9512 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009513 unlock_user(p2, arg2, 0);
9514 unlock_user(p, arg1, 0);
9515 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009516 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009517#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009518#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009519 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009520 {
bellard579a97f2007-11-11 14:26:47 +00009521 void *p2;
thsf0b62432007-09-24 09:25:40 +00009522 p = lock_user_string(arg1);
9523 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009524 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009525 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009526 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009527 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009528 unlock_user(p2, arg3, 0);
9529 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009530 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009531 return ret;
thsf0b62432007-09-24 09:25:40 +00009532#endif
Chen Gang704eff62015-08-21 05:37:33 +08009533#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009534 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009535 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009536 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009537 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009538 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009539 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009540 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009541 } else if (!arg3) {
9542 /* Short circuit this for the magic exe check. */
9543 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009544 } else if (is_proc_myself((const char *)p, "exe")) {
9545 char real[PATH_MAX], *temp;
9546 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009547 /* Return value is # of bytes that we wrote to the buffer. */
9548 if (temp == NULL) {
9549 ret = get_errno(-1);
9550 } else {
9551 /* Don't worry about sign mismatch as earlier mapping
9552 * logic would have thrown a bad address error. */
9553 ret = MIN(strlen(real), arg3);
9554 /* We cannot NUL terminate the string. */
9555 memcpy(p2, real, ret);
9556 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009557 } else {
9558 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009559 }
pbrook53a59602006-03-25 19:31:22 +00009560 unlock_user(p2, arg2, ret);
9561 unlock_user(p, arg1, 0);
9562 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009563 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009564#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009565#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009566 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009567 {
bellard579a97f2007-11-11 14:26:47 +00009568 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009569 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009570 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009571 if (!p || !p2) {
9572 ret = -TARGET_EFAULT;
9573 } else if (is_proc_myself((const char *)p, "exe")) {
9574 char real[PATH_MAX], *temp;
9575 temp = realpath(exec_path, real);
9576 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9577 snprintf((char *)p2, arg4, "%s", real);
9578 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009579 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009580 }
bellard579a97f2007-11-11 14:26:47 +00009581 unlock_user(p2, arg3, ret);
9582 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009583 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009584 return ret;
ths5e0ccb12007-09-24 09:26:10 +00009585#endif
thse5febef2007-04-01 18:31:35 +00009586#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009587 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009588 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009589 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009590 ret = get_errno(swapon(p, arg2));
9591 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009592 return ret;
thse5febef2007-04-01 18:31:35 +00009593#endif
bellard31e31b82003-02-18 22:55:36 +00009594 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009595 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9596 /* arg4 must be ignored in all other cases */
9597 p = lock_user_string(arg4);
9598 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009599 return -TARGET_EFAULT;
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009600 }
9601 ret = get_errno(reboot(arg1, arg2, arg3, p));
9602 unlock_user(p, arg4, 0);
9603 } else {
9604 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9605 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009606 return ret;
thse5febef2007-04-01 18:31:35 +00009607#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009608 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009609#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9610 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009611 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9612 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009613 {
blueswir1992f48a2007-10-14 16:27:31 +00009614 abi_ulong *v;
9615 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009616 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009617 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009618 v1 = tswapal(v[0]);
9619 v2 = tswapal(v[1]);
9620 v3 = tswapal(v[2]);
9621 v4 = tswapal(v[3]);
9622 v5 = tswapal(v[4]);
9623 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009624 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009625 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009626 target_to_host_bitmask(v4, mmap_flags_tbl),
9627 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009628 }
bellard31e31b82003-02-18 22:55:36 +00009629#else
ths5fafdf22007-09-16 21:08:06 +00009630 ret = get_errno(target_mmap(arg1, arg2, arg3,
9631 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009632 arg5,
9633 arg6));
bellard31e31b82003-02-18 22:55:36 +00009634#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009635 return ret;
thse5febef2007-04-01 18:31:35 +00009636#endif
bellarda315a142005-01-30 22:59:18 +00009637#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009638 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009639#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009640#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009641#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009642 ret = target_mmap(arg1, arg2, arg3,
9643 target_to_host_bitmask(arg4, mmap_flags_tbl),
9644 arg5, arg6 << MMAP_SHIFT);
9645 return get_errno(ret);
bellarda315a142005-01-30 22:59:18 +00009646#endif
bellard31e31b82003-02-18 22:55:36 +00009647 case TARGET_NR_munmap:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009648 return get_errno(target_munmap(arg1, arg2));
bellard9de5e442003-03-23 16:49:39 +00009649 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009650 {
Andreas Färber0429a972013-08-26 18:14:44 +02009651 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009652 /* Special hack to detect libc making the stack executable. */
9653 if ((arg3 & PROT_GROWSDOWN)
9654 && arg1 >= ts->info->stack_limit
9655 && arg1 <= ts->info->start_stack) {
9656 arg3 &= ~PROT_GROWSDOWN;
9657 arg2 = arg2 + arg1 - ts->info->stack_limit;
9658 arg1 = ts->info->stack_limit;
9659 }
9660 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009661 return get_errno(target_mprotect(arg1, arg2, arg3));
thse5febef2007-04-01 18:31:35 +00009662#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009663 case TARGET_NR_mremap:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009664 return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
thse5febef2007-04-01 18:31:35 +00009665#endif
pbrook53a59602006-03-25 19:31:22 +00009666 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009667#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009668 case TARGET_NR_msync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009669 return get_errno(msync(g2h(arg1), arg2, arg3));
thse5febef2007-04-01 18:31:35 +00009670#endif
9671#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009672 case TARGET_NR_mlock:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009673 return get_errno(mlock(g2h(arg1), arg2));
thse5febef2007-04-01 18:31:35 +00009674#endif
9675#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009676 case TARGET_NR_munlock:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009677 return get_errno(munlock(g2h(arg1), arg2));
thse5febef2007-04-01 18:31:35 +00009678#endif
9679#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009680 case TARGET_NR_mlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009681 return get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
thse5febef2007-04-01 18:31:35 +00009682#endif
9683#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009684 case TARGET_NR_munlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009685 return get_errno(munlockall());
thse5febef2007-04-01 18:31:35 +00009686#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009687#ifdef TARGET_NR_truncate
bellard31e31b82003-02-18 22:55:36 +00009688 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009689 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009690 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009691 ret = get_errno(truncate(p, arg2));
9692 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009693 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009694#endif
9695#ifdef TARGET_NR_ftruncate
bellard31e31b82003-02-18 22:55:36 +00009696 case TARGET_NR_ftruncate:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009697 return get_errno(ftruncate(arg1, arg2));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009698#endif
bellard31e31b82003-02-18 22:55:36 +00009699 case TARGET_NR_fchmod:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009700 return get_errno(fchmod(arg1, arg2));
Peter Maydellc0d472b2013-06-12 16:20:21 +01009701#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009702 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009703 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009704 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009705 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009706 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009707 return ret;
ths814d7972007-09-24 09:26:51 +00009708#endif
bellard31e31b82003-02-18 22:55:36 +00009709 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009710 /* Note that negative values are valid for getpriority, so we must
9711 differentiate based on errno settings. */
9712 errno = 0;
9713 ret = getpriority(arg1, arg2);
9714 if (ret == -1 && errno != 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009715 return -host_to_target_errno(errno);
Richard Henderson95c09822012-06-07 15:14:50 -07009716 }
9717#ifdef TARGET_ALPHA
9718 /* Return value is the unbiased priority. Signal no error. */
9719 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9720#else
9721 /* Return value is a biased priority to avoid negative numbers. */
9722 ret = 20 - ret;
9723#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009724 return ret;
bellard31e31b82003-02-18 22:55:36 +00009725 case TARGET_NR_setpriority:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009726 return get_errno(setpriority(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009727#ifdef TARGET_NR_statfs
bellard31e31b82003-02-18 22:55:36 +00009728 case TARGET_NR_statfs:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009729 if (!(p = lock_user_string(arg1))) {
9730 return -TARGET_EFAULT;
9731 }
pbrook53a59602006-03-25 19:31:22 +00009732 ret = get_errno(statfs(path(p), &stfs));
9733 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009734 convert_statfs:
9735 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009736 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009737
bellard579a97f2007-11-11 14:26:47 +00009738 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009739 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009740 __put_user(stfs.f_type, &target_stfs->f_type);
9741 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9742 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9743 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9744 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9745 __put_user(stfs.f_files, &target_stfs->f_files);
9746 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9747 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9748 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9749 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009750 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05009751#ifdef _STATFS_F_FLAGS
9752 __put_user(stfs.f_flags, &target_stfs->f_flags);
9753#else
9754 __put_user(0, &target_stfs->f_flags);
9755#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009756 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009757 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009758 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009759 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009760#endif
9761#ifdef TARGET_NR_fstatfs
bellard31e31b82003-02-18 22:55:36 +00009762 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009763 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009764 goto convert_statfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009765#endif
bellard56c8f682005-11-28 22:28:41 +00009766#ifdef TARGET_NR_statfs64
9767 case TARGET_NR_statfs64:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009768 if (!(p = lock_user_string(arg1))) {
9769 return -TARGET_EFAULT;
9770 }
pbrook53a59602006-03-25 19:31:22 +00009771 ret = get_errno(statfs(path(p), &stfs));
9772 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009773 convert_statfs64:
9774 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009775 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009776
bellard579a97f2007-11-11 14:26:47 +00009777 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009778 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009779 __put_user(stfs.f_type, &target_stfs->f_type);
9780 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9781 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9782 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9783 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9784 __put_user(stfs.f_files, &target_stfs->f_files);
9785 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9786 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9787 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9788 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009789 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Frajob94e2b42020-01-30 15:00:30 +02009790#ifdef _STATFS_F_FLAGS
9791 __put_user(stfs.f_flags, &target_stfs->f_flags);
9792#else
9793 __put_user(0, &target_stfs->f_flags);
9794#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009795 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009796 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009797 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009798 return ret;
bellard56c8f682005-11-28 22:28:41 +00009799 case TARGET_NR_fstatfs64:
9800 ret = get_errno(fstatfs(arg1, &stfs));
9801 goto convert_statfs64;
9802#endif
thse5febef2007-04-01 18:31:35 +00009803#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009804 case TARGET_NR_socketcall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009805 return do_socketcall(arg1, arg2);
thse5febef2007-04-01 18:31:35 +00009806#endif
bellard3532fa72006-06-24 15:06:03 +00009807#ifdef TARGET_NR_accept
9808 case TARGET_NR_accept:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009809 return do_accept4(arg1, arg2, arg3, 0);
Peter Maydella94b4982013-02-08 04:35:04 +00009810#endif
9811#ifdef TARGET_NR_accept4
9812 case TARGET_NR_accept4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009813 return do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009814#endif
9815#ifdef TARGET_NR_bind
9816 case TARGET_NR_bind:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009817 return do_bind(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009818#endif
9819#ifdef TARGET_NR_connect
9820 case TARGET_NR_connect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009821 return do_connect(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009822#endif
9823#ifdef TARGET_NR_getpeername
9824 case TARGET_NR_getpeername:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009825 return do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009826#endif
9827#ifdef TARGET_NR_getsockname
9828 case TARGET_NR_getsockname:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009829 return do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009830#endif
9831#ifdef TARGET_NR_getsockopt
9832 case TARGET_NR_getsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009833 return do_getsockopt(arg1, arg2, arg3, arg4, arg5);
bellard3532fa72006-06-24 15:06:03 +00009834#endif
9835#ifdef TARGET_NR_listen
9836 case TARGET_NR_listen:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009837 return get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009838#endif
9839#ifdef TARGET_NR_recv
9840 case TARGET_NR_recv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009841 return do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009842#endif
9843#ifdef TARGET_NR_recvfrom
9844 case TARGET_NR_recvfrom:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009845 return do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009846#endif
9847#ifdef TARGET_NR_recvmsg
9848 case TARGET_NR_recvmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009849 return do_sendrecvmsg(arg1, arg2, arg3, 0);
bellard3532fa72006-06-24 15:06:03 +00009850#endif
9851#ifdef TARGET_NR_send
9852 case TARGET_NR_send:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009853 return do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009854#endif
9855#ifdef TARGET_NR_sendmsg
9856 case TARGET_NR_sendmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009857 return do_sendrecvmsg(arg1, arg2, arg3, 1);
bellard3532fa72006-06-24 15:06:03 +00009858#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009859#ifdef TARGET_NR_sendmmsg
9860 case TARGET_NR_sendmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009861 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
Alistair Francis859e8a82020-03-12 15:13:49 -07009862#endif
9863#ifdef TARGET_NR_recvmmsg
Alexander Graff19e00d2014-03-02 19:36:42 +00009864 case TARGET_NR_recvmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009865 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
Alexander Graff19e00d2014-03-02 19:36:42 +00009866#endif
bellard3532fa72006-06-24 15:06:03 +00009867#ifdef TARGET_NR_sendto
9868 case TARGET_NR_sendto:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009869 return do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009870#endif
9871#ifdef TARGET_NR_shutdown
9872 case TARGET_NR_shutdown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009873 return get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009874#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009875#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9876 case TARGET_NR_getrandom:
9877 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9878 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009879 return -TARGET_EFAULT;
Laurent Vivierf894efd2016-02-21 10:56:23 +01009880 }
9881 ret = get_errno(getrandom(p, arg2, arg3));
9882 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009883 return ret;
Laurent Vivierf894efd2016-02-21 10:56:23 +01009884#endif
bellard3532fa72006-06-24 15:06:03 +00009885#ifdef TARGET_NR_socket
9886 case TARGET_NR_socket:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009887 return do_socket(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009888#endif
9889#ifdef TARGET_NR_socketpair
9890 case TARGET_NR_socketpair:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009891 return do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009892#endif
9893#ifdef TARGET_NR_setsockopt
9894 case TARGET_NR_setsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009895 return do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
bellard3532fa72006-06-24 15:06:03 +00009896#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009897#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009898 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009899 {
9900 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009901
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009902 switch (arg1) {
9903 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9904 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9905 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9906 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9907 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9908 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9909 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9910 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009911 return get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009912 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9913 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9914 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9915 {
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009916 if (len < 0) {
Richard Henderson259841c2018-08-18 12:01:09 -07009917 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009918 }
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009919 if (len == 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009920 return 0;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009921 }
9922 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9923 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -07009924 return -TARGET_EFAULT;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009925 }
9926 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9927 unlock_user(p, arg2, arg3);
9928 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009929 return ret;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009930 default:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009931 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009932 }
9933 }
9934 break;
9935#endif
bellard31e31b82003-02-18 22:55:36 +00009936 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009937 {
bellard66fb9762003-03-23 01:06:05 +00009938 struct itimerval value, ovalue, *pvalue;
9939
pbrook53a59602006-03-25 19:31:22 +00009940 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009941 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009942 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9943 || copy_from_user_timeval(&pvalue->it_value,
9944 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009945 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00009946 } else {
9947 pvalue = NULL;
9948 }
9949 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009950 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009951 if (copy_to_user_timeval(arg3,
9952 &ovalue.it_interval)
9953 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9954 &ovalue.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009955 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00009956 }
9957 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009958 return ret;
bellard31e31b82003-02-18 22:55:36 +00009959 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009960 {
bellard66fb9762003-03-23 01:06:05 +00009961 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009962
bellard66fb9762003-03-23 01:06:05 +00009963 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009964 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009965 if (copy_to_user_timeval(arg2,
9966 &value.it_interval)
9967 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9968 &value.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009969 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +00009970 }
9971 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009972 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009973#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009974 case TARGET_NR_stat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009975 if (!(p = lock_user_string(arg1))) {
9976 return -TARGET_EFAULT;
9977 }
pbrook53a59602006-03-25 19:31:22 +00009978 ret = get_errno(stat(path(p), &st));
9979 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009980 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009981#endif
9982#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009983 case TARGET_NR_lstat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009984 if (!(p = lock_user_string(arg1))) {
9985 return -TARGET_EFAULT;
9986 }
pbrook53a59602006-03-25 19:31:22 +00009987 ret = get_errno(lstat(path(p), &st));
9988 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009989 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009990#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009991#ifdef TARGET_NR_fstat
bellard31e31b82003-02-18 22:55:36 +00009992 case TARGET_NR_fstat:
9993 {
9994 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009995#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009996 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009997#endif
bellard31e31b82003-02-18 22:55:36 +00009998 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009999 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +000010000
bellard579a97f2007-11-11 14:26:47 +000010001 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010002 return -TARGET_EFAULT;
Ulrich Hecht12727912009-07-24 19:10:32 +020010003 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +000010004 __put_user(st.st_dev, &target_st->st_dev);
10005 __put_user(st.st_ino, &target_st->st_ino);
10006 __put_user(st.st_mode, &target_st->st_mode);
10007 __put_user(st.st_uid, &target_st->st_uid);
10008 __put_user(st.st_gid, &target_st->st_gid);
10009 __put_user(st.st_nlink, &target_st->st_nlink);
10010 __put_user(st.st_rdev, &target_st->st_rdev);
10011 __put_user(st.st_size, &target_st->st_size);
10012 __put_user(st.st_blksize, &target_st->st_blksize);
10013 __put_user(st.st_blocks, &target_st->st_blocks);
10014 __put_user(st.st_atime, &target_st->target_st_atime);
10015 __put_user(st.st_mtime, &target_st->target_st_mtime);
10016 __put_user(st.st_ctime, &target_st->target_st_ctime);
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +080010017#if (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) && \
10018 defined(TARGET_STAT_HAVE_NSEC)
10019 __put_user(st.st_atim.tv_nsec,
10020 &target_st->target_st_atime_nsec);
10021 __put_user(st.st_mtim.tv_nsec,
10022 &target_st->target_st_mtime_nsec);
10023 __put_user(st.st_ctim.tv_nsec,
10024 &target_st->target_st_ctime_nsec);
10025#endif
pbrook53a59602006-03-25 19:31:22 +000010026 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +000010027 }
10028 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010029 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010030#endif
bellard31e31b82003-02-18 22:55:36 +000010031 case TARGET_NR_vhangup:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010032 return get_errno(vhangup());
bellard42ad6ae2005-01-03 22:48:11 +000010033#ifdef TARGET_NR_syscall
10034 case TARGET_NR_syscall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010035 return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
10036 arg6, arg7, arg8, 0);
bellard42ad6ae2005-01-03 22:48:11 +000010037#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070010038#if defined(TARGET_NR_wait4)
bellard31e31b82003-02-18 22:55:36 +000010039 case TARGET_NR_wait4:
10040 {
10041 int status;
blueswir1992f48a2007-10-14 16:27:31 +000010042 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +000010043 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +000010044 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +020010045 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +000010046 if (target_rusage)
10047 rusage_ptr = &rusage;
10048 else
10049 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +010010050 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +000010051 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +010010052 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +000010053 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +000010054 if (put_user_s32(status, status_ptr))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010055 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +000010056 }
Petar Jovanovica39fb272014-04-08 19:24:30 +020010057 if (target_rusage) {
10058 rusage_err = host_to_target_rusage(target_rusage, &rusage);
10059 if (rusage_err) {
10060 ret = rusage_err;
10061 }
10062 }
bellard31e31b82003-02-18 22:55:36 +000010063 }
10064 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010065 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010066#endif
thse5febef2007-04-01 18:31:35 +000010067#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +000010068 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +000010069 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010070 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010071 ret = get_errno(swapoff(p));
10072 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010073 return ret;
thse5febef2007-04-01 18:31:35 +000010074#endif
bellard31e31b82003-02-18 22:55:36 +000010075 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +000010076 {
pbrook53a59602006-03-25 19:31:22 +000010077 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +000010078 struct sysinfo value;
10079 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +000010080 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +000010081 {
bellard579a97f2007-11-11 14:26:47 +000010082 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010083 return -TARGET_EFAULT;
bellarda5448a72004-06-19 16:59:03 +000010084 __put_user(value.uptime, &target_value->uptime);
10085 __put_user(value.loads[0], &target_value->loads[0]);
10086 __put_user(value.loads[1], &target_value->loads[1]);
10087 __put_user(value.loads[2], &target_value->loads[2]);
10088 __put_user(value.totalram, &target_value->totalram);
10089 __put_user(value.freeram, &target_value->freeram);
10090 __put_user(value.sharedram, &target_value->sharedram);
10091 __put_user(value.bufferram, &target_value->bufferram);
10092 __put_user(value.totalswap, &target_value->totalswap);
10093 __put_user(value.freeswap, &target_value->freeswap);
10094 __put_user(value.procs, &target_value->procs);
10095 __put_user(value.totalhigh, &target_value->totalhigh);
10096 __put_user(value.freehigh, &target_value->freehigh);
10097 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +000010098 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +000010099 }
10100 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010101 return ret;
thse5febef2007-04-01 18:31:35 +000010102#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +000010103 case TARGET_NR_ipc:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010104 return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
thse5febef2007-04-01 18:31:35 +000010105#endif
aurel32e5289082009-04-18 16:16:12 +000010106#ifdef TARGET_NR_semget
10107 case TARGET_NR_semget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010108 return get_errno(semget(arg1, arg2, arg3));
aurel32e5289082009-04-18 16:16:12 +000010109#endif
10110#ifdef TARGET_NR_semop
10111 case TARGET_NR_semop:
Filip Bozutacac46eb2020-08-25 00:30:50 +020010112 return do_semtimedop(arg1, arg2, arg3, 0, false);
Matus Kyseld8c08b12020-06-26 14:46:11 +020010113#endif
10114#ifdef TARGET_NR_semtimedop
10115 case TARGET_NR_semtimedop:
Filip Bozutacac46eb2020-08-25 00:30:50 +020010116 return do_semtimedop(arg1, arg2, arg3, arg4, false);
10117#endif
10118#ifdef TARGET_NR_semtimedop_time64
10119 case TARGET_NR_semtimedop_time64:
10120 return do_semtimedop(arg1, arg2, arg3, arg4, true);
aurel32e5289082009-04-18 16:16:12 +000010121#endif
10122#ifdef TARGET_NR_semctl
10123 case TARGET_NR_semctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010124 return do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +000010125#endif
aurel32eeb438c2008-10-13 21:08:55 +000010126#ifdef TARGET_NR_msgctl
10127 case TARGET_NR_msgctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010128 return do_msgctl(arg1, arg2, arg3);
aurel32eeb438c2008-10-13 21:08:55 +000010129#endif
10130#ifdef TARGET_NR_msgget
10131 case TARGET_NR_msgget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010132 return get_errno(msgget(arg1, arg2));
aurel32eeb438c2008-10-13 21:08:55 +000010133#endif
10134#ifdef TARGET_NR_msgrcv
10135 case TARGET_NR_msgrcv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010136 return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
aurel32eeb438c2008-10-13 21:08:55 +000010137#endif
10138#ifdef TARGET_NR_msgsnd
10139 case TARGET_NR_msgsnd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010140 return do_msgsnd(arg1, arg2, arg3, arg4);
aurel32eeb438c2008-10-13 21:08:55 +000010141#endif
Riku Voipio88a8c982009-04-03 10:42:00 +030010142#ifdef TARGET_NR_shmget
10143 case TARGET_NR_shmget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010144 return get_errno(shmget(arg1, arg2, arg3));
Riku Voipio88a8c982009-04-03 10:42:00 +030010145#endif
10146#ifdef TARGET_NR_shmctl
10147 case TARGET_NR_shmctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010148 return do_shmctl(arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030010149#endif
10150#ifdef TARGET_NR_shmat
10151 case TARGET_NR_shmat:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010152 return do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030010153#endif
10154#ifdef TARGET_NR_shmdt
10155 case TARGET_NR_shmdt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010156 return do_shmdt(arg1);
Riku Voipio88a8c982009-04-03 10:42:00 +030010157#endif
bellard31e31b82003-02-18 22:55:36 +000010158 case TARGET_NR_fsync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010159 return get_errno(fsync(arg1));
bellard31e31b82003-02-18 22:55:36 +000010160 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +010010161 /* Linux manages to have three different orderings for its
10162 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
10163 * match the kernel's CONFIG_CLONE_* settings.
10164 * Microblaze is further special in that it uses a sixth
10165 * implicit argument to clone for the TLS pointer.
10166 */
10167#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020010168 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010010169#elif defined(TARGET_CLONE_BACKWARDS)
10170 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
10171#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010172 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010173#else
Peter Maydell4ce62432013-07-16 18:44:57 +010010174 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010175#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010176 return ret;
bellardec86b0f2003-04-11 00:15:04 +000010177#ifdef __NR_exit_group
10178 /* new thread calls */
10179 case TARGET_NR_exit_group:
Alex Bennée708b6a62018-06-22 17:09:10 +010010180 preexit_cleanup(cpu_env, arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010181 return get_errno(exit_group(arg1));
bellardec86b0f2003-04-11 00:15:04 +000010182#endif
bellard31e31b82003-02-18 22:55:36 +000010183 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000010184 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010185 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010186 ret = get_errno(setdomainname(p, arg2));
10187 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010188 return ret;
bellard31e31b82003-02-18 22:55:36 +000010189 case TARGET_NR_uname:
10190 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000010191 {
10192 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000010193
bellard579a97f2007-11-11 14:26:47 +000010194 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010195 return -TARGET_EFAULT;
bellard29e619b2004-09-13 21:41:04 +000010196 ret = get_errno(sys_uname(buf));
10197 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010010198 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000010199 emulated. */
Philippe Mathieu-Daudé871f95c2017-07-24 15:27:47 -030010200 g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
10201 sizeof(buf->machine));
pbrookc5937222006-05-14 11:30:38 +000010202 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010010203 if (qemu_uname_release && *qemu_uname_release) {
10204 g_strlcpy(buf->release, qemu_uname_release,
10205 sizeof(buf->release));
10206 }
bellard29e619b2004-09-13 21:41:04 +000010207 }
pbrook53a59602006-03-25 19:31:22 +000010208 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000010209 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010210 return ret;
bellard6dbad632003-03-16 18:05:05 +000010211#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000010212 case TARGET_NR_modify_ldt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010213 return do_modify_ldt(cpu_env, arg1, arg2, arg3);
j_mayer84409dd2007-04-06 08:56:50 +000010214#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000010215 case TARGET_NR_vm86:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010216 return do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000010217#endif
j_mayer84409dd2007-04-06 08:56:50 +000010218#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070010219#if defined(TARGET_NR_adjtimex)
bellard31e31b82003-02-18 22:55:36 +000010220 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010221 {
10222 struct timex host_buf;
10223
10224 if (target_to_host_timex(&host_buf, arg1) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010225 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010226 }
10227 ret = get_errno(adjtimex(&host_buf));
10228 if (!is_error(ret)) {
10229 if (host_to_target_timex(arg1, &host_buf) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010230 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010231 }
10232 }
10233 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010234 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010235#endif
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010236#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10237 case TARGET_NR_clock_adjtime:
10238 {
10239 struct timex htx, *phtx = &htx;
10240
10241 if (target_to_host_timex(phtx, arg2) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010242 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010243 }
10244 ret = get_errno(clock_adjtime(arg1, phtx));
10245 if (!is_error(ret) && phtx) {
10246 if (host_to_target_timex(arg2, phtx) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010247 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010248 }
10249 }
10250 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010251 return ret;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010252#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +020010253#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
10254 case TARGET_NR_clock_adjtime64:
10255 {
10256 struct timex htx;
10257
10258 if (target_to_host_timex64(&htx, arg2) != 0) {
10259 return -TARGET_EFAULT;
10260 }
10261 ret = get_errno(clock_adjtime(arg1, &htx));
10262 if (!is_error(ret) && host_to_target_timex64(arg2, &htx)) {
10263 return -TARGET_EFAULT;
10264 }
10265 }
10266 return ret;
10267#endif
bellard31e31b82003-02-18 22:55:36 +000010268 case TARGET_NR_getpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010269 return get_errno(getpgid(arg1));
bellard31e31b82003-02-18 22:55:36 +000010270 case TARGET_NR_fchdir:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010271 return get_errno(fchdir(arg1));
bellard31e31b82003-02-18 22:55:36 +000010272 case TARGET_NR_personality:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010273 return get_errno(personality(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000010274#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010275 case TARGET_NR__llseek:
10276 {
10277 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010278#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010279 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010280 if (res == -1) {
10281 ret = get_errno(res);
10282 } else {
10283 ret = 0;
10284 }
10285#else
bellard31e31b82003-02-18 22:55:36 +000010286 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010287#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010288 if ((ret == 0) && put_user_s64(res, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010289 return -TARGET_EFAULT;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010290 }
bellard31e31b82003-02-18 22:55:36 +000010291 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010292 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +000010293#endif
Chen Gang704eff62015-08-21 05:37:33 +080010294#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010295 case TARGET_NR_getdents:
Peter Maydell2b3f64c2018-04-19 13:57:40 +010010296#ifdef EMULATE_GETDENTS_WITH_GETDENTS
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010297#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010298 {
pbrook53a59602006-03-25 19:31:22 +000010299 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010300 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010301 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010302
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010303 dirp = g_try_malloc(count);
10304 if (!dirp) {
Richard Henderson259841c2018-08-18 12:01:09 -070010305 return -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010306 }
ths3b46e622007-09-17 08:09:54 +000010307
bellard4add45b2003-06-05 01:52:59 +000010308 ret = get_errno(sys_getdents(arg1, dirp, count));
10309 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010310 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010311 struct target_dirent *tde;
10312 int len = ret;
10313 int reclen, treclen;
10314 int count1, tnamelen;
10315
10316 count1 = 0;
10317 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010318 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010319 return -TARGET_EFAULT;
bellard4add45b2003-06-05 01:52:59 +000010320 tde = target_dirp;
10321 while (len > 0) {
10322 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010323 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10324 assert(tnamelen >= 0);
10325 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10326 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010327 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010328 tde->d_ino = tswapal(de->d_ino);
10329 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010330 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010331 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010332 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010333 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010334 count1 += treclen;
10335 }
10336 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010337 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010338 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010339 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010340 }
10341#else
bellard31e31b82003-02-18 22:55:36 +000010342 {
aurel326556a832008-10-13 21:08:17 +000010343 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010344 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010345
bellard579a97f2007-11-11 14:26:47 +000010346 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010347 return -TARGET_EFAULT;
bellard72f03902003-02-18 23:33:18 +000010348 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010349 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010350 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010351 int len = ret;
10352 int reclen;
10353 de = dirp;
10354 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010355 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010356 if (reclen > len)
10357 break;
bellard8083a3e2003-03-24 23:12:16 +000010358 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010359 tswapls(&de->d_ino);
10360 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010361 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010362 len -= reclen;
10363 }
10364 }
pbrook53a59602006-03-25 19:31:22 +000010365 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010366 }
bellard4add45b2003-06-05 01:52:59 +000010367#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010368#else
10369 /* Implement getdents in terms of getdents64 */
10370 {
10371 struct linux_dirent64 *dirp;
10372 abi_long count = arg3;
10373
10374 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10375 if (!dirp) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010376 return -TARGET_EFAULT;
Peter Maydell3307e232013-06-12 16:20:21 +010010377 }
10378 ret = get_errno(sys_getdents64(arg1, dirp, count));
10379 if (!is_error(ret)) {
10380 /* Convert the dirent64 structs to target dirent. We do this
10381 * in-place, since we can guarantee that a target_dirent is no
10382 * larger than a dirent64; however this means we have to be
10383 * careful to read everything before writing in the new format.
10384 */
10385 struct linux_dirent64 *de;
10386 struct target_dirent *tde;
10387 int len = ret;
10388 int tlen = 0;
10389
10390 de = dirp;
10391 tde = (struct target_dirent *)dirp;
10392 while (len > 0) {
10393 int namelen, treclen;
10394 int reclen = de->d_reclen;
10395 uint64_t ino = de->d_ino;
10396 int64_t off = de->d_off;
10397 uint8_t type = de->d_type;
10398
10399 namelen = strlen(de->d_name);
10400 treclen = offsetof(struct target_dirent, d_name)
10401 + namelen + 2;
10402 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10403
10404 memmove(tde->d_name, de->d_name, namelen + 1);
10405 tde->d_ino = tswapal(ino);
10406 tde->d_off = tswapal(off);
10407 tde->d_reclen = tswap16(treclen);
10408 /* The target_dirent type is in what was formerly a padding
10409 * byte at the end of the structure:
10410 */
10411 *(((char *)tde) + treclen - 1) = type;
10412
10413 de = (struct linux_dirent64 *)((char *)de + reclen);
10414 tde = (struct target_dirent *)((char *)tde + treclen);
10415 len -= reclen;
10416 tlen += treclen;
10417 }
10418 ret = tlen;
10419 }
10420 unlock_user(dirp, arg2, ret);
10421 }
10422#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010423 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010424#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010425#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010426 case TARGET_NR_getdents64:
10427 {
aurel326556a832008-10-13 21:08:17 +000010428 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010429 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010430 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010431 return -TARGET_EFAULT;
bellarddab2ed92003-03-22 15:23:14 +000010432 ret = get_errno(sys_getdents64(arg1, dirp, count));
10433 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010434 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010435 int len = ret;
10436 int reclen;
10437 de = dirp;
10438 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010439 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010440 if (reclen > len)
10441 break;
bellard8083a3e2003-03-24 23:12:16 +000010442 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010443 tswap64s((uint64_t *)&de->d_ino);
10444 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010445 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010446 len -= reclen;
10447 }
10448 }
pbrook53a59602006-03-25 19:31:22 +000010449 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010450 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010451 return ret;
bellarda541f292004-04-12 20:39:29 +000010452#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010453#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010454 case TARGET_NR__newselect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010455 return do_select(arg1, arg2, arg3, arg4, arg5);
thse5febef2007-04-01 18:31:35 +000010456#endif
Filip Bozutae5ce9682020-08-25 00:30:49 +020010457#ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010458 case TARGET_NR_poll:
Filip Bozutae5ce9682020-08-25 00:30:49 +020010459 return do_ppoll(arg1, arg2, arg3, arg4, arg5, false, false);
10460#endif
10461#ifdef TARGET_NR_ppoll
Mike Frysingerd8035d42011-02-07 01:05:51 -050010462 case TARGET_NR_ppoll:
Filip Bozutae5ce9682020-08-25 00:30:49 +020010463 return do_ppoll(arg1, arg2, arg3, arg4, arg5, true, false);
10464#endif
10465#ifdef TARGET_NR_ppoll_time64
10466 case TARGET_NR_ppoll_time64:
10467 return do_ppoll(arg1, arg2, arg3, arg4, arg5, true, true);
thse5febef2007-04-01 18:31:35 +000010468#endif
bellard31e31b82003-02-18 22:55:36 +000010469 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010470 /* NOTE: the flock constant seems to be the same for every
10471 Linux platform */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010472 return get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010473 case TARGET_NR_readv:
10474 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010475 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10476 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010477 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010478 unlock_iovec(vec, arg2, arg3, 1);
10479 } else {
10480 ret = -host_to_target_errno(errno);
10481 }
bellard31e31b82003-02-18 22:55:36 +000010482 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010483 return ret;
bellard31e31b82003-02-18 22:55:36 +000010484 case TARGET_NR_writev:
10485 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010486 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10487 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010488 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010489 unlock_iovec(vec, arg2, arg3, 0);
10490 } else {
10491 ret = -host_to_target_errno(errno);
10492 }
bellard31e31b82003-02-18 22:55:36 +000010493 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010494 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010495#if defined(TARGET_NR_preadv)
10496 case TARGET_NR_preadv:
10497 {
10498 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10499 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010500 unsigned long low, high;
10501
10502 target_to_host_low_high(arg4, arg5, &low, &high);
10503 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010504 unlock_iovec(vec, arg2, arg3, 1);
10505 } else {
10506 ret = -host_to_target_errno(errno);
10507 }
10508 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010509 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010510#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010511#if defined(TARGET_NR_pwritev)
10512 case TARGET_NR_pwritev:
10513 {
10514 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10515 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010516 unsigned long low, high;
10517
10518 target_to_host_low_high(arg4, arg5, &low, &high);
10519 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010520 unlock_iovec(vec, arg2, arg3, 0);
10521 } else {
10522 ret = -host_to_target_errno(errno);
10523 }
10524 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010525 return ret;
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010526#endif
bellard31e31b82003-02-18 22:55:36 +000010527 case TARGET_NR_getsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010528 return get_errno(getsid(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000010529#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010530 case TARGET_NR_fdatasync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010531 return get_errno(fdatasync(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000010532#endif
Chen Gang704eff62015-08-21 05:37:33 +080010533#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010534 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010535 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010536 return value. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010537 return -TARGET_ENOTDIR;
Chen Gang704eff62015-08-21 05:37:33 +080010538#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010539 case TARGET_NR_sched_getaffinity:
10540 {
10541 unsigned int mask_size;
10542 unsigned long *mask;
10543
10544 /*
10545 * sched_getaffinity needs multiples of ulong, so need to take
10546 * care of mismatches between target ulong and host ulong sizes.
10547 */
10548 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010549 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010550 }
10551 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10552
10553 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010554 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010555 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10556
10557 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010558 if (ret > arg2) {
10559 /* More data returned than the caller's buffer will fit.
10560 * This only happens if sizeof(abi_long) < sizeof(long)
10561 * and the caller passed us a buffer holding an odd number
10562 * of abi_longs. If the host kernel is actually using the
10563 * extra 4 bytes then fail EINVAL; otherwise we can just
10564 * ignore them and only copy the interesting part.
10565 */
10566 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10567 if (numcpus > arg2 * 8) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010568 return -TARGET_EINVAL;
Peter Maydellbe3bd282014-05-15 14:40:23 +010010569 }
10570 ret = arg2;
10571 }
10572
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010573 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010574 return -TARGET_EFAULT;
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010575 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010576 }
10577 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010578 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010579 case TARGET_NR_sched_setaffinity:
10580 {
10581 unsigned int mask_size;
10582 unsigned long *mask;
10583
10584 /*
10585 * sched_setaffinity needs multiples of ulong, so need to take
10586 * care of mismatches between target ulong and host ulong sizes.
10587 */
10588 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010589 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010590 }
10591 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010592 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010593
10594 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10595 if (ret) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010596 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010597 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010598
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010599 return get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
Mike Frysinger737de1d2011-02-07 01:05:55 -050010600 }
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010601 case TARGET_NR_getcpu:
10602 {
10603 unsigned cpu, node;
10604 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
10605 arg2 ? &node : NULL,
10606 NULL));
10607 if (is_error(ret)) {
Richard Henderson259841c2018-08-18 12:01:09 -070010608 return ret;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010609 }
10610 if (arg1 && put_user_u32(cpu, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010611 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010612 }
10613 if (arg2 && put_user_u32(node, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010614 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010615 }
10616 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010617 return ret;
bellard31e31b82003-02-18 22:55:36 +000010618 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010619 {
pbrook53a59602006-03-25 19:31:22 +000010620 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010621 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010622
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010623 if (arg2 == 0) {
10624 return -TARGET_EINVAL;
10625 }
bellard579a97f2007-11-11 14:26:47 +000010626 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010627 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +000010628 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010629 unlock_user_struct(target_schp, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010630 return get_errno(sched_setparam(arg1, &schp));
bellard5cd43932003-03-29 16:54:36 +000010631 }
bellard31e31b82003-02-18 22:55:36 +000010632 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010633 {
pbrook53a59602006-03-25 19:31:22 +000010634 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010635 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010636
10637 if (arg2 == 0) {
10638 return -TARGET_EINVAL;
10639 }
bellard5cd43932003-03-29 16:54:36 +000010640 ret = get_errno(sched_getparam(arg1, &schp));
10641 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010642 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010643 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +000010644 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010645 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010646 }
10647 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010648 return ret;
bellard31e31b82003-02-18 22:55:36 +000010649 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010650 {
pbrook53a59602006-03-25 19:31:22 +000010651 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010652 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010653 if (arg3 == 0) {
10654 return -TARGET_EINVAL;
10655 }
bellard579a97f2007-11-11 14:26:47 +000010656 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010657 return -TARGET_EFAULT;
bellard5cd43932003-03-29 16:54:36 +000010658 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010659 unlock_user_struct(target_schp, arg3, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010660 return get_errno(sched_setscheduler(arg1, arg2, &schp));
bellard5cd43932003-03-29 16:54:36 +000010661 }
bellard31e31b82003-02-18 22:55:36 +000010662 case TARGET_NR_sched_getscheduler:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010663 return get_errno(sched_getscheduler(arg1));
bellard31e31b82003-02-18 22:55:36 +000010664 case TARGET_NR_sched_yield:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010665 return get_errno(sched_yield());
bellard31e31b82003-02-18 22:55:36 +000010666 case TARGET_NR_sched_get_priority_max:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010667 return get_errno(sched_get_priority_max(arg1));
bellard31e31b82003-02-18 22:55:36 +000010668 case TARGET_NR_sched_get_priority_min:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010669 return get_errno(sched_get_priority_min(arg1));
Alistair Francis859e8a82020-03-12 15:13:49 -070010670#ifdef TARGET_NR_sched_rr_get_interval
bellard31e31b82003-02-18 22:55:36 +000010671 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010672 {
bellard5cd43932003-03-29 16:54:36 +000010673 struct timespec ts;
10674 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10675 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010676 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010677 }
10678 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010679 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010680#endif
Filip Bozutaddcbde12020-08-24 21:21:16 +020010681#ifdef TARGET_NR_sched_rr_get_interval_time64
10682 case TARGET_NR_sched_rr_get_interval_time64:
10683 {
10684 struct timespec ts;
10685 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10686 if (!is_error(ret)) {
10687 ret = host_to_target_timespec64(arg2, &ts);
10688 }
10689 }
10690 return ret;
10691#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070010692#if defined(TARGET_NR_nanosleep)
bellard31e31b82003-02-18 22:55:36 +000010693 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010694 {
bellard1b6b0292003-03-22 17:31:38 +000010695 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010696 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010697 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010698 if (is_error(ret) && arg2) {
10699 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010700 }
10701 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010702 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010703#endif
bellard31e31b82003-02-18 22:55:36 +000010704 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010705 switch (arg1) {
10706 case PR_GET_PDEATHSIG:
10707 {
10708 int deathsig;
10709 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10710 if (!is_error(ret) && arg2
Stephen Longd9a5eba2020-05-07 06:03:02 -070010711 && put_user_s32(deathsig, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010712 return -TARGET_EFAULT;
thse5574482007-02-11 20:03:13 +000010713 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010714 return ret;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010715 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010716#ifdef PR_GET_NAME
10717 case PR_GET_NAME:
10718 {
10719 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10720 if (!name) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010721 return -TARGET_EFAULT;
Peter Maydelldb9526b2012-02-03 14:48:03 +000010722 }
10723 ret = get_errno(prctl(arg1, (unsigned long)name,
10724 arg3, arg4, arg5));
10725 unlock_user(name, arg2, 16);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010726 return ret;
Peter Maydelldb9526b2012-02-03 14:48:03 +000010727 }
10728 case PR_SET_NAME:
10729 {
10730 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10731 if (!name) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010732 return -TARGET_EFAULT;
Peter Maydelldb9526b2012-02-03 14:48:03 +000010733 }
10734 ret = get_errno(prctl(arg1, (unsigned long)name,
10735 arg3, arg4, arg5));
10736 unlock_user(name, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010737 return ret;
Peter Maydelldb9526b2012-02-03 14:48:03 +000010738 }
10739#endif
Stefan Markovic5b702ff2018-10-12 12:57:35 +020010740#ifdef TARGET_MIPS
10741 case TARGET_PR_GET_FP_MODE:
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010742 {
10743 CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
10744 ret = 0;
10745 if (env->CP0_Status & (1 << CP0St_FR)) {
10746 ret |= TARGET_PR_FP_MODE_FR;
10747 }
10748 if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
10749 ret |= TARGET_PR_FP_MODE_FRE;
10750 }
10751 return ret;
10752 }
Stefan Markovic5b702ff2018-10-12 12:57:35 +020010753 case TARGET_PR_SET_FP_MODE:
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010754 {
10755 CPUMIPSState *env = ((CPUMIPSState *)cpu_env);
10756 bool old_fr = env->CP0_Status & (1 << CP0St_FR);
Stefan Markovic6456c512018-11-14 14:37:08 +010010757 bool old_fre = env->CP0_Config5 & (1 << CP0C5_FRE);
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010758 bool new_fr = arg2 & TARGET_PR_FP_MODE_FR;
10759 bool new_fre = arg2 & TARGET_PR_FP_MODE_FRE;
10760
Stefan Markovic6456c512018-11-14 14:37:08 +010010761 const unsigned int known_bits = TARGET_PR_FP_MODE_FR |
10762 TARGET_PR_FP_MODE_FRE;
10763
10764 /* If nothing to change, return right away, successfully. */
10765 if (old_fr == new_fr && old_fre == new_fre) {
10766 return 0;
10767 }
10768 /* Check the value is valid */
10769 if (arg2 & ~known_bits) {
10770 return -TARGET_EOPNOTSUPP;
10771 }
10772 /* Setting FRE without FR is not supported. */
10773 if (new_fre && !new_fr) {
10774 return -TARGET_EOPNOTSUPP;
10775 }
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010776 if (new_fr && !(env->active_fpu.fcr0 & (1 << FCR0_F64))) {
10777 /* FR1 is not supported */
10778 return -TARGET_EOPNOTSUPP;
10779 }
10780 if (!new_fr && (env->active_fpu.fcr0 & (1 << FCR0_F64))
10781 && !(env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
10782 /* cannot set FR=0 */
10783 return -TARGET_EOPNOTSUPP;
10784 }
10785 if (new_fre && !(env->active_fpu.fcr0 & (1 << FCR0_FREP))) {
10786 /* Cannot set FRE=1 */
10787 return -TARGET_EOPNOTSUPP;
10788 }
10789
10790 int i;
10791 fpr_t *fpr = env->active_fpu.fpr;
10792 for (i = 0; i < 32 ; i += 2) {
10793 if (!old_fr && new_fr) {
10794 fpr[i].w[!FP_ENDIAN_IDX] = fpr[i + 1].w[FP_ENDIAN_IDX];
10795 } else if (old_fr && !new_fr) {
10796 fpr[i + 1].w[FP_ENDIAN_IDX] = fpr[i].w[!FP_ENDIAN_IDX];
10797 }
10798 }
10799
10800 if (new_fr) {
10801 env->CP0_Status |= (1 << CP0St_FR);
10802 env->hflags |= MIPS_HFLAG_F64;
10803 } else {
10804 env->CP0_Status &= ~(1 << CP0St_FR);
Stefan Markovic6456c512018-11-14 14:37:08 +010010805 env->hflags &= ~MIPS_HFLAG_F64;
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010806 }
10807 if (new_fre) {
10808 env->CP0_Config5 |= (1 << CP0C5_FRE);
10809 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
10810 env->hflags |= MIPS_HFLAG_FRE;
10811 }
10812 } else {
10813 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
Stefan Markovic6456c512018-11-14 14:37:08 +010010814 env->hflags &= ~MIPS_HFLAG_FRE;
Stefan Markovic64ea3d62018-10-26 13:17:43 +020010815 }
10816
10817 return 0;
10818 }
Stefan Markovic5b702ff2018-10-12 12:57:35 +020010819#endif /* MIPS */
Richard Henderson85fc7162018-03-09 17:09:43 +000010820#ifdef TARGET_AARCH64
10821 case TARGET_PR_SVE_SET_VL:
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010822 /*
10823 * We cannot support either PR_SVE_SET_VL_ONEXEC or
10824 * PR_SVE_VL_INHERIT. Note the kernel definition
10825 * of sve_vl_valid allows for VQ=512, i.e. VL=8192,
10826 * even though the current architectural maximum is VQ=16.
10827 */
Richard Henderson85fc7162018-03-09 17:09:43 +000010828 ret = -TARGET_EINVAL;
Richard Henderson2fc0cc02019-03-22 17:41:14 -070010829 if (cpu_isar_feature(aa64_sve, env_archcpu(cpu_env))
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010830 && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
Richard Henderson85fc7162018-03-09 17:09:43 +000010831 CPUARMState *env = cpu_env;
Richard Henderson2fc0cc02019-03-22 17:41:14 -070010832 ARMCPU *cpu = env_archcpu(env);
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010833 uint32_t vq, old_vq;
10834
10835 old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
10836 vq = MAX(arg2 / 16, 1);
10837 vq = MIN(vq, cpu->sve_max_vq);
Richard Henderson85fc7162018-03-09 17:09:43 +000010838
10839 if (vq < old_vq) {
10840 aarch64_sve_narrow_vq(env, vq);
10841 }
10842 env->vfp.zcr_el[1] = vq - 1;
Richard Hendersona8a79c72019-10-23 11:00:49 -040010843 arm_rebuild_hflags(env);
Richard Henderson85fc7162018-03-09 17:09:43 +000010844 ret = vq * 16;
10845 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010846 return ret;
Richard Henderson85fc7162018-03-09 17:09:43 +000010847 case TARGET_PR_SVE_GET_VL:
10848 ret = -TARGET_EINVAL;
Richard Hendersoncd208a12018-10-24 07:50:17 +010010849 {
Richard Henderson2fc0cc02019-03-22 17:41:14 -070010850 ARMCPU *cpu = env_archcpu(cpu_env);
Richard Hendersoncd208a12018-10-24 07:50:17 +010010851 if (cpu_isar_feature(aa64_sve, cpu)) {
10852 ret = ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
10853 }
Richard Henderson85fc7162018-03-09 17:09:43 +000010854 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010855 return ret;
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010856 case TARGET_PR_PAC_RESET_KEYS:
10857 {
10858 CPUARMState *env = cpu_env;
Richard Henderson2fc0cc02019-03-22 17:41:14 -070010859 ARMCPU *cpu = env_archcpu(env);
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010860
10861 if (arg3 || arg4 || arg5) {
10862 return -TARGET_EINVAL;
10863 }
10864 if (cpu_isar_feature(aa64_pauth, cpu)) {
10865 int all = (TARGET_PR_PAC_APIAKEY | TARGET_PR_PAC_APIBKEY |
10866 TARGET_PR_PAC_APDAKEY | TARGET_PR_PAC_APDBKEY |
10867 TARGET_PR_PAC_APGAKEY);
Richard Henderson51977e22019-03-12 19:22:20 -070010868 int ret = 0;
10869 Error *err = NULL;
10870
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010871 if (arg2 == 0) {
10872 arg2 = all;
10873 } else if (arg2 & ~all) {
10874 return -TARGET_EINVAL;
10875 }
10876 if (arg2 & TARGET_PR_PAC_APIAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -070010877 ret |= qemu_guest_getrandom(&env->keys.apia,
Richard Henderson51977e22019-03-12 19:22:20 -070010878 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010879 }
10880 if (arg2 & TARGET_PR_PAC_APIBKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -070010881 ret |= qemu_guest_getrandom(&env->keys.apib,
Richard Henderson51977e22019-03-12 19:22:20 -070010882 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010883 }
10884 if (arg2 & TARGET_PR_PAC_APDAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -070010885 ret |= qemu_guest_getrandom(&env->keys.apda,
Richard Henderson51977e22019-03-12 19:22:20 -070010886 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010887 }
10888 if (arg2 & TARGET_PR_PAC_APDBKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -070010889 ret |= qemu_guest_getrandom(&env->keys.apdb,
Richard Henderson51977e22019-03-12 19:22:20 -070010890 sizeof(ARMPACKey), &err);
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010891 }
10892 if (arg2 & TARGET_PR_PAC_APGAKEY) {
Richard Henderson108b3ba2019-03-14 17:28:32 -070010893 ret |= qemu_guest_getrandom(&env->keys.apga,
Richard Henderson51977e22019-03-12 19:22:20 -070010894 sizeof(ARMPACKey), &err);
10895 }
10896 if (ret != 0) {
10897 /*
10898 * Some unknown failure in the crypto. The best
10899 * we can do is log it and fail the syscall.
10900 * The real syscall cannot fail this way.
10901 */
10902 qemu_log_mask(LOG_UNIMP,
10903 "PR_PAC_RESET_KEYS: Crypto failure: %s",
10904 error_get_pretty(err));
10905 error_free(err);
10906 return -TARGET_EIO;
Richard Hendersonbff63fb2019-02-05 16:52:39 +000010907 }
10908 return 0;
10909 }
10910 }
10911 return -TARGET_EINVAL;
Richard Henderson85fc7162018-03-09 17:09:43 +000010912#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +000010913 case PR_GET_SECCOMP:
10914 case PR_SET_SECCOMP:
10915 /* Disable seccomp to prevent the target disabling syscalls we
10916 * need. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010917 return -TARGET_EINVAL;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010918 default:
10919 /* Most prctl options have no pointer arguments */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010920 return get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
Peter Maydell1e6722f2012-02-03 14:48:03 +000010921 }
ths39b9aae2007-02-11 18:36:44 +000010922 break;
bellardd2fd1af2007-11-14 18:08:56 +000010923#ifdef TARGET_NR_arch_prctl
10924 case TARGET_NR_arch_prctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010925 return do_arch_prctl(cpu_env, arg1, arg2);
bellardd2fd1af2007-11-14 18:08:56 +000010926#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010927#ifdef TARGET_NR_pread64
10928 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010929 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010930 arg4 = arg5;
10931 arg5 = arg6;
10932 }
Peter Maydell2bd3f892019-01-08 18:49:00 +000010933 if (arg2 == 0 && arg3 == 0) {
10934 /* Special-case NULL buffer and zero length, which should succeed */
10935 p = 0;
10936 } else {
10937 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10938 if (!p) {
10939 return -TARGET_EFAULT;
10940 }
10941 }
aurel32f2c7ba12008-03-28 22:32:06 +000010942 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10943 unlock_user(p, arg2, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010944 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +000010945 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010946 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010947 arg4 = arg5;
10948 arg5 = arg6;
10949 }
Peter Maydell2bd3f892019-01-08 18:49:00 +000010950 if (arg2 == 0 && arg3 == 0) {
10951 /* Special-case NULL buffer and zero length, which should succeed */
10952 p = 0;
10953 } else {
10954 p = lock_user(VERIFY_READ, arg2, arg3, 1);
10955 if (!p) {
10956 return -TARGET_EFAULT;
10957 }
10958 }
aurel32f2c7ba12008-03-28 22:32:06 +000010959 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10960 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010961 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +000010962#endif
bellard31e31b82003-02-18 22:55:36 +000010963 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010964 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010965 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010966 ret = get_errno(sys_getcwd1(p, arg2));
10967 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010968 return ret;
bellard31e31b82003-02-18 22:55:36 +000010969 case TARGET_NR_capget:
10970 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010971 {
10972 struct target_user_cap_header *target_header;
10973 struct target_user_cap_data *target_data = NULL;
10974 struct __user_cap_header_struct header;
10975 struct __user_cap_data_struct data[2];
10976 struct __user_cap_data_struct *dataptr = NULL;
10977 int i, target_datalen;
10978 int data_items = 1;
10979
10980 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010981 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +000010982 }
10983 header.version = tswap32(target_header->version);
10984 header.pid = tswap32(target_header->pid);
10985
Peter Maydellec864872014-03-19 16:07:30 +000010986 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010987 /* Version 2 and up takes pointer to two user_data structs */
10988 data_items = 2;
10989 }
10990
10991 target_datalen = sizeof(*target_data) * data_items;
10992
10993 if (arg2) {
10994 if (num == TARGET_NR_capget) {
10995 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10996 } else {
10997 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10998 }
10999 if (!target_data) {
11000 unlock_user_struct(target_header, arg1, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -070011001 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +000011002 }
11003
11004 if (num == TARGET_NR_capset) {
11005 for (i = 0; i < data_items; i++) {
11006 data[i].effective = tswap32(target_data[i].effective);
11007 data[i].permitted = tswap32(target_data[i].permitted);
11008 data[i].inheritable = tswap32(target_data[i].inheritable);
11009 }
11010 }
11011
11012 dataptr = data;
11013 }
11014
11015 if (num == TARGET_NR_capget) {
11016 ret = get_errno(capget(&header, dataptr));
11017 } else {
11018 ret = get_errno(capset(&header, dataptr));
11019 }
11020
11021 /* The kernel always updates version for both capget and capset */
11022 target_header->version = tswap32(header.version);
11023 unlock_user_struct(target_header, arg1, 1);
11024
11025 if (arg2) {
11026 if (num == TARGET_NR_capget) {
11027 for (i = 0; i < data_items; i++) {
11028 target_data[i].effective = tswap32(data[i].effective);
11029 target_data[i].permitted = tswap32(data[i].permitted);
11030 target_data[i].inheritable = tswap32(data[i].inheritable);
11031 }
11032 unlock_user(target_data, arg2, target_datalen);
11033 } else {
11034 unlock_user(target_data, arg2, 0);
11035 }
11036 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011037 return ret;
Peter Maydelle0eb2102014-03-17 12:15:35 +000011038 }
bellard31e31b82003-02-18 22:55:36 +000011039 case TARGET_NR_sigaltstack:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011040 return do_sigaltstack(arg1, arg2,
11041 get_sp_from_cpustate((CPUArchState *)cpu_env));
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011042
11043#ifdef CONFIG_SENDFILE
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011044#ifdef TARGET_NR_sendfile
bellard31e31b82003-02-18 22:55:36 +000011045 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011046 {
11047 off_t *offp = NULL;
11048 off_t off;
11049 if (arg3) {
11050 ret = get_user_sal(off, arg3);
11051 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011052 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011053 }
11054 offp = &off;
11055 }
11056 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11057 if (!is_error(ret) && arg3) {
11058 abi_long ret2 = put_user_sal(off, arg3);
11059 if (is_error(ret2)) {
11060 ret = ret2;
11061 }
11062 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011063 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011064 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011065#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011066#ifdef TARGET_NR_sendfile64
11067 case TARGET_NR_sendfile64:
11068 {
11069 off_t *offp = NULL;
11070 off_t off;
11071 if (arg3) {
11072 ret = get_user_s64(off, arg3);
11073 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011074 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011075 }
11076 offp = &off;
11077 }
11078 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11079 if (!is_error(ret) && arg3) {
11080 abi_long ret2 = put_user_s64(off, arg3);
11081 if (is_error(ret2)) {
11082 ret = ret2;
11083 }
11084 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011085 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011086 }
11087#endif
bellardebc05482003-09-30 21:08:41 +000011088#endif
bellard048f6b42005-11-26 18:47:20 +000011089#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000011090 case TARGET_NR_vfork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011091 return get_errno(do_fork(cpu_env,
11092 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
11093 0, 0, 0, 0));
bellard048f6b42005-11-26 18:47:20 +000011094#endif
bellardebc05482003-09-30 21:08:41 +000011095#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000011096 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000011097 {
11098 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030011099 int resource = target_to_host_resource(arg1);
11100 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000011101 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000011102 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000011103 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011104 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090011105 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
11106 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000011107 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000011108 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011109 return ret;
bellard728584b2003-04-29 20:43:36 +000011110 }
bellardebc05482003-09-30 21:08:41 +000011111#endif
bellarda315a142005-01-30 22:59:18 +000011112#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000011113 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000011114 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011115 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011116 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
11117 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011118 return ret;
bellarda315a142005-01-30 22:59:18 +000011119#endif
11120#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000011121 case TARGET_NR_ftruncate64:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011122 return target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellarda315a142005-01-30 22:59:18 +000011123#endif
11124#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000011125 case TARGET_NR_stat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070011126 if (!(p = lock_user_string(arg1))) {
11127 return -TARGET_EFAULT;
11128 }
pbrook53a59602006-03-25 19:31:22 +000011129 ret = get_errno(stat(path(p), &st));
11130 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011131 if (!is_error(ret))
11132 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011133 return ret;
bellarda315a142005-01-30 22:59:18 +000011134#endif
11135#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000011136 case TARGET_NR_lstat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070011137 if (!(p = lock_user_string(arg1))) {
11138 return -TARGET_EFAULT;
11139 }
pbrook53a59602006-03-25 19:31:22 +000011140 ret = get_errno(lstat(path(p), &st));
11141 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011142 if (!is_error(ret))
11143 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011144 return ret;
bellarda315a142005-01-30 22:59:18 +000011145#endif
11146#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000011147 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000011148 ret = get_errno(fstat(arg1, &st));
11149 if (!is_error(ret))
11150 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011151 return ret;
bellardec86b0f2003-04-11 00:15:04 +000011152#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010011153#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000011154#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000011155 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000011156#endif
11157#ifdef TARGET_NR_newfstatat
11158 case TARGET_NR_newfstatat:
11159#endif
Richard Henderson2852aaf2018-08-18 12:01:06 -070011160 if (!(p = lock_user_string(arg2))) {
11161 return -TARGET_EFAULT;
11162 }
Peter Maydellc0d472b2013-06-12 16:20:21 +010011163 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
Richard Henderson2852aaf2018-08-18 12:01:06 -070011164 unlock_user(p, arg2, 0);
balrog6a24a772008-09-20 02:23:36 +000011165 if (!is_error(ret))
11166 ret = host_to_target_stat64(cpu_env, arg3, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011167 return ret;
bellarda315a142005-01-30 22:59:18 +000011168#endif
Aleksandar Rikaloefa92182019-06-28 12:43:34 +020011169#if defined(TARGET_NR_statx)
11170 case TARGET_NR_statx:
11171 {
11172 struct target_statx *target_stx;
11173 int dirfd = arg1;
11174 int flags = arg3;
11175
11176 p = lock_user_string(arg2);
11177 if (p == NULL) {
11178 return -TARGET_EFAULT;
11179 }
11180#if defined(__NR_statx)
11181 {
11182 /*
11183 * It is assumed that struct statx is architecture independent.
11184 */
11185 struct target_statx host_stx;
11186 int mask = arg4;
11187
11188 ret = get_errno(sys_statx(dirfd, p, flags, mask, &host_stx));
11189 if (!is_error(ret)) {
11190 if (host_to_target_statx(&host_stx, arg5) != 0) {
11191 unlock_user(p, arg2, 0);
11192 return -TARGET_EFAULT;
11193 }
11194 }
11195
11196 if (ret != -TARGET_ENOSYS) {
11197 unlock_user(p, arg2, 0);
11198 return ret;
11199 }
11200 }
11201#endif
11202 ret = get_errno(fstatat(dirfd, path(p), &st, flags));
11203 unlock_user(p, arg2, 0);
11204
11205 if (!is_error(ret)) {
11206 if (!lock_user_struct(VERIFY_WRITE, target_stx, arg5, 0)) {
11207 return -TARGET_EFAULT;
11208 }
11209 memset(target_stx, 0, sizeof(*target_stx));
11210 __put_user(major(st.st_dev), &target_stx->stx_dev_major);
11211 __put_user(minor(st.st_dev), &target_stx->stx_dev_minor);
11212 __put_user(st.st_ino, &target_stx->stx_ino);
11213 __put_user(st.st_mode, &target_stx->stx_mode);
11214 __put_user(st.st_uid, &target_stx->stx_uid);
11215 __put_user(st.st_gid, &target_stx->stx_gid);
11216 __put_user(st.st_nlink, &target_stx->stx_nlink);
11217 __put_user(major(st.st_rdev), &target_stx->stx_rdev_major);
11218 __put_user(minor(st.st_rdev), &target_stx->stx_rdev_minor);
11219 __put_user(st.st_size, &target_stx->stx_size);
11220 __put_user(st.st_blksize, &target_stx->stx_blksize);
11221 __put_user(st.st_blocks, &target_stx->stx_blocks);
11222 __put_user(st.st_atime, &target_stx->stx_atime.tv_sec);
11223 __put_user(st.st_mtime, &target_stx->stx_mtime.tv_sec);
11224 __put_user(st.st_ctime, &target_stx->stx_ctime.tv_sec);
11225 unlock_user_struct(target_stx, arg5, 1);
11226 }
11227 }
11228 return ret;
11229#endif
Chen Gang704eff62015-08-21 05:37:33 +080011230#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000011231 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000011232 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011233 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011234 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
11235 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011236 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080011237#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030011238#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000011239 case TARGET_NR_getuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011240 return get_errno(high2lowuid(getuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011241#endif
11242#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000011243 case TARGET_NR_getgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011244 return get_errno(high2lowgid(getgid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011245#endif
11246#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000011247 case TARGET_NR_geteuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011248 return get_errno(high2lowuid(geteuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011249#endif
11250#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011251 case TARGET_NR_getegid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011252 return get_errno(high2lowgid(getegid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011253#endif
bellard67867302003-11-23 17:05:30 +000011254 case TARGET_NR_setreuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011255 return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
bellard67867302003-11-23 17:05:30 +000011256 case TARGET_NR_setregid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011257 return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
bellard67867302003-11-23 17:05:30 +000011258 case TARGET_NR_getgroups:
11259 {
11260 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011261 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000011262 gid_t *grouplist;
11263 int i;
11264
11265 grouplist = alloca(gidsetsize * sizeof(gid_t));
11266 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011267 if (gidsetsize == 0)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011268 return ret;
bellard67867302003-11-23 17:05:30 +000011269 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000011270 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000011271 if (!target_grouplist)
Richard Henderson2852aaf2018-08-18 12:01:06 -070011272 return -TARGET_EFAULT;
balroga2155fc2008-09-20 02:12:08 +000011273 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030011274 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011275 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000011276 }
11277 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011278 return ret;
bellard67867302003-11-23 17:05:30 +000011279 case TARGET_NR_setgroups:
11280 {
11281 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011282 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011283 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011284 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011285 if (gidsetsize) {
11286 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011287 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011288 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070011289 return -TARGET_EFAULT;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011290 }
11291 for (i = 0; i < gidsetsize; i++) {
11292 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11293 }
11294 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000011295 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011296 return get_errno(setgroups(gidsetsize, grouplist));
bellard67867302003-11-23 17:05:30 +000011297 }
bellard67867302003-11-23 17:05:30 +000011298 case TARGET_NR_fchown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011299 return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
Peter Maydellc0d472b2013-06-12 16:20:21 +010011300#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011301 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011302 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011303 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011304 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11305 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011306 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011307 return ret;
thsccfa72b2007-09-24 09:23:34 +000011308#endif
bellard67867302003-11-23 17:05:30 +000011309#ifdef TARGET_NR_setresuid
11310 case TARGET_NR_setresuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011311 return get_errno(sys_setresuid(low2highuid(arg1),
11312 low2highuid(arg2),
11313 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011314#endif
11315#ifdef TARGET_NR_getresuid
11316 case TARGET_NR_getresuid:
11317 {
pbrook53a59602006-03-25 19:31:22 +000011318 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011319 ret = get_errno(getresuid(&ruid, &euid, &suid));
11320 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011321 if (put_user_id(high2lowuid(ruid), arg1)
11322 || put_user_id(high2lowuid(euid), arg2)
11323 || put_user_id(high2lowuid(suid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011324 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000011325 }
11326 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011327 return ret;
bellard67867302003-11-23 17:05:30 +000011328#endif
11329#ifdef TARGET_NR_getresgid
11330 case TARGET_NR_setresgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011331 return get_errno(sys_setresgid(low2highgid(arg1),
11332 low2highgid(arg2),
11333 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011334#endif
11335#ifdef TARGET_NR_getresgid
11336 case TARGET_NR_getresgid:
11337 {
pbrook53a59602006-03-25 19:31:22 +000011338 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011339 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11340 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011341 if (put_user_id(high2lowgid(rgid), arg1)
11342 || put_user_id(high2lowgid(egid), arg2)
11343 || put_user_id(high2lowgid(sgid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011344 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000011345 }
11346 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011347 return ret;
bellard67867302003-11-23 17:05:30 +000011348#endif
Chen Gang704eff62015-08-21 05:37:33 +080011349#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011350 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011351 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011352 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011353 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11354 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011355 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080011356#endif
bellard67867302003-11-23 17:05:30 +000011357 case TARGET_NR_setuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011358 return get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011359 case TARGET_NR_setgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011360 return get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011361 case TARGET_NR_setfsuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011362 return get_errno(setfsuid(arg1));
bellard67867302003-11-23 17:05:30 +000011363 case TARGET_NR_setfsgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011364 return get_errno(setfsgid(arg1));
bellard67867302003-11-23 17:05:30 +000011365
bellarda315a142005-01-30 22:59:18 +000011366#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011367 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011368 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011369 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011370 ret = get_errno(lchown(p, arg2, arg3));
11371 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011372 return ret;
bellarda315a142005-01-30 22:59:18 +000011373#endif
11374#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011375 case TARGET_NR_getuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011376 return get_errno(getuid());
bellarda315a142005-01-30 22:59:18 +000011377#endif
aurel3264b4d282008-11-14 17:20:15 +000011378
11379#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11380 /* Alpha specific */
11381 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011382 {
11383 uid_t euid;
11384 euid=geteuid();
11385 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11386 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011387 return get_errno(getuid());
aurel3264b4d282008-11-14 17:20:15 +000011388#endif
11389#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11390 /* Alpha specific */
11391 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011392 {
11393 uid_t egid;
11394 egid=getegid();
11395 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11396 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011397 return get_errno(getgid());
aurel3264b4d282008-11-14 17:20:15 +000011398#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011399#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11400 /* Alpha specific */
11401 case TARGET_NR_osf_getsysinfo:
11402 ret = -TARGET_EOPNOTSUPP;
11403 switch (arg1) {
11404 case TARGET_GSI_IEEE_FP_CONTROL:
11405 {
Richard Henderson21ba8562019-04-26 15:20:51 -070011406 uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env);
11407 uint64_t swcr = ((CPUAlphaState *)cpu_env)->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011408
Richard Henderson21ba8562019-04-26 15:20:51 -070011409 swcr &= ~SWCR_STATUS_MASK;
11410 swcr |= (fpcr >> 35) & SWCR_STATUS_MASK;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011411
11412 if (put_user_u64 (swcr, arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011413 return -TARGET_EFAULT;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011414 ret = 0;
11415 }
11416 break;
11417
11418 /* case GSI_IEEE_STATE_AT_SIGNAL:
11419 -- Not implemented in linux kernel.
11420 case GSI_UACPROC:
11421 -- Retrieves current unaligned access state; not much used.
11422 case GSI_PROC_TYPE:
11423 -- Retrieves implver information; surely not used.
11424 case GSI_GET_HWRPB:
11425 -- Grabs a copy of the HWRPB; surely not used.
11426 */
11427 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011428 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011429#endif
11430#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11431 /* Alpha specific */
11432 case TARGET_NR_osf_setsysinfo:
11433 ret = -TARGET_EOPNOTSUPP;
11434 switch (arg1) {
11435 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011436 {
Richard Henderson21ba8562019-04-26 15:20:51 -070011437 uint64_t swcr, fpcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011438
Richard Henderson6e06d512012-06-01 09:08:21 -070011439 if (get_user_u64 (swcr, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011440 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070011441 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011442
Richard Henderson21ba8562019-04-26 15:20:51 -070011443 /*
11444 * The kernel calls swcr_update_status to update the
11445 * status bits from the fpcr at every point that it
11446 * could be queried. Therefore, we store the status
11447 * bits only in FPCR.
11448 */
11449 ((CPUAlphaState *)cpu_env)->swcr
11450 = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011451
Richard Henderson21ba8562019-04-26 15:20:51 -070011452 fpcr = cpu_alpha_load_fpcr(cpu_env);
11453 fpcr &= ((uint64_t)FPCR_DYN_MASK << 32);
11454 fpcr |= alpha_ieee_swcr_to_fpcr(swcr);
Richard Henderson6e06d512012-06-01 09:08:21 -070011455 cpu_alpha_store_fpcr(cpu_env, fpcr);
11456 ret = 0;
11457 }
11458 break;
11459
11460 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11461 {
Richard Henderson21ba8562019-04-26 15:20:51 -070011462 uint64_t exc, fpcr, fex;
Richard Henderson6e06d512012-06-01 09:08:21 -070011463
11464 if (get_user_u64(exc, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011465 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070011466 }
Richard Henderson21ba8562019-04-26 15:20:51 -070011467 exc &= SWCR_STATUS_MASK;
11468 fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011469
Richard Henderson6e06d512012-06-01 09:08:21 -070011470 /* Old exceptions are not signaled. */
Richard Henderson21ba8562019-04-26 15:20:51 -070011471 fex = alpha_ieee_fpcr_to_swcr(fpcr);
11472 fex = exc & ~fex;
11473 fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT;
11474 fex &= ((CPUArchState *)cpu_env)->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011475
Richard Henderson21ba8562019-04-26 15:20:51 -070011476 /* Update the hardware fpcr. */
11477 fpcr |= alpha_ieee_swcr_to_fpcr(exc);
11478 cpu_alpha_store_fpcr(cpu_env, fpcr);
11479
11480 if (fex) {
11481 int si_code = TARGET_FPE_FLTUNK;
Richard Henderson6e06d512012-06-01 09:08:21 -070011482 target_siginfo_t info;
Richard Henderson21ba8562019-04-26 15:20:51 -070011483
11484 if (fex & SWCR_TRAP_ENABLE_DNO) {
11485 si_code = TARGET_FPE_FLTUND;
11486 }
11487 if (fex & SWCR_TRAP_ENABLE_INE) {
11488 si_code = TARGET_FPE_FLTRES;
11489 }
11490 if (fex & SWCR_TRAP_ENABLE_UNF) {
11491 si_code = TARGET_FPE_FLTUND;
11492 }
11493 if (fex & SWCR_TRAP_ENABLE_OVF) {
11494 si_code = TARGET_FPE_FLTOVF;
11495 }
11496 if (fex & SWCR_TRAP_ENABLE_DZE) {
11497 si_code = TARGET_FPE_FLTDIV;
11498 }
11499 if (fex & SWCR_TRAP_ENABLE_INV) {
11500 si_code = TARGET_FPE_FLTINV;
11501 }
11502
Richard Henderson6e06d512012-06-01 09:08:21 -070011503 info.si_signo = SIGFPE;
11504 info.si_errno = 0;
11505 info.si_code = si_code;
11506 info._sifields._sigfault._addr
11507 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011508 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11509 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011510 }
Richard Henderson21ba8562019-04-26 15:20:51 -070011511 ret = 0;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011512 }
11513 break;
11514
11515 /* case SSI_NVPAIRS:
11516 -- Used with SSIN_UACPROC to enable unaligned accesses.
11517 case SSI_IEEE_STATE_AT_SIGNAL:
11518 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11519 -- Not implemented in linux kernel
11520 */
11521 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011522 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011523#endif
11524#ifdef TARGET_NR_osf_sigprocmask
11525 /* Alpha specific. */
11526 case TARGET_NR_osf_sigprocmask:
11527 {
11528 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011529 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011530 sigset_t set, oldset;
11531
11532 switch(arg1) {
11533 case TARGET_SIG_BLOCK:
11534 how = SIG_BLOCK;
11535 break;
11536 case TARGET_SIG_UNBLOCK:
11537 how = SIG_UNBLOCK;
11538 break;
11539 case TARGET_SIG_SETMASK:
11540 how = SIG_SETMASK;
11541 break;
11542 default:
Richard Henderson259841c2018-08-18 12:01:09 -070011543 return -TARGET_EINVAL;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011544 }
11545 mask = arg2;
11546 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011547 ret = do_sigprocmask(how, &set, &oldset);
11548 if (!ret) {
11549 host_to_target_old_sigset(&mask, &oldset);
11550 ret = mask;
11551 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011552 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011553 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011554#endif
aurel3264b4d282008-11-14 17:20:15 +000011555
bellarda315a142005-01-30 22:59:18 +000011556#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011557 case TARGET_NR_getgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011558 return get_errno(getgid());
bellarda315a142005-01-30 22:59:18 +000011559#endif
11560#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011561 case TARGET_NR_geteuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011562 return get_errno(geteuid());
bellarda315a142005-01-30 22:59:18 +000011563#endif
11564#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011565 case TARGET_NR_getegid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011566 return get_errno(getegid());
bellarda315a142005-01-30 22:59:18 +000011567#endif
11568#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011569 case TARGET_NR_setreuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011570 return get_errno(setreuid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000011571#endif
11572#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011573 case TARGET_NR_setregid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011574 return get_errno(setregid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000011575#endif
11576#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011577 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011578 {
11579 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011580 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011581 gid_t *grouplist;
11582 int i;
11583
11584 grouplist = alloca(gidsetsize * sizeof(gid_t));
11585 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011586 if (gidsetsize == 0)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011587 return ret;
bellard99c475a2005-01-31 20:45:13 +000011588 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011589 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11590 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070011591 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011592 }
balroga2155fc2008-09-20 02:12:08 +000011593 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011594 target_grouplist[i] = tswap32(grouplist[i]);
11595 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011596 }
11597 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011598 return ret;
bellarda315a142005-01-30 22:59:18 +000011599#endif
11600#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011601 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011602 {
11603 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011604 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011605 gid_t *grouplist;
11606 int i;
ths3b46e622007-09-17 08:09:54 +000011607
bellard99c475a2005-01-31 20:45:13 +000011608 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011609 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11610 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070011611 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011612 }
bellard99c475a2005-01-31 20:45:13 +000011613 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011614 grouplist[i] = tswap32(target_grouplist[i]);
11615 unlock_user(target_grouplist, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011616 return get_errno(setgroups(gidsetsize, grouplist));
bellard99c475a2005-01-31 20:45:13 +000011617 }
bellarda315a142005-01-30 22:59:18 +000011618#endif
11619#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011620 case TARGET_NR_fchown32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011621 return get_errno(fchown(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000011622#endif
11623#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011624 case TARGET_NR_setresuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011625 return get_errno(sys_setresuid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000011626#endif
11627#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011628 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011629 {
pbrook53a59602006-03-25 19:31:22 +000011630 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011631 ret = get_errno(getresuid(&ruid, &euid, &suid));
11632 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011633 if (put_user_u32(ruid, arg1)
11634 || put_user_u32(euid, arg2)
11635 || put_user_u32(suid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011636 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000011637 }
11638 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011639 return ret;
bellarda315a142005-01-30 22:59:18 +000011640#endif
11641#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011642 case TARGET_NR_setresgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011643 return get_errno(sys_setresgid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000011644#endif
11645#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011646 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011647 {
pbrook53a59602006-03-25 19:31:22 +000011648 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011649 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11650 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011651 if (put_user_u32(rgid, arg1)
11652 || put_user_u32(egid, arg2)
11653 || put_user_u32(sgid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011654 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000011655 }
11656 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011657 return ret;
bellarda315a142005-01-30 22:59:18 +000011658#endif
11659#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011660 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011661 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011662 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011663 ret = get_errno(chown(p, arg2, arg3));
11664 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011665 return ret;
bellarda315a142005-01-30 22:59:18 +000011666#endif
11667#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011668 case TARGET_NR_setuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011669 return get_errno(sys_setuid(arg1));
bellarda315a142005-01-30 22:59:18 +000011670#endif
11671#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011672 case TARGET_NR_setgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011673 return get_errno(sys_setgid(arg1));
bellarda315a142005-01-30 22:59:18 +000011674#endif
11675#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011676 case TARGET_NR_setfsuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011677 return get_errno(setfsuid(arg1));
bellarda315a142005-01-30 22:59:18 +000011678#endif
11679#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011680 case TARGET_NR_setfsgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011681 return get_errno(setfsgid(arg1));
bellarda315a142005-01-30 22:59:18 +000011682#endif
bellardffa65c32004-01-04 23:57:22 +000011683#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011684 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011685 {
Richard Henderson259841c2018-08-18 12:01:09 -070011686 void *a = lock_user(VERIFY_READ, arg1, arg2, 0);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011687 if (!a) {
Richard Henderson259841c2018-08-18 12:01:09 -070011688 return -TARGET_ENOMEM;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011689 }
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011690 p = lock_user_string(arg3);
11691 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -070011692 ret = -TARGET_EFAULT;
11693 } else {
11694 ret = get_errno(mincore(a, arg2, p));
11695 unlock_user(p, arg3, ret);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011696 }
aurel3204bb9ac2008-10-01 21:46:41 +000011697 unlock_user(a, arg1, 0);
11698 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011699 return ret;
bellardffa65c32004-01-04 23:57:22 +000011700#endif
aurel32408321b2008-10-01 21:46:32 +000011701#ifdef TARGET_NR_arm_fadvise64_64
11702 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011703 /* arm_fadvise64_64 looks like fadvise64_64 but
11704 * with different argument order: fd, advice, offset, len
11705 * rather than the usual fd, offset, len, advice.
11706 * Note that offset and len are both 64-bit so appear as
11707 * pairs of 32-bit registers.
11708 */
11709 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11710 target_offset64(arg5, arg6), arg2);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011711 return -host_to_target_errno(ret);
aurel32408321b2008-10-01 21:46:32 +000011712#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011713
11714#if TARGET_ABI_BITS == 32
11715
11716#ifdef TARGET_NR_fadvise64_64
11717 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070011718#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010011719 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11720 ret = arg2;
11721 arg2 = arg3;
11722 arg3 = arg4;
11723 arg4 = arg5;
11724 arg5 = arg6;
11725 arg6 = ret;
11726#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011727 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011728 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011729 /* offset is in (3,4), len in (5,6) and advice in 7 */
11730 arg2 = arg3;
11731 arg3 = arg4;
11732 arg4 = arg5;
11733 arg5 = arg6;
11734 arg6 = arg7;
11735 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011736#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011737 ret = posix_fadvise(arg1, target_offset64(arg2, arg3),
11738 target_offset64(arg4, arg5), arg6);
11739 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011740#endif
11741
11742#ifdef TARGET_NR_fadvise64
11743 case TARGET_NR_fadvise64:
11744 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011745 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011746 /* offset is in (3,4), len in 5 and advice in 6 */
11747 arg2 = arg3;
11748 arg3 = arg4;
11749 arg4 = arg5;
11750 arg5 = arg6;
11751 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011752 ret = posix_fadvise(arg1, target_offset64(arg2, arg3), arg4, arg5);
11753 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011754#endif
11755
11756#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011757#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011758#ifdef TARGET_NR_fadvise64_64
11759 case TARGET_NR_fadvise64_64:
11760#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011761#ifdef TARGET_NR_fadvise64
11762 case TARGET_NR_fadvise64:
11763#endif
11764#ifdef TARGET_S390X
11765 switch (arg4) {
11766 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11767 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11768 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11769 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11770 default: break;
11771 }
11772#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011773 return -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
aurel32408321b2008-10-01 21:46:32 +000011774#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011775#endif /* end of 64-bit ABI fadvise handling */
11776
bellardffa65c32004-01-04 23:57:22 +000011777#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011778 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011779 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011780 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011781 This will break MADV_DONTNEED.
11782 This is a hint, so ignoring and returning success is ok. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011783 return 0;
bellardffa65c32004-01-04 23:57:22 +000011784#endif
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010011785#ifdef TARGET_NR_fcntl64
bellard31e31b82003-02-18 22:55:36 +000011786 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011787 {
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010011788 int cmd;
11789 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011790 from_flock64_fn *copyfrom = copy_from_user_flock64;
11791 to_flock64_fn *copyto = copy_to_user_flock64;
11792
pbrookce4defa2006-02-09 16:49:55 +000011793#ifdef TARGET_ARM
Laurent Vivier7f254c52018-05-02 23:57:30 +020011794 if (!((CPUARMState *)cpu_env)->eabi) {
11795 copyfrom = copy_from_user_oabi_flock64;
11796 copyto = copy_to_user_oabi_flock64;
Peter Maydell213d3e92016-06-13 11:22:05 +010011797 }
pbrookce4defa2006-02-09 16:49:55 +000011798#endif
bellard77e46722003-04-29 20:39:06 +000011799
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010011800 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011801 if (cmd == -TARGET_EINVAL) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011802 return cmd;
Peter Maydell31b63192011-12-05 23:11:50 +000011803 }
thsb1e341e2007-03-20 21:50:52 +000011804
bellard60cd49d2003-03-16 22:53:56 +000011805 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011806 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011807 ret = copyfrom(&fl, arg3);
11808 if (ret) {
11809 break;
ths58134272007-03-31 18:59:32 +000011810 }
Laurent Vivieraf8ab2b2018-07-13 14:58:05 +020011811 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011812 if (ret == 0) {
11813 ret = copyto(arg3, &fl);
11814 }
bellard77e46722003-04-29 20:39:06 +000011815 break;
11816
thsb1e341e2007-03-20 21:50:52 +000011817 case TARGET_F_SETLK64:
11818 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011819 ret = copyfrom(&fl, arg3);
11820 if (ret) {
11821 break;
pbrookce4defa2006-02-09 16:49:55 +000011822 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011823 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011824 break;
bellard60cd49d2003-03-16 22:53:56 +000011825 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011826 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011827 break;
11828 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011829 return ret;
bellard77e46722003-04-29 20:39:06 +000011830 }
bellard60cd49d2003-03-16 22:53:56 +000011831#endif
ths7d600c82006-12-08 01:32:58 +000011832#ifdef TARGET_NR_cacheflush
11833 case TARGET_NR_cacheflush:
11834 /* self-modifying code is handled automatically, so nothing needed */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011835 return 0;
ths7d600c82006-12-08 01:32:58 +000011836#endif
bellardc573ff62004-01-04 15:51:36 +000011837#ifdef TARGET_NR_getpagesize
11838 case TARGET_NR_getpagesize:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011839 return TARGET_PAGE_SIZE;
bellardc573ff62004-01-04 15:51:36 +000011840#endif
bellard31e31b82003-02-18 22:55:36 +000011841 case TARGET_NR_gettid:
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +000011842 return get_errno(sys_gettid());
thse5febef2007-04-01 18:31:35 +000011843#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011844 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011845#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011846 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011847 arg2 = arg3;
11848 arg3 = arg4;
11849 arg4 = arg5;
11850 }
Lena Djokic77c68502016-11-24 17:08:56 +010011851 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011852#else
11853 ret = get_errno(readahead(arg1, arg2, arg3));
11854#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011855 return ret;
thse5febef2007-04-01 18:31:35 +000011856#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011857#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011858#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011859 case TARGET_NR_listxattr:
11860 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011861 {
11862 void *p, *b = 0;
11863 if (arg2) {
11864 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11865 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011866 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011867 }
11868 }
11869 p = lock_user_string(arg1);
11870 if (p) {
11871 if (num == TARGET_NR_listxattr) {
11872 ret = get_errno(listxattr(p, b, arg3));
11873 } else {
11874 ret = get_errno(llistxattr(p, b, arg3));
11875 }
11876 } else {
11877 ret = -TARGET_EFAULT;
11878 }
11879 unlock_user(p, arg1, 0);
11880 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011881 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011882 }
11883 case TARGET_NR_flistxattr:
11884 {
11885 void *b = 0;
11886 if (arg2) {
11887 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11888 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011889 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011890 }
11891 }
11892 ret = get_errno(flistxattr(arg1, b, arg3));
11893 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011894 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011895 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011896 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011897 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011898 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011899 void *p, *n, *v = 0;
11900 if (arg3) {
11901 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11902 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011903 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011904 }
11905 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011906 p = lock_user_string(arg1);
11907 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011908 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011909 if (num == TARGET_NR_setxattr) {
11910 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11911 } else {
11912 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11913 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011914 } else {
11915 ret = -TARGET_EFAULT;
11916 }
11917 unlock_user(p, arg1, 0);
11918 unlock_user(n, arg2, 0);
11919 unlock_user(v, arg3, 0);
11920 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011921 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000011922 case TARGET_NR_fsetxattr:
11923 {
11924 void *n, *v = 0;
11925 if (arg3) {
11926 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11927 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011928 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000011929 }
11930 }
11931 n = lock_user_string(arg2);
11932 if (n) {
11933 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11934 } else {
11935 ret = -TARGET_EFAULT;
11936 }
11937 unlock_user(n, arg2, 0);
11938 unlock_user(v, arg3, 0);
11939 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011940 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011941 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011942 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011943 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011944 void *p, *n, *v = 0;
11945 if (arg3) {
11946 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11947 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011948 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011949 }
11950 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011951 p = lock_user_string(arg1);
11952 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011953 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011954 if (num == TARGET_NR_getxattr) {
11955 ret = get_errno(getxattr(p, n, v, arg4));
11956 } else {
11957 ret = get_errno(lgetxattr(p, n, v, arg4));
11958 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011959 } else {
11960 ret = -TARGET_EFAULT;
11961 }
11962 unlock_user(p, arg1, 0);
11963 unlock_user(n, arg2, 0);
11964 unlock_user(v, arg3, arg4);
11965 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011966 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000011967 case TARGET_NR_fgetxattr:
11968 {
11969 void *n, *v = 0;
11970 if (arg3) {
11971 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11972 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011973 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000011974 }
11975 }
11976 n = lock_user_string(arg2);
11977 if (n) {
11978 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11979 } else {
11980 ret = -TARGET_EFAULT;
11981 }
11982 unlock_user(n, arg2, 0);
11983 unlock_user(v, arg3, arg4);
11984 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011985 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011986 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011987 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011988 {
11989 void *p, *n;
11990 p = lock_user_string(arg1);
11991 n = lock_user_string(arg2);
11992 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011993 if (num == TARGET_NR_removexattr) {
11994 ret = get_errno(removexattr(p, n));
11995 } else {
11996 ret = get_errno(lremovexattr(p, n));
11997 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011998 } else {
11999 ret = -TARGET_EFAULT;
12000 }
12001 unlock_user(p, arg1, 0);
12002 unlock_user(n, arg2, 0);
12003 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012004 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000012005 case TARGET_NR_fremovexattr:
12006 {
12007 void *n;
12008 n = lock_user_string(arg2);
12009 if (n) {
12010 ret = get_errno(fremovexattr(arg1, n));
12011 } else {
12012 ret = -TARGET_EFAULT;
12013 }
12014 unlock_user(n, arg2, 0);
12015 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012016 return ret;
bellardebc05482003-09-30 21:08:41 +000012017#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012018#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000012019#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000012020 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012021#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020012022 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012023 return 0;
edgar_iglef967792009-01-07 14:19:38 +000012024#elif defined(TARGET_CRIS)
12025 if (arg1 & 0xff)
12026 ret = -TARGET_EINVAL;
12027 else {
12028 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
12029 ret = 0;
12030 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012031 return ret;
bellard8d18e892007-11-14 15:18:40 +000012032#elif defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012033 return do_set_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010012034#elif defined(TARGET_M68K)
12035 {
Andreas Färber0429a972013-08-26 18:14:44 +020012036 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012037 ts->tp_value = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012038 return 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012039 }
ths6f5b89a2007-03-02 20:48:00 +000012040#else
Richard Henderson10f45d92018-08-18 12:01:07 -070012041 return -TARGET_ENOSYS;
ths6f5b89a2007-03-02 20:48:00 +000012042#endif
12043#endif
12044#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000012045 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012046#if defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012047 return do_get_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010012048#elif defined(TARGET_M68K)
12049 {
Andreas Färber0429a972013-08-26 18:14:44 +020012050 TaskState *ts = cpu->opaque;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012051 return ts->tp_value;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012052 }
bellard8d18e892007-11-14 15:18:40 +000012053#else
Richard Henderson10f45d92018-08-18 12:01:07 -070012054 return -TARGET_ENOSYS;
bellardebc05482003-09-30 21:08:41 +000012055#endif
bellard8d18e892007-11-14 15:18:40 +000012056#endif
bellard48dc41e2006-06-21 18:15:50 +000012057#ifdef TARGET_NR_getdomainname
12058 case TARGET_NR_getdomainname:
Richard Henderson10f45d92018-08-18 12:01:07 -070012059 return -TARGET_ENOSYS;
bellard48dc41e2006-06-21 18:15:50 +000012060#endif
ths6f5b89a2007-03-02 20:48:00 +000012061
Max Filippov12e33402018-04-01 13:13:49 -070012062#ifdef TARGET_NR_clock_settime
12063 case TARGET_NR_clock_settime:
12064 {
12065 struct timespec ts;
12066
12067 ret = target_to_host_timespec(&ts, arg2);
12068 if (!is_error(ret)) {
12069 ret = get_errno(clock_settime(arg1, &ts));
12070 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012071 return ret;
Max Filippov12e33402018-04-01 13:13:49 -070012072 }
12073#endif
Alistair Francisc6c8d102020-03-12 15:13:53 -070012074#ifdef TARGET_NR_clock_settime64
12075 case TARGET_NR_clock_settime64:
12076 {
12077 struct timespec ts;
12078
12079 ret = target_to_host_timespec64(&ts, arg2);
12080 if (!is_error(ret)) {
12081 ret = get_errno(clock_settime(arg1, &ts));
12082 }
12083 return ret;
12084 }
12085#endif
thsb5906f92007-03-19 13:32:45 +000012086#ifdef TARGET_NR_clock_gettime
12087 case TARGET_NR_clock_gettime:
12088 {
12089 struct timespec ts;
12090 ret = get_errno(clock_gettime(arg1, &ts));
12091 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070012092 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000012093 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012094 return ret;
thsb5906f92007-03-19 13:32:45 +000012095 }
12096#endif
Alistair Francisc6c8d102020-03-12 15:13:53 -070012097#ifdef TARGET_NR_clock_gettime64
12098 case TARGET_NR_clock_gettime64:
12099 {
12100 struct timespec ts;
12101 ret = get_errno(clock_gettime(arg1, &ts));
12102 if (!is_error(ret)) {
12103 ret = host_to_target_timespec64(arg2, &ts);
12104 }
12105 return ret;
12106 }
12107#endif
thsb5906f92007-03-19 13:32:45 +000012108#ifdef TARGET_NR_clock_getres
12109 case TARGET_NR_clock_getres:
12110 {
12111 struct timespec ts;
12112 ret = get_errno(clock_getres(arg1, &ts));
12113 if (!is_error(ret)) {
12114 host_to_target_timespec(arg2, &ts);
12115 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012116 return ret;
thsb5906f92007-03-19 13:32:45 +000012117 }
12118#endif
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012119#ifdef TARGET_NR_clock_getres_time64
12120 case TARGET_NR_clock_getres_time64:
12121 {
12122 struct timespec ts;
12123 ret = get_errno(clock_getres(arg1, &ts));
12124 if (!is_error(ret)) {
12125 host_to_target_timespec64(arg2, &ts);
12126 }
12127 return ret;
12128 }
12129#endif
pbrook63d76512008-05-29 13:43:29 +000012130#ifdef TARGET_NR_clock_nanosleep
12131 case TARGET_NR_clock_nanosleep:
12132 {
12133 struct timespec ts;
Filip Bozutab09d6402020-07-27 22:13:26 +020012134 if (target_to_host_timespec(&ts, arg3)) {
12135 return -TARGET_EFAULT;
12136 }
Peter Maydell9e518222016-06-06 19:58:09 +010012137 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12138 &ts, arg4 ? &ts : NULL));
Laurent Vivier8ec68a02020-07-24 07:45:05 +010012139 /*
12140 * if the call is interrupted by a signal handler, it fails
12141 * with error -TARGET_EINTR and if arg4 is not NULL and arg2 is not
12142 * TIMER_ABSTIME, it returns the remaining unslept time in arg4.
12143 */
Filip Bozutab09d6402020-07-27 22:13:26 +020012144 if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME &&
12145 host_to_target_timespec(arg4, &ts)) {
12146 return -TARGET_EFAULT;
Laurent Vivier8ec68a02020-07-24 07:45:05 +010012147 }
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012148
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012149 return ret;
pbrook63d76512008-05-29 13:43:29 +000012150 }
12151#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +020012152#ifdef TARGET_NR_clock_nanosleep_time64
12153 case TARGET_NR_clock_nanosleep_time64:
12154 {
12155 struct timespec ts;
12156
12157 if (target_to_host_timespec64(&ts, arg3)) {
12158 return -TARGET_EFAULT;
12159 }
12160
12161 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12162 &ts, arg4 ? &ts : NULL));
12163
12164 if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME &&
12165 host_to_target_timespec64(arg4, &ts)) {
12166 return -TARGET_EFAULT;
12167 }
12168 return ret;
12169 }
12170#endif
thsb5906f92007-03-19 13:32:45 +000012171
ths6f5b89a2007-03-02 20:48:00 +000012172#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
12173 case TARGET_NR_set_tid_address:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012174 return get_errno(set_tid_address((int *)g2h(arg1)));
ths6f5b89a2007-03-02 20:48:00 +000012175#endif
12176
ths4cae1d12007-07-12 11:06:53 +000012177 case TARGET_NR_tkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012178 return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000012179
ths71455572007-06-21 21:45:30 +000012180 case TARGET_NR_tgkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012181 return get_errno(safe_tgkill((int)arg1, (int)arg2,
12182 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +000012183
ths4f2b1fe2007-06-21 21:57:12 +000012184#ifdef TARGET_NR_set_robust_list
12185 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000012186 case TARGET_NR_get_robust_list:
12187 /* The ABI for supporting robust futexes has userspace pass
12188 * the kernel a pointer to a linked list which is updated by
12189 * userspace after the syscall; the list is walked by the kernel
12190 * when the thread exits. Since the linked list in QEMU guest
12191 * memory isn't a valid linked list for the host and we have
12192 * no way to reliably intercept the thread-death event, we can't
12193 * support these. Silently return ENOSYS so that guest userspace
12194 * falls back to a non-robust futex implementation (which should
12195 * be OK except in the corner case of the guest crashing while
12196 * holding a mutex that is shared with another process via
12197 * shared memory).
12198 */
Richard Henderson10f45d92018-08-18 12:01:07 -070012199 return -TARGET_ENOSYS;
ths4f2b1fe2007-06-21 21:57:12 +000012200#endif
12201
Peter Maydell1acae9f2013-07-02 14:04:12 +010012202#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000012203 case TARGET_NR_utimensat:
12204 {
Riku Voipioebc996f2009-04-21 15:01:51 +030012205 struct timespec *tsp, ts[2];
12206 if (!arg3) {
12207 tsp = NULL;
12208 } else {
Filip Bozutab3a3af72020-08-11 13:31:01 +020012209 if (target_to_host_timespec(ts, arg3)) {
12210 return -TARGET_EFAULT;
12211 }
12212 if (target_to_host_timespec(ts + 1, arg3 +
12213 sizeof(struct target_timespec))) {
12214 return -TARGET_EFAULT;
12215 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012216 tsp = ts;
12217 }
ths9007f0e2007-09-25 17:50:37 +000012218 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030012219 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000012220 else {
bellard579a97f2007-11-11 14:26:47 +000012221 if (!(p = lock_user_string(arg2))) {
Richard Henderson259841c2018-08-18 12:01:09 -070012222 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012223 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012224 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000012225 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000012226 }
12227 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012228 return ret;
ths9007f0e2007-09-25 17:50:37 +000012229#endif
Filip Bozutacac46eb2020-08-25 00:30:50 +020012230#ifdef TARGET_NR_utimensat_time64
12231 case TARGET_NR_utimensat_time64:
12232 {
12233 struct timespec *tsp, ts[2];
12234 if (!arg3) {
12235 tsp = NULL;
12236 } else {
12237 if (target_to_host_timespec64(ts, arg3)) {
12238 return -TARGET_EFAULT;
12239 }
12240 if (target_to_host_timespec64(ts + 1, arg3 +
12241 sizeof(struct target__kernel_timespec))) {
12242 return -TARGET_EFAULT;
12243 }
12244 tsp = ts;
12245 }
12246 if (!arg2)
12247 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
12248 else {
12249 p = lock_user_string(arg2);
12250 if (!p) {
12251 return -TARGET_EFAULT;
12252 }
12253 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
12254 unlock_user(p, arg2, 0);
12255 }
12256 }
12257 return ret;
12258#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070012259#ifdef TARGET_NR_futex
pbrookbd0c5662008-05-29 14:34:11 +000012260 case TARGET_NR_futex:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012261 return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
Alistair Francis859e8a82020-03-12 15:13:49 -070012262#endif
Alistair Francis14690292020-03-18 15:47:01 -070012263#ifdef TARGET_NR_futex_time64
12264 case TARGET_NR_futex_time64:
12265 return do_futex_time64(arg1, arg2, arg3, arg4, arg5, arg6);
12266#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012267#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000012268 case TARGET_NR_inotify_init:
12269 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012270 if (ret >= 0) {
12271 fd_trans_register(ret, &target_inotify_trans);
12272 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012273 return ret;
aurel3239b59762008-10-01 21:46:50 +000012274#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012275#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000012276#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
12277 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010012278 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
12279 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012280 if (ret >= 0) {
12281 fd_trans_register(ret, &target_inotify_trans);
12282 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012283 return ret;
Riku Voipioc05c7a72010-03-26 15:25:11 +000012284#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012285#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012286#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012287 case TARGET_NR_inotify_add_watch:
12288 p = lock_user_string(arg2);
12289 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
12290 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012291 return ret;
aurel3239b59762008-10-01 21:46:50 +000012292#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012293#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012294 case TARGET_NR_inotify_rm_watch:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012295 return get_errno(sys_inotify_rm_watch(arg1, arg2));
aurel3239b59762008-10-01 21:46:50 +000012296#endif
ths9007f0e2007-09-25 17:50:37 +000012297
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012298#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012299 case TARGET_NR_mq_open:
12300 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012301 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012302 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012303 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012304
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012305 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012306 pposix_mq_attr = NULL;
12307 if (arg4) {
12308 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012309 return -TARGET_EFAULT;
Lena Djokic26400772016-11-24 17:08:58 +010012310 }
12311 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012312 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012313 p = lock_user_string(arg1 - 1);
12314 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012315 return -TARGET_EFAULT;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012316 }
Lena Djokic26400772016-11-24 17:08:58 +010012317 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012318 unlock_user (p, arg1, 0);
12319 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012320 return ret;
aurel3224e10032009-04-15 16:11:43 +000012321
12322 case TARGET_NR_mq_unlink:
12323 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012324 if (!p) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012325 return -TARGET_EFAULT;
Peter Maydell32112152016-07-12 13:02:13 +010012326 }
aurel3224e10032009-04-15 16:11:43 +000012327 ret = get_errno(mq_unlink(p));
12328 unlock_user (p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012329 return ret;
aurel3224e10032009-04-15 16:11:43 +000012330
Alistair Francis859e8a82020-03-12 15:13:49 -070012331#ifdef TARGET_NR_mq_timedsend
aurel3224e10032009-04-15 16:11:43 +000012332 case TARGET_NR_mq_timedsend:
12333 {
12334 struct timespec ts;
12335
12336 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12337 if (arg5 != 0) {
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012338 if (target_to_host_timespec(&ts, arg5)) {
12339 return -TARGET_EFAULT;
12340 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012341 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012342 if (!is_error(ret) && host_to_target_timespec(arg5, &ts)) {
12343 return -TARGET_EFAULT;
12344 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012345 } else {
12346 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012347 }
aurel3224e10032009-04-15 16:11:43 +000012348 unlock_user (p, arg2, arg3);
12349 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012350 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070012351#endif
Filip Bozutad107e372020-08-24 21:37:52 +020012352#ifdef TARGET_NR_mq_timedsend_time64
12353 case TARGET_NR_mq_timedsend_time64:
12354 {
12355 struct timespec ts;
12356
12357 p = lock_user(VERIFY_READ, arg2, arg3, 1);
12358 if (arg5 != 0) {
12359 if (target_to_host_timespec64(&ts, arg5)) {
12360 return -TARGET_EFAULT;
12361 }
12362 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
12363 if (!is_error(ret) && host_to_target_timespec64(arg5, &ts)) {
12364 return -TARGET_EFAULT;
12365 }
12366 } else {
12367 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
12368 }
12369 unlock_user(p, arg2, arg3);
12370 }
12371 return ret;
12372#endif
aurel3224e10032009-04-15 16:11:43 +000012373
Alistair Francis859e8a82020-03-12 15:13:49 -070012374#ifdef TARGET_NR_mq_timedreceive
aurel3224e10032009-04-15 16:11:43 +000012375 case TARGET_NR_mq_timedreceive:
12376 {
12377 struct timespec ts;
12378 unsigned int prio;
12379
12380 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12381 if (arg5 != 0) {
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012382 if (target_to_host_timespec(&ts, arg5)) {
12383 return -TARGET_EFAULT;
12384 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012385 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12386 &prio, &ts));
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012387 if (!is_error(ret) && host_to_target_timespec(arg5, &ts)) {
12388 return -TARGET_EFAULT;
12389 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012390 } else {
12391 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12392 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000012393 }
aurel3224e10032009-04-15 16:11:43 +000012394 unlock_user (p, arg2, arg3);
12395 if (arg4 != 0)
12396 put_user_u32(prio, arg4);
12397 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012398 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070012399#endif
Filip Bozutad107e372020-08-24 21:37:52 +020012400#ifdef TARGET_NR_mq_timedreceive_time64
12401 case TARGET_NR_mq_timedreceive_time64:
12402 {
12403 struct timespec ts;
12404 unsigned int prio;
12405
12406 p = lock_user(VERIFY_READ, arg2, arg3, 1);
12407 if (arg5 != 0) {
12408 if (target_to_host_timespec64(&ts, arg5)) {
12409 return -TARGET_EFAULT;
12410 }
12411 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12412 &prio, &ts));
12413 if (!is_error(ret) && host_to_target_timespec64(arg5, &ts)) {
12414 return -TARGET_EFAULT;
12415 }
12416 } else {
12417 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12418 &prio, NULL));
12419 }
12420 unlock_user(p, arg2, arg3);
12421 if (arg4 != 0) {
12422 put_user_u32(prio, arg4);
12423 }
12424 }
12425 return ret;
12426#endif
aurel3224e10032009-04-15 16:11:43 +000012427
12428 /* Not implemented for now... */
12429/* case TARGET_NR_mq_notify: */
12430/* break; */
12431
12432 case TARGET_NR_mq_getsetattr:
12433 {
12434 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
12435 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000012436 if (arg2 != 0) {
12437 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070012438 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
12439 &posix_mq_attr_out));
12440 } else if (arg3 != 0) {
12441 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000012442 }
Max Filippova23ea402018-03-31 08:20:15 -070012443 if (ret == 0 && arg3 != 0) {
12444 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
12445 }
aurel3224e10032009-04-15 16:11:43 +000012446 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012447 return ret;
aurel3224e10032009-04-15 16:11:43 +000012448#endif
12449
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012450#ifdef CONFIG_SPLICE
12451#ifdef TARGET_NR_tee
12452 case TARGET_NR_tee:
12453 {
12454 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12455 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012456 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012457#endif
12458#ifdef TARGET_NR_splice
12459 case TARGET_NR_splice:
12460 {
12461 loff_t loff_in, loff_out;
12462 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012463 if (arg2) {
12464 if (get_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012465 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010012466 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012467 ploff_in = &loff_in;
12468 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012469 if (arg4) {
12470 if (get_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012471 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010012472 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012473 ploff_out = &loff_out;
12474 }
12475 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012476 if (arg2) {
12477 if (put_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012478 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010012479 }
12480 }
12481 if (arg4) {
12482 if (put_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012483 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010012484 }
12485 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012486 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012487 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012488#endif
12489#ifdef TARGET_NR_vmsplice
12490 case TARGET_NR_vmsplice:
12491 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012492 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12493 if (vec != NULL) {
12494 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12495 unlock_iovec(vec, arg2, arg3, 0);
12496 } else {
12497 ret = -host_to_target_errno(errno);
12498 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012499 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012500 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012501#endif
12502#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012503#ifdef CONFIG_EVENTFD
12504#if defined(TARGET_NR_eventfd)
12505 case TARGET_NR_eventfd:
12506 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012507 if (ret >= 0) {
12508 fd_trans_register(ret, &target_eventfd_trans);
12509 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012510 return ret;
Riku Voipioc2882b92009-08-12 15:08:24 +030012511#endif
12512#if defined(TARGET_NR_eventfd2)
12513 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012514 {
12515 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12516 if (arg2 & TARGET_O_NONBLOCK) {
12517 host_flags |= O_NONBLOCK;
12518 }
12519 if (arg2 & TARGET_O_CLOEXEC) {
12520 host_flags |= O_CLOEXEC;
12521 }
12522 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012523 if (ret >= 0) {
12524 fd_trans_register(ret, &target_eventfd_trans);
12525 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012526 return ret;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012527 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012528#endif
12529#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012530#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12531 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012532#if TARGET_ABI_BITS == 32
12533 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12534 target_offset64(arg5, arg6)));
12535#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012536 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012537#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012538 return ret;
Ulrich Hechtd0927932009-09-17 20:22:14 +030012539#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012540#if defined(CONFIG_SYNC_FILE_RANGE)
12541#if defined(TARGET_NR_sync_file_range)
12542 case TARGET_NR_sync_file_range:
12543#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012544#if defined(TARGET_MIPS)
12545 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12546 target_offset64(arg5, arg6), arg7));
12547#else
Peter Maydellc727f472011-01-06 11:05:10 +000012548 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12549 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012550#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012551#else
12552 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12553#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012554 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000012555#endif
Laurent Vivier5bcb4982020-03-10 11:33:50 +010012556#if defined(TARGET_NR_sync_file_range2) || \
12557 defined(TARGET_NR_arm_sync_file_range)
Peter Maydellc727f472011-01-06 11:05:10 +000012558#if defined(TARGET_NR_sync_file_range2)
12559 case TARGET_NR_sync_file_range2:
Laurent Vivier5bcb4982020-03-10 11:33:50 +010012560#endif
12561#if defined(TARGET_NR_arm_sync_file_range)
12562 case TARGET_NR_arm_sync_file_range:
12563#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012564 /* This is like sync_file_range but the arguments are reordered */
12565#if TARGET_ABI_BITS == 32
12566 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12567 target_offset64(arg5, arg6), arg2));
12568#else
12569 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12570#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012571 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000012572#endif
12573#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012574#if defined(TARGET_NR_signalfd4)
12575 case TARGET_NR_signalfd4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012576 return do_signalfd4(arg1, arg2, arg4);
Laurent Viviere36800c2015-10-02 14:48:09 +020012577#endif
12578#if defined(TARGET_NR_signalfd)
12579 case TARGET_NR_signalfd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012580 return do_signalfd4(arg1, arg2, 0);
Laurent Viviere36800c2015-10-02 14:48:09 +020012581#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012582#if defined(CONFIG_EPOLL)
12583#if defined(TARGET_NR_epoll_create)
12584 case TARGET_NR_epoll_create:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012585 return get_errno(epoll_create(arg1));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012586#endif
12587#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12588 case TARGET_NR_epoll_create1:
Sergei Trofimovich386d3862020-04-15 23:05:08 +010012589 return get_errno(epoll_create1(target_to_host_bitmask(arg1, fcntl_flags_tbl)));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012590#endif
12591#if defined(TARGET_NR_epoll_ctl)
12592 case TARGET_NR_epoll_ctl:
12593 {
12594 struct epoll_event ep;
12595 struct epoll_event *epp = 0;
12596 if (arg4) {
12597 struct target_epoll_event *target_ep;
12598 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012599 return -TARGET_EFAULT;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012600 }
12601 ep.events = tswap32(target_ep->events);
12602 /* The epoll_data_t union is just opaque data to the kernel,
12603 * so we transfer all 64 bits across and need not worry what
12604 * actual data type it is.
12605 */
12606 ep.data.u64 = tswap64(target_ep->data.u64);
12607 unlock_user_struct(target_ep, arg4, 0);
12608 epp = &ep;
12609 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012610 return get_errno(epoll_ctl(arg1, arg2, arg3, epp));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012611 }
12612#endif
12613
Peter Maydell227f0212016-06-06 19:58:11 +010012614#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012615#if defined(TARGET_NR_epoll_wait)
12616 case TARGET_NR_epoll_wait:
12617#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012618#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012619 case TARGET_NR_epoll_pwait:
12620#endif
12621 {
12622 struct target_epoll_event *target_ep;
12623 struct epoll_event *ep;
12624 int epfd = arg1;
12625 int maxevents = arg3;
12626 int timeout = arg4;
12627
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012628 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012629 return -TARGET_EINVAL;
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012630 }
12631
Peter Maydell3b6edd12011-02-15 18:35:05 +000012632 target_ep = lock_user(VERIFY_WRITE, arg2,
12633 maxevents * sizeof(struct target_epoll_event), 1);
12634 if (!target_ep) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012635 return -TARGET_EFAULT;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012636 }
12637
Peter Maydell04c95f42016-07-18 15:36:00 +010012638 ep = g_try_new(struct epoll_event, maxevents);
12639 if (!ep) {
12640 unlock_user(target_ep, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012641 return -TARGET_ENOMEM;
Peter Maydell04c95f42016-07-18 15:36:00 +010012642 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012643
12644 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012645#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012646 case TARGET_NR_epoll_pwait:
12647 {
12648 target_sigset_t *target_set;
12649 sigset_t _set, *set = &_set;
12650
12651 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012652 if (arg6 != sizeof(target_sigset_t)) {
12653 ret = -TARGET_EINVAL;
12654 break;
12655 }
12656
Peter Maydell3b6edd12011-02-15 18:35:05 +000012657 target_set = lock_user(VERIFY_READ, arg5,
12658 sizeof(target_sigset_t), 1);
12659 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012660 ret = -TARGET_EFAULT;
12661 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012662 }
12663 target_to_host_sigset(set, target_set);
12664 unlock_user(target_set, arg5, 0);
12665 } else {
12666 set = NULL;
12667 }
12668
Peter Maydell227f0212016-06-06 19:58:11 +010012669 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12670 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012671 break;
12672 }
12673#endif
12674#if defined(TARGET_NR_epoll_wait)
12675 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012676 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12677 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012678 break;
12679#endif
12680 default:
12681 ret = -TARGET_ENOSYS;
12682 }
12683 if (!is_error(ret)) {
12684 int i;
12685 for (i = 0; i < ret; i++) {
12686 target_ep[i].events = tswap32(ep[i].events);
12687 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12688 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012689 unlock_user(target_ep, arg2,
12690 ret * sizeof(struct target_epoll_event));
12691 } else {
12692 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012693 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012694 g_free(ep);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012695 return ret;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012696 }
12697#endif
12698#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012699#ifdef TARGET_NR_prlimit64
12700 case TARGET_NR_prlimit64:
12701 {
12702 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12703 struct target_rlimit64 *target_rnew, *target_rold;
12704 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012705 int resource = target_to_host_resource(arg2);
Tobias Koch055d92f2020-03-05 21:24:00 +010012706
12707 if (arg3 && (resource != RLIMIT_AS &&
12708 resource != RLIMIT_DATA &&
12709 resource != RLIMIT_STACK)) {
Peter Maydell163a05a2011-06-27 17:44:52 +010012710 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012711 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010012712 }
12713 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12714 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12715 unlock_user_struct(target_rnew, arg3, 0);
12716 rnewp = &rnew;
12717 }
12718
Felix Janda95018012014-12-02 22:11:17 +010012719 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012720 if (!is_error(ret) && arg4) {
12721 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012722 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010012723 }
12724 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12725 target_rold->rlim_max = tswap64(rold.rlim_max);
12726 unlock_user_struct(target_rold, arg4, 1);
12727 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012728 return ret;
Peter Maydell163a05a2011-06-27 17:44:52 +010012729 }
12730#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012731#ifdef TARGET_NR_gethostname
12732 case TARGET_NR_gethostname:
12733 {
12734 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12735 if (name) {
12736 ret = get_errno(gethostname(name, arg2));
12737 unlock_user(name, arg1, arg2);
12738 } else {
12739 ret = -TARGET_EFAULT;
12740 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012741 return ret;
Richard Henderson3d21d292012-09-15 13:20:46 -070012742 }
12743#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012744#ifdef TARGET_NR_atomic_cmpxchg_32
12745 case TARGET_NR_atomic_cmpxchg_32:
12746 {
12747 /* should use start_exclusive from main.c */
12748 abi_ulong mem_value;
12749 if (get_user_u32(mem_value, arg6)) {
12750 target_siginfo_t info;
12751 info.si_signo = SIGSEGV;
12752 info.si_errno = 0;
12753 info.si_code = TARGET_SEGV_MAPERR;
12754 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012755 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12756 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012757 ret = 0xdeadbeef;
12758
12759 }
12760 if (mem_value == arg2)
12761 put_user_u32(arg1, arg6);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012762 return mem_value;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012763 }
12764#endif
12765#ifdef TARGET_NR_atomic_barrier
12766 case TARGET_NR_atomic_barrier:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012767 /* Like the kernel implementation and the
12768 qemu arm barrier, no-op this? */
12769 return 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012770#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012771
12772#ifdef TARGET_NR_timer_create
12773 case TARGET_NR_timer_create:
12774 {
12775 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12776
12777 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012778
12779 int clkid = arg1;
12780 int timer_index = next_free_host_timer();
12781
12782 if (timer_index < 0) {
12783 ret = -TARGET_EAGAIN;
12784 } else {
12785 timer_t *phtimer = g_posix_timers + timer_index;
12786
12787 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012788 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012789 ret = target_to_host_sigevent(phost_sevp, arg2);
12790 if (ret != 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012791 return ret;
Peter Maydellc0659762014-08-09 15:42:32 +010012792 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012793 }
12794
12795 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12796 if (ret) {
12797 phtimer = NULL;
12798 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012799 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012800 return -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012801 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012802 }
12803 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012804 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012805 }
12806#endif
12807
12808#ifdef TARGET_NR_timer_settime
12809 case TARGET_NR_timer_settime:
12810 {
12811 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12812 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012813 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012814
Alexander Grafaecc8862014-11-10 21:33:03 +010012815 if (timerid < 0) {
12816 ret = timerid;
12817 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012818 ret = -TARGET_EINVAL;
12819 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012820 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012821 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12822
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012823 if (target_to_host_itimerspec(&hspec_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012824 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012825 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012826 ret = get_errno(
12827 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012828 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012829 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012830 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012831 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012832 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012833 }
12834#endif
12835
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012836#ifdef TARGET_NR_timer_settime64
12837 case TARGET_NR_timer_settime64:
12838 {
12839 target_timer_t timerid = get_timer_id(arg1);
12840
12841 if (timerid < 0) {
12842 ret = timerid;
12843 } else if (arg3 == 0) {
12844 ret = -TARGET_EINVAL;
12845 } else {
12846 timer_t htimer = g_posix_timers[timerid];
12847 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12848
12849 if (target_to_host_itimerspec64(&hspec_new, arg3)) {
12850 return -TARGET_EFAULT;
12851 }
12852 ret = get_errno(
12853 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
12854 if (arg4 && host_to_target_itimerspec64(arg4, &hspec_old)) {
12855 return -TARGET_EFAULT;
12856 }
12857 }
12858 return ret;
12859 }
12860#endif
12861
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012862#ifdef TARGET_NR_timer_gettime
12863 case TARGET_NR_timer_gettime:
12864 {
12865 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012866 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012867
Alexander Grafaecc8862014-11-10 21:33:03 +010012868 if (timerid < 0) {
12869 ret = timerid;
12870 } else if (!arg2) {
12871 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012872 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012873 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012874 struct itimerspec hspec;
12875 ret = get_errno(timer_gettime(htimer, &hspec));
12876
12877 if (host_to_target_itimerspec(arg2, &hspec)) {
12878 ret = -TARGET_EFAULT;
12879 }
12880 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012881 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012882 }
12883#endif
12884
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012885#ifdef TARGET_NR_timer_gettime64
12886 case TARGET_NR_timer_gettime64:
12887 {
12888 /* args: timer_t timerid, struct itimerspec64 *curr_value */
12889 target_timer_t timerid = get_timer_id(arg1);
12890
12891 if (timerid < 0) {
12892 ret = timerid;
12893 } else if (!arg2) {
12894 ret = -TARGET_EFAULT;
12895 } else {
12896 timer_t htimer = g_posix_timers[timerid];
12897 struct itimerspec hspec;
12898 ret = get_errno(timer_gettime(htimer, &hspec));
12899
12900 if (host_to_target_itimerspec64(arg2, &hspec)) {
12901 ret = -TARGET_EFAULT;
12902 }
12903 }
12904 return ret;
12905 }
12906#endif
12907
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012908#ifdef TARGET_NR_timer_getoverrun
12909 case TARGET_NR_timer_getoverrun:
12910 {
12911 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012912 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012913
Alexander Grafaecc8862014-11-10 21:33:03 +010012914 if (timerid < 0) {
12915 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012916 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012917 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012918 ret = get_errno(timer_getoverrun(htimer));
12919 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012920 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012921 }
12922#endif
12923
12924#ifdef TARGET_NR_timer_delete
12925 case TARGET_NR_timer_delete:
12926 {
12927 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012928 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012929
Alexander Grafaecc8862014-11-10 21:33:03 +010012930 if (timerid < 0) {
12931 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012932 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012933 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012934 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012935 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012936 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012937 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012938 }
12939#endif
12940
Riku Voipio51834342014-06-22 11:25:42 +010012941#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12942 case TARGET_NR_timerfd_create:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012943 return get_errno(timerfd_create(arg1,
12944 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
Riku Voipio51834342014-06-22 11:25:42 +010012945#endif
12946
12947#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12948 case TARGET_NR_timerfd_gettime:
12949 {
12950 struct itimerspec its_curr;
12951
12952 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12953
12954 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012955 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010012956 }
12957 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012958 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010012959#endif
12960
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012961#if defined(TARGET_NR_timerfd_gettime64) && defined(CONFIG_TIMERFD)
12962 case TARGET_NR_timerfd_gettime64:
12963 {
12964 struct itimerspec its_curr;
12965
12966 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12967
12968 if (arg2 && host_to_target_itimerspec64(arg2, &its_curr)) {
12969 return -TARGET_EFAULT;
12970 }
12971 }
12972 return ret;
12973#endif
12974
Riku Voipio51834342014-06-22 11:25:42 +010012975#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12976 case TARGET_NR_timerfd_settime:
12977 {
12978 struct itimerspec its_new, its_old, *p_new;
12979
12980 if (arg3) {
12981 if (target_to_host_itimerspec(&its_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012982 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010012983 }
12984 p_new = &its_new;
12985 } else {
12986 p_new = NULL;
12987 }
12988
12989 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12990
12991 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012992 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010012993 }
12994 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012995 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010012996#endif
12997
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012998#if defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD)
12999 case TARGET_NR_timerfd_settime64:
13000 {
13001 struct itimerspec its_new, its_old, *p_new;
13002
13003 if (arg3) {
13004 if (target_to_host_itimerspec64(&its_new, arg3)) {
13005 return -TARGET_EFAULT;
13006 }
13007 p_new = &its_new;
13008 } else {
13009 p_new = NULL;
13010 }
13011
13012 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
13013
13014 if (arg4 && host_to_target_itimerspec64(arg4, &its_old)) {
13015 return -TARGET_EFAULT;
13016 }
13017 }
13018 return ret;
13019#endif
13020
Paul Burtonab31cda2014-06-22 11:25:43 +010013021#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
13022 case TARGET_NR_ioprio_get:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013023 return get_errno(ioprio_get(arg1, arg2));
Paul Burtonab31cda2014-06-22 11:25:43 +010013024#endif
13025
13026#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
13027 case TARGET_NR_ioprio_set:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013028 return get_errno(ioprio_set(arg1, arg2, arg3));
Paul Burtonab31cda2014-06-22 11:25:43 +010013029#endif
13030
Riku Voipio9af5c902014-08-12 15:58:57 +030013031#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
13032 case TARGET_NR_setns:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013033 return get_errno(setns(arg1, arg2));
Riku Voipio9af5c902014-08-12 15:58:57 +030013034#endif
13035#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
13036 case TARGET_NR_unshare:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013037 return get_errno(unshare(arg1));
Riku Voipio9af5c902014-08-12 15:58:57 +030013038#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020013039#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
13040 case TARGET_NR_kcmp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013041 return get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
Laurent Vivier2f147882016-09-25 22:20:20 +020013042#endif
Richard Hendersonfa97e382018-07-18 13:06:48 -070013043#ifdef TARGET_NR_swapcontext
13044 case TARGET_NR_swapcontext:
13045 /* PowerPC specific. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013046 return do_swapcontext(cpu_env, arg1, arg2, arg3);
Richard Hendersonfa97e382018-07-18 13:06:48 -070013047#endif
Shu-Chun Weng9bdfa4d2019-08-19 11:09:47 -070013048#ifdef TARGET_NR_memfd_create
13049 case TARGET_NR_memfd_create:
13050 p = lock_user_string(arg1);
13051 if (!p) {
13052 return -TARGET_EFAULT;
13053 }
13054 ret = get_errno(memfd_create(p, arg2));
13055 fd_trans_unregister(ret);
13056 unlock_user(p, arg1, 0);
13057 return ret;
13058#endif
Andreas Schwab85004762019-05-13 11:02:53 +020013059#if defined TARGET_NR_membarrier && defined __NR_membarrier
13060 case TARGET_NR_membarrier:
13061 return get_errno(membarrier(arg1, arg2));
13062#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030013063
bellard31e31b82003-02-18 22:55:36 +000013064 default:
Philippe Mathieu-Daudé122f9c82018-07-06 12:51:25 -030013065 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013066 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000013067 }
bellard31e31b82003-02-18 22:55:36 +000013068 return ret;
13069}
Richard Hendersondc1ce182018-08-18 12:01:04 -070013070
13071abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
13072 abi_long arg2, abi_long arg3, abi_long arg4,
13073 abi_long arg5, abi_long arg6, abi_long arg7,
13074 abi_long arg8)
13075{
Richard Henderson29a0af62019-03-22 16:07:18 -070013076 CPUState *cpu = env_cpu(cpu_env);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013077 abi_long ret;
13078
13079#ifdef DEBUG_ERESTARTSYS
13080 /* Debug-only code for exercising the syscall-restart code paths
13081 * in the per-architecture cpu main loops: restart every syscall
13082 * the guest makes once before letting it through.
13083 */
13084 {
13085 static bool flag;
13086 flag = !flag;
13087 if (flag) {
13088 return -TARGET_ERESTARTSYS;
13089 }
13090 }
13091#endif
13092
Emilio G. Cotac36f7a62018-10-21 13:27:44 -040013093 record_syscall_start(cpu, num, arg1,
13094 arg2, arg3, arg4, arg5, arg6, arg7, arg8);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013095
Josh Kunz4b25a502020-02-03 18:54:14 -080013096 if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
Filip Bozutae400e112020-08-11 18:45:49 +020013097 print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6);
Josh Kunz4b25a502020-02-03 18:54:14 -080013098 }
13099
13100 ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
13101 arg5, arg6, arg7, arg8);
13102
13103 if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
Filip Bozutae400e112020-08-11 18:45:49 +020013104 print_syscall_ret(cpu_env, num, ret, arg1, arg2,
13105 arg3, arg4, arg5, arg6);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013106 }
13107
Emilio G. Cotac36f7a62018-10-21 13:27:44 -040013108 record_syscall_return(cpu, num, ret);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013109 return ret;
13110}