blob: a666986189488fcd0d1c4c5a741ffa3a2be2ec6c [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"
Richard Henderson720ace22023-03-15 17:43:14 +000025#include "qemu/plugin.h"
Richard Hendersond7ec12f2023-09-29 19:54:54 -070026#include "tcg/startup.h"
Helge Dellerfe080592022-12-15 08:27:46 +010027#include "target_mman.h"
Philippe Mathieu-Daudé74781c02023-12-06 20:27:32 +010028#include "exec/page-protection.h"
bellard31e31b82003-02-18 22:55:36 +000029#include <elf.h>
30#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010031#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000032#include <sys/ipc.h>
33#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010036#include <sys/file.h>
37#include <sys/fsuid.h>
38#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000039#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000040#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000041#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000042#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sched.h>
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020044#include <sys/timex.h>
bellard31e31b82003-02-18 22:55:36 +000045#include <sys/socket.h>
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +020046#include <linux/sockios.h>
aurel32607175e2009-04-15 16:11:59 +000047#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000048#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040049#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000050#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000051#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000052#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000053#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000054#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000055#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020056#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000057//#include <sys/user.h>
Shu-Chun Weng22db1212020-12-18 11:32:12 -080058#include <netinet/in.h>
bellard8853f862004-02-22 14:57:26 +000059#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000060#include <netinet/tcp.h>
Shu-Chun Wengfe51b0a2020-12-18 11:32:11 -080061#include <netinet/udp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020062#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000063#include <linux/icmp.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010064#include <linux/icmpv6.h>
Shu-Chun Weng6addf062020-09-28 18:48:01 -070065#include <linux/if_tun.h>
Shu-Chun Weng22db1212020-12-18 11:32:12 -080066#include <linux/in6.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010067#include <linux/errqueue.h>
Marco A L Barbosad6d6d6f2017-10-05 10:55:30 -030068#include <linux/random.h>
Riku Voipiod80a1902014-10-01 16:05:46 +030069#ifdef CONFIG_TIMERFD
70#include <sys/timerfd.h>
71#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030072#ifdef CONFIG_EVENTFD
73#include <sys/eventfd.h>
74#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000075#ifdef CONFIG_EPOLL
76#include <sys/epoll.h>
77#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070078#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010079#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070080#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000081#ifdef CONFIG_SENDFILE
82#include <sys/sendfile.h>
83#endif
Thomas Huth4a9d5f82020-11-18 18:10:51 +010084#ifdef HAVE_SYS_KCOV_H
Aleksandar Markovicbd27e672020-01-16 23:49:50 +010085#include <sys/kcov.h>
86#endif
bellard31e31b82003-02-18 22:55:36 +000087
88#define termios host_termios
89#define winsize host_winsize
90#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000091#define sgttyb host_sgttyb /* same as target */
92#define tchars host_tchars /* same as target */
93#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000094
95#include <linux/termios.h>
96#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000097#include <linux/cdrom.h>
98#include <linux/hdreg.h>
99#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +0000100#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +0000101#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300102#include <linux/fs.h>
Yunqiang Suab22b4d2019-09-04 14:59:24 +0200103#include <linux/fd.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000104#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000105#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000106#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200107#include <linux/fb.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -0700108#if defined(CONFIG_USBFS)
109#include <linux/usbdevice_fs.h>
Cortland Tölvaa1333672018-10-08 09:35:21 -0700110#include <linux/usb/ch9.h>
Cortland Tölva6c753a62018-10-08 09:35:20 -0700111#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200112#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100113#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000114#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100115#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200116#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100117#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200118#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200119#include <linux/netlink.h>
Yunqiang Suf31dddd2019-06-19 16:17:11 +0200120#include <linux/if_alg.h>
Filip Bozuta68365f92020-01-15 20:36:35 +0100121#include <linux/rtc.h>
Filip Bozuta1c4c6fc2020-01-15 20:36:41 +0100122#include <sound/asound.h>
Thomas Huth48f670e2020-11-18 18:10:52 +0100123#ifdef HAVE_BTRFS_H
Filip Bozutad6092e02020-08-23 21:50:07 +0200124#include <linux/btrfs.h>
125#endif
Chen Gange865b972020-06-05 09:32:21 +0800126#ifdef HAVE_DRM_H
127#include <libdrm/drm.h>
Chen Gang913b03c2020-08-02 21:39:38 +0800128#include <libdrm/i915_drm.h>
Chen Gange865b972020-06-05 09:32:21 +0800129#endif
pbrookd7e40362008-05-23 16:06:43 +0000130#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200131#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000132
bellard3ef693a2003-03-23 20:17:16 +0000133#include "qemu.h"
Peter Maydell3b249d22021-09-08 16:44:03 +0100134#include "user-internals.h"
Peter Maydella44d57a2021-09-08 16:43:58 +0100135#include "strace.h"
Peter Maydell2113aed2021-09-08 16:43:59 +0100136#include "signal-common.h"
Peter Maydell3ad0a762021-09-08 16:44:00 +0100137#include "loader.h"
Peter Maydell5423e6d2021-09-08 16:44:01 +0100138#include "user-mmap.h"
Richard Hendersonbbf15aa2021-11-17 16:14:00 +0100139#include "user/safe-syscall.h"
Richard Henderson5ebdd772019-03-14 13:10:53 -0700140#include "qemu/guest-random.h"
Alex Bennée01ef6b92020-04-03 20:11:46 +0100141#include "qemu/selfmap.h"
Emilio G. Cotac36f7a62018-10-21 13:27:44 -0400142#include "user/syscall-trace.h"
Richard Henderson5da40632021-11-17 15:46:05 +0100143#include "special-errno.h"
Richard Henderson51977e22019-03-12 19:22:20 -0700144#include "qapi/error.h"
Laurent Vivierf7e6a402018-08-24 00:22:15 +0200145#include "fd-trans.h"
Helge Dellerbd5ccd62022-10-24 22:18:09 +0200146#include "cpu_loop-common.h"
bellard31e31b82003-02-18 22:55:36 +0000147
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100148#ifndef CLONE_IO
149#define CLONE_IO 0x80000000 /* Clone io context */
150#endif
151
152/* We can't directly call the host clone syscall, because this will
153 * badly confuse libc (breaking mutexes, for example). So we must
154 * divide clone flags into:
155 * * flag combinations that look like pthread_create()
156 * * flag combinations that look like fork()
157 * * flags we can implement within QEMU itself
158 * * flags we can't support and will return an error for
159 */
160/* For thread creation, all these flags must be present; for
161 * fork, none must be present.
162 */
163#define CLONE_THREAD_FLAGS \
164 (CLONE_VM | CLONE_FS | CLONE_FILES | \
165 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
166
167/* These flags are ignored:
168 * CLONE_DETACHED is now ignored by the kernel;
169 * CLONE_IO is just an optimisation hint to the I/O scheduler
170 */
171#define CLONE_IGNORED_FLAGS \
172 (CLONE_DETACHED | CLONE_IO)
173
Helge Deller895ce8b2022-11-29 12:08:20 +0100174#ifndef CLONE_PIDFD
175# define CLONE_PIDFD 0x00001000
176#endif
177
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100178/* Flags for fork which we can implement within QEMU itself */
179#define CLONE_OPTIONAL_FORK_FLAGS \
Helge Deller895ce8b2022-11-29 12:08:20 +0100180 (CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100181 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
182
183/* Flags for thread creation which we can implement within QEMU itself */
184#define CLONE_OPTIONAL_THREAD_FLAGS \
185 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
186 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
187
188#define CLONE_INVALID_FORK_FLAGS \
189 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
190
191#define CLONE_INVALID_THREAD_FLAGS \
192 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
193 CLONE_IGNORED_FLAGS))
194
195/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
196 * have almost all been allocated. We cannot support any of
197 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
198 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
199 * The checks against the invalid thread masks above will catch these.
200 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
201 */
pbrook30813ce2008-06-02 15:45:44 +0000202
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100203/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
204 * once. This exercises the codepaths for restart.
205 */
206//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000207
bellard1a9353d2003-03-16 20:28:50 +0000208//#include <linux/msdos_fs.h>
Richard Henderson540a7362021-11-14 11:35:37 +0100209#define VFAT_IOCTL_READDIR_BOTH \
210 _IOC(_IOC_READ, 'r', 1, (sizeof(struct linux_dirent) + 256) * 2)
211#define VFAT_IOCTL_READDIR_SHORT \
212 _IOC(_IOC_READ, 'r', 2, (sizeof(struct linux_dirent) + 256) * 2)
bellard1a9353d2003-03-16 20:28:50 +0000213
bellard70a194b2003-08-11 22:20:16 +0000214#undef _syscall0
215#undef _syscall1
216#undef _syscall2
217#undef _syscall3
218#undef _syscall4
219#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000220#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000221
bellard83fcb512006-06-14 13:37:16 +0000222#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000223static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000224{ \
225 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000226}
227
bellard83fcb512006-06-14 13:37:16 +0000228#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000229static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000230{ \
231 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000232}
233
bellard83fcb512006-06-14 13:37:16 +0000234#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000235static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000236{ \
237 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000238}
239
bellard83fcb512006-06-14 13:37:16 +0000240#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000241static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000242{ \
243 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000244}
245
bellard83fcb512006-06-14 13:37:16 +0000246#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000247static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000248{ \
249 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000250}
251
bellard83fcb512006-06-14 13:37:16 +0000252#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
253 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000254static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000255{ \
256 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000257}
bellard83fcb512006-06-14 13:37:16 +0000258
259
260#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
261 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000262static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
263 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000264{ \
265 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
266}
267
bellard70a194b2003-08-11 22:20:16 +0000268
bellard31e31b82003-02-18 22:55:36 +0000269#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000270#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000271#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000272#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000273#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000274#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200275#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000276#define __NR_sys_syslog __NR_syslog
Alistair Francis14690292020-03-18 15:47:01 -0700277#if defined(__NR_futex)
278# define __NR_sys_futex __NR_futex
279#endif
280#if defined(__NR_futex_time64)
281# define __NR_sys_futex_time64 __NR_futex_time64
282#endif
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200283#define __NR_sys_statx __NR_statx
bellard31e31b82003-02-18 22:55:36 +0000284
Peter Maydellb1cef6d2018-01-25 16:19:49 +0000285#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000286#define __NR__llseek __NR_lseek
287#endif
288
James Hogana29e5ba2014-03-25 21:51:08 +0000289/* Newer kernel ports have llseek() instead of _llseek() */
290#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
291#define TARGET_NR__llseek TARGET_NR_llseek
292#endif
293
Helge Deller78721302021-02-10 07:12:14 +0100294/* some platforms need to mask more bits than just TARGET_O_NONBLOCK */
295#ifndef TARGET_O_NONBLOCK_MASK
296#define TARGET_O_NONBLOCK_MASK TARGET_O_NONBLOCK
297#endif
298
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +0000299#define __NR_sys_gettid __NR_gettid
300_syscall0(int, sys_gettid)
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100301
302/* For the 64-bit guest on 32-bit host case we must emulate
303 * getdents using getdents64, because otherwise the host
304 * might hand us back more dirent records than we can fit
305 * into the guest buffer after structure format conversion.
306 * Otherwise we emulate getdents with getdents if the host has it.
307 */
308#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
309#define EMULATE_GETDENTS_WITH_GETDENTS
310#endif
311
312#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
Juan Quintelaac42f442023-07-09 18:34:30 +0100313_syscall3(int, sys_getdents, unsigned int, fd, struct linux_dirent *, dirp, unsigned int, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100314#endif
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100315#if (defined(TARGET_NR_getdents) && \
316 !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
Peter Maydell3307e232013-06-12 16:20:21 +0100317 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
Juan Quintelaac42f442023-07-09 18:34:30 +0100318_syscall3(int, sys_getdents64, unsigned int, fd, struct linux_dirent64 *, dirp, unsigned int, count);
aurel323b3f24a2009-04-15 16:12:13 +0000319#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700320#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
Juan Quintelaac42f442023-07-09 18:34:30 +0100321_syscall5(int, _llseek, unsigned int, fd, unsigned long, hi, unsigned long, lo,
322 loff_t *, res, unsigned int, wh);
aurel323b3f24a2009-04-15 16:12:13 +0000323#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200324_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200325_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
326 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000327_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000328#ifdef __NR_exit_group
329_syscall1(int,exit_group,int,error_code)
330#endif
Helge Delleraf804f32022-10-25 04:34:14 +0200331#if defined(__NR_close_range) && defined(TARGET_NR_close_range)
332#define __NR_sys_close_range __NR_close_range
333_syscall3(int,sys_close_range,int,first,int,last,int,flags)
334#ifndef CLOSE_RANGE_CLOEXEC
335#define CLOSE_RANGE_CLOEXEC (1U << 2)
336#endif
337#endif
Alistair Francis14690292020-03-18 15:47:01 -0700338#if defined(__NR_futex)
aurel323b3f24a2009-04-15 16:12:13 +0000339_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
340 const struct timespec *,timeout,int *,uaddr2,int,val3)
341#endif
Alistair Francis14690292020-03-18 15:47:01 -0700342#if defined(__NR_futex_time64)
343_syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val,
344 const struct timespec *,timeout,int *,uaddr2,int,val3)
345#endif
Helge Dellercc054c62022-09-18 21:45:46 +0200346#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
347_syscall2(int, pidfd_open, pid_t, pid, unsigned int, flags);
348#endif
349#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal)
350_syscall4(int, pidfd_send_signal, int, pidfd, int, sig, siginfo_t *, info,
351 unsigned int, flags);
352#endif
353#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd)
354_syscall3(int, pidfd_getfd, int, pidfd, int, targetfd, unsigned int, flags);
355#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500356#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
357_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
358 unsigned long *, user_mask_ptr);
359#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
360_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
361 unsigned long *, user_mask_ptr);
Tonis Tiigi45ad7612022-01-04 20:18:18 -0800362/* sched_attr is not defined in glibc */
363struct sched_attr {
364 uint32_t size;
365 uint32_t sched_policy;
366 uint64_t sched_flags;
367 int32_t sched_nice;
368 uint32_t sched_priority;
369 uint64_t sched_runtime;
370 uint64_t sched_deadline;
371 uint64_t sched_period;
372 uint32_t sched_util_min;
373 uint32_t sched_util_max;
374};
375#define __NR_sys_sched_getattr __NR_sched_getattr
376_syscall4(int, sys_sched_getattr, pid_t, pid, struct sched_attr *, attr,
377 unsigned int, size, unsigned int, flags);
378#define __NR_sys_sched_setattr __NR_sched_setattr
379_syscall3(int, sys_sched_setattr, pid_t, pid, struct sched_attr *, attr,
380 unsigned int, flags);
Tonis Tiigi407a1192022-01-04 20:18:19 -0800381#define __NR_sys_sched_getscheduler __NR_sched_getscheduler
382_syscall1(int, sys_sched_getscheduler, pid_t, pid);
383#define __NR_sys_sched_setscheduler __NR_sched_setscheduler
384_syscall3(int, sys_sched_setscheduler, pid_t, pid, int, policy,
385 const struct sched_param *, param);
386#define __NR_sys_sched_getparam __NR_sched_getparam
387_syscall2(int, sys_sched_getparam, pid_t, pid,
388 struct sched_param *, param);
389#define __NR_sys_sched_setparam __NR_sched_setparam
390_syscall2(int, sys_sched_setparam, pid_t, pid,
391 const struct sched_param *, param);
Samuel Thibaultb827c3e2018-01-12 09:14:35 +0100392#define __NR_sys_getcpu __NR_getcpu
393_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200394_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
395 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000396_syscall2(int, capget, struct __user_cap_header_struct *, header,
397 struct __user_cap_data_struct *, data);
398_syscall2(int, capset, struct __user_cap_header_struct *, header,
399 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100400#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
401_syscall2(int, ioprio_get, int, which, int, who)
402#endif
403#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
404_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
405#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100406#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
407_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
408#endif
aurel323b3f24a2009-04-15 16:12:13 +0000409
Laurent Vivier2f147882016-09-25 22:20:20 +0200410#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
411_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
412 unsigned long, idx1, unsigned long, idx2)
413#endif
414
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200415/*
416 * It is assumed that struct statx is architecture independent.
417 */
418#if defined(TARGET_NR_statx) && defined(__NR_statx)
419_syscall5(int, sys_statx, int, dirfd, const char *, pathname, int, flags,
420 unsigned int, mask, struct target_statx *, statxbuf)
421#endif
Andreas Schwab85004762019-05-13 11:02:53 +0200422#if defined(TARGET_NR_membarrier) && defined(__NR_membarrier)
423_syscall2(int, membarrier, int, cmd, int, flags)
424#endif
Aleksandar Rikaloefa92182019-06-28 12:43:34 +0200425
Philippe Mathieu-Daudé180d4ef2021-05-17 07:52:43 +0200426static const bitmask_transtbl fcntl_flags_tbl[] = {
aurel323b3f24a2009-04-15 16:12:13 +0000427 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
428 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
429 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
430 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
431 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
432 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
433 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
434 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700435 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000436 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
437 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
438 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
439 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000440#if defined(O_DIRECT)
441 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
442#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700443#if defined(O_NOATIME)
444 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
445#endif
446#if defined(O_CLOEXEC)
447 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
448#endif
449#if defined(O_PATH)
450 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
451#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300452#if defined(O_TMPFILE)
453 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
454#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700455 /* Don't terminate the list prematurely on 64-bit host+guest. */
456#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
457 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
458#endif
aurel323b3f24a2009-04-15 16:12:13 +0000459};
460
Andreas Schwab0f6bb192020-07-23 12:27:13 +0200461_syscall2(int, sys_getcwd1, char *, buf, size_t, size)
aurel323b3f24a2009-04-15 16:12:13 +0000462
Filip Bozutacac46eb2020-08-25 00:30:50 +0200463#if defined(TARGET_NR_utimensat) || defined(TARGET_NR_utimensat_time64)
Peter Maydell700fa582016-07-18 11:47:55 +0100464#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100465#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000466_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
467 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100468#else
469static int sys_utimensat(int dirfd, const char *pathname,
470 const struct timespec times[2], int flags)
471{
472 errno = ENOSYS;
473 return -1;
474}
ths9007f0e2007-09-25 17:50:37 +0000475#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100476#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000477
Andreas Schwab95d03072018-01-23 11:53:31 +0100478#ifdef TARGET_NR_renameat2
479#if defined(__NR_renameat2)
480#define __NR_sys_renameat2 __NR_renameat2
481_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
482 const char *, new, unsigned int, flags)
483#else
484static int sys_renameat2(int oldfd, const char *old,
485 int newfd, const char *new, int flags)
486{
487 if (flags == 0) {
488 return renameat(oldfd, old, newfd, new);
489 }
490 errno = ENOSYS;
491 return -1;
492}
493#endif
494#endif /* TARGET_NR_renameat2 */
495
aurel323b3f24a2009-04-15 16:12:13 +0000496#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000497#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000498#else
499/* Userspace can usually survive runtime without inotify */
500#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000501#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000502#undef TARGET_NR_inotify_add_watch
503#undef TARGET_NR_inotify_rm_watch
504#endif /* CONFIG_INOTIFY */
505
Peter Maydell163a05a2011-06-27 17:44:52 +0100506#if defined(TARGET_NR_prlimit64)
507#ifndef __NR_prlimit64
508# define __NR_prlimit64 -1
509#endif
510#define __NR_sys_prlimit64 __NR_prlimit64
511/* The glibc rlimit structure may not be that used by the underlying syscall */
512struct host_rlimit64 {
513 uint64_t rlim_cur;
514 uint64_t rlim_max;
515};
516_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
517 const struct host_rlimit64 *, new_limit,
518 struct host_rlimit64 *, old_limit)
519#endif
520
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100521
522#if defined(TARGET_NR_timer_create)
zhaolichang6f9ff552020-09-17 15:50:25 +0800523/* Maximum of 32 active POSIX timers allowed at any one time. */
Peter Maydell9e598992022-07-25 12:00:35 +0100524#define GUEST_TIMER_MAX 32
525static timer_t g_posix_timers[GUEST_TIMER_MAX];
526static int g_posix_timer_allocated[GUEST_TIMER_MAX];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100527
528static inline int next_free_host_timer(void)
529{
Peter Maydell9e598992022-07-25 12:00:35 +0100530 int k;
531 for (k = 0; k < ARRAY_SIZE(g_posix_timer_allocated); k++) {
532 if (qatomic_xchg(g_posix_timer_allocated + k, 1) == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100533 return k;
534 }
535 }
536 return -1;
537}
Peter Maydell9e598992022-07-25 12:00:35 +0100538
539static inline void free_host_timer_slot(int id)
540{
541 qatomic_store_release(g_posix_timer_allocated + id, 0);
542}
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100543#endif
544
Philippe Mathieu-Daudé3ffe3262021-07-08 19:05:49 +0200545static inline int host_to_target_errno(int host_errno)
ths637947f2007-06-01 12:09:19 +0000546{
Philippe Mathieu-Daudé3ffe3262021-07-08 19:05:49 +0200547 switch (host_errno) {
548#define E(X) case X: return TARGET_##X;
549#include "errnos.c.inc"
550#undef E
551 default:
552 return host_errno;
Timothy E Baldwin24661192016-05-12 18:47:25 +0100553 }
ths637947f2007-06-01 12:09:19 +0000554}
555
Philippe Mathieu-Daudé3ffe3262021-07-08 19:05:49 +0200556static inline int target_to_host_errno(int target_errno)
thsb92c47c2007-11-01 00:07:38 +0000557{
Philippe Mathieu-Daudé3ffe3262021-07-08 19:05:49 +0200558 switch (target_errno) {
559#define E(X) case TARGET_##X: return X;
560#include "errnos.c.inc"
561#undef E
562 default:
563 return target_errno;
Timothy E Baldwin24661192016-05-12 18:47:25 +0100564 }
thsb92c47c2007-11-01 00:07:38 +0000565}
566
Ilya Leoshkevich892a4f62022-06-21 16:42:05 +0200567abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000568{
569 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000570 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000571 else
572 return ret;
573}
574
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100575const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000576{
Richard Hendersonaf254a22021-11-22 19:47:33 +0100577 if (err == QEMU_ERESTARTSYS) {
Peter Maydellda2a34f2016-06-06 19:58:19 +0100578 return "To be restarted";
579 }
Richard Henderson57a0c932021-11-17 05:14:52 -0800580 if (err == QEMU_ESIGRETURN) {
Peter Maydellda2a34f2016-06-06 19:58:19 +0100581 return "Successful exit from sigreturn";
582 }
583
thsb92c47c2007-11-01 00:07:38 +0000584 return strerror(target_to_host_errno(err));
585}
586
Tonis Tiigi45ad7612022-01-04 20:18:18 -0800587static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize)
588{
589 int i;
590 uint8_t b;
591 if (usize <= ksize) {
592 return 1;
593 }
594 for (i = ksize; i < usize; i++) {
595 if (get_user_u8(b, addr + i)) {
596 return -TARGET_EFAULT;
597 }
598 if (b != 0) {
599 return 0;
600 }
601 }
602 return 1;
603}
604
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100605#define safe_syscall0(type, name) \
606static type safe_##name(void) \
607{ \
608 return safe_syscall(__NR_##name); \
609}
610
611#define safe_syscall1(type, name, type1, arg1) \
612static type safe_##name(type1 arg1) \
613{ \
614 return safe_syscall(__NR_##name, arg1); \
615}
616
617#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
618static type safe_##name(type1 arg1, type2 arg2) \
619{ \
620 return safe_syscall(__NR_##name, arg1, arg2); \
621}
622
623#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
624static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
625{ \
626 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
627}
628
629#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
630 type4, arg4) \
631static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
632{ \
633 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
634}
635
636#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
637 type4, arg4, type5, arg5) \
638static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
639 type5 arg5) \
640{ \
641 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
642}
643
644#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
645 type4, arg4, type5, arg5, type6, arg6) \
646static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
647 type5 arg5, type6 arg6) \
648{ \
649 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
650}
651
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100652safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
653safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100654safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
655 int, flags, mode_t, mode)
Alistair Francis859e8a82020-03-12 15:13:49 -0700656#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100657safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
658 struct rusage *, rusage)
Alistair Francis859e8a82020-03-12 15:13:49 -0700659#endif
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100660safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
661 int, options, struct rusage *, rusage)
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +0200662safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Drew DeVault55bbe4d2022-11-04 18:36:32 +0100663safe_syscall5(int, execveat, int, dirfd, const char *, filename,
664 char **, argv, char **, envp, int, flags)
Alistair Francis859e8a82020-03-12 15:13:49 -0700665#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +0200666 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
Peter Maydell6df9d382016-05-12 18:47:51 +0100667safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
668 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Alistair Francis859e8a82020-03-12 15:13:49 -0700669#endif
Filip Bozutae5ce9682020-08-25 00:30:49 +0200670#if defined(TARGET_NR_ppoll) || defined(TARGET_NR_ppoll_time64)
Peter Maydella6130232016-06-06 19:58:10 +0100671safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
672 struct timespec *, tsp, const sigset_t *, sigmask,
673 size_t, sigsetsize)
Alistair Francis859e8a82020-03-12 15:13:49 -0700674#endif
Peter Maydell227f0212016-06-06 19:58:11 +0100675safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
676 int, maxevents, int, timeout, const sigset_t *, sigmask,
677 size_t, sigsetsize)
Alistair Francis14690292020-03-18 15:47:01 -0700678#if defined(__NR_futex)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100679safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
680 const struct timespec *,timeout,int *,uaddr2,int,val3)
Alistair Francis859e8a82020-03-12 15:13:49 -0700681#endif
Alistair Francis14690292020-03-18 15:47:01 -0700682#if defined(__NR_futex_time64)
683safe_syscall6(int,futex_time64,int *,uaddr,int,op,int,val, \
684 const struct timespec *,timeout,int *,uaddr2,int,val3)
685#endif
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100686safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100687safe_syscall2(int, kill, pid_t, pid, int, sig)
688safe_syscall2(int, tkill, int, tid, int, sig)
689safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100690safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
691safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200692safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
693 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200694safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
695 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100696safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
697 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100698safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
699 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
700safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
701 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
702safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
703safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100704safe_syscall2(int, flock, int, fd, int, operation)
Filip Bozutaddcbde12020-08-24 21:21:16 +0200705#if defined(TARGET_NR_rt_sigtimedwait) || defined(TARGET_NR_rt_sigtimedwait_time64)
Peter Maydellb3f82332016-06-06 19:58:08 +0100706safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
707 const struct timespec *, uts, size_t, sigsetsize)
Alistair Francis859e8a82020-03-12 15:13:49 -0700708#endif
Peter Maydellff6dc132016-06-06 19:58:13 +0100709safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
710 int, flags)
Alistair Francis859e8a82020-03-12 15:13:49 -0700711#if defined(TARGET_NR_nanosleep)
Peter Maydell9e518222016-06-06 19:58:09 +0100712safe_syscall2(int, nanosleep, const struct timespec *, req,
713 struct timespec *, rem)
Alistair Francis859e8a82020-03-12 15:13:49 -0700714#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +0200715#if defined(TARGET_NR_clock_nanosleep) || \
716 defined(TARGET_NR_clock_nanosleep_time64)
Peter Maydell9e518222016-06-06 19:58:09 +0100717safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
718 const struct timespec *, req, struct timespec *, rem)
719#endif
Laurent Vivier524fa342019-05-29 10:48:04 +0200720#ifdef __NR_ipc
Matus Kyseld8c08b12020-06-26 14:46:11 +0200721#ifdef __s390x__
722safe_syscall5(int, ipc, int, call, long, first, long, second, long, third,
723 void *, ptr)
724#else
Peter Maydell89f9fe42016-06-06 19:58:05 +0100725safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
726 void *, ptr, long, fifth)
Laurent Vivier86e63692019-05-23 19:54:13 +0200727#endif
Matus Kyseld8c08b12020-06-26 14:46:11 +0200728#endif
Laurent Vivier86e63692019-05-23 19:54:13 +0200729#ifdef __NR_msgsnd
730safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
731 int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200732#endif
733#ifdef __NR_msgrcv
734safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
735 long, msgtype, int, flags)
Laurent Vivier86e63692019-05-23 19:54:13 +0200736#endif
737#ifdef __NR_semtimedop
738safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
739 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100740#endif
Filip Bozutad107e372020-08-24 21:37:52 +0200741#if defined(TARGET_NR_mq_timedsend) || \
742 defined(TARGET_NR_mq_timedsend_time64)
Peter Maydelld40ecd62016-06-06 19:58:06 +0100743safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
744 size_t, len, unsigned, prio, const struct timespec *, timeout)
Alistair Francis859e8a82020-03-12 15:13:49 -0700745#endif
Filip Bozutad107e372020-08-24 21:37:52 +0200746#if defined(TARGET_NR_mq_timedreceive) || \
747 defined(TARGET_NR_mq_timedreceive_time64)
Peter Maydelld40ecd62016-06-06 19:58:06 +0100748safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
749 size_t, len, unsigned *, prio, const struct timespec *, timeout)
750#endif
Andreas Schwab84946452020-11-12 12:45:16 +0100751#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range)
752safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
753 int, outfd, loff_t *, poutoff, size_t, length,
754 unsigned int, flags)
755#endif
756
Peter Maydell49ca6f32016-06-06 19:58:14 +0100757/* We do ioctl like this rather than via safe_syscall3 to preserve the
758 * "third argument might be integer or pointer or not present" behaviour of
759 * the libc function.
760 */
761#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Michael Tokarevac1bbe82024-08-29 09:39:50 +0300762/* Similarly for fcntl. Since we always build with LFS enabled,
763 * we should be using the 64-bit structures automatically.
Peter Maydell435da5e2016-06-13 11:22:05 +0100764 */
765#ifdef __NR_fcntl64
766#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
767#else
768#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
769#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100770
Paul Burton8289d112014-06-22 11:25:33 +0100771static inline int host_to_target_sock_type(int host_type)
772{
773 int target_type;
774
775 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
776 case SOCK_DGRAM:
777 target_type = TARGET_SOCK_DGRAM;
778 break;
779 case SOCK_STREAM:
780 target_type = TARGET_SOCK_STREAM;
781 break;
782 default:
783 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
784 break;
785 }
786
787#if defined(SOCK_CLOEXEC)
788 if (host_type & SOCK_CLOEXEC) {
789 target_type |= TARGET_SOCK_CLOEXEC;
790 }
791#endif
792
793#if defined(SOCK_NONBLOCK)
794 if (host_type & SOCK_NONBLOCK) {
795 target_type |= TARGET_SOCK_NONBLOCK;
796 }
797#endif
798
799 return target_type;
800}
801
Helge Dellerdfe49862023-07-17 12:27:13 +0200802static abi_ulong target_brk, initial_target_brk;
bellard31e31b82003-02-18 22:55:36 +0000803
blueswir1992f48a2007-10-14 16:27:31 +0000804void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000805{
Andreas Schwabd28b3c92023-07-06 13:34:19 +0200806 target_brk = TARGET_PAGE_ALIGN(new_brk);
Helge Dellerdfe49862023-07-17 12:27:13 +0200807 initial_target_brk = target_brk;
bellard31e31b82003-02-18 22:55:36 +0000808}
809
ths0da46a62007-10-20 20:23:07 +0000810/* do_brk() must return target values and target errnos. */
Helge Deller86f04732022-12-25 09:23:19 +0100811abi_long do_brk(abi_ulong brk_val)
bellard31e31b82003-02-18 22:55:36 +0000812{
blueswir1992f48a2007-10-14 16:27:31 +0000813 abi_long mapped_addr;
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900814 abi_ulong new_brk;
815 abi_ulong old_brk;
bellard31e31b82003-02-18 22:55:36 +0000816
Richard Hendersonee1bf832021-02-12 10:48:44 -0800817 /* brk pointers are always untagged */
818
Helge Dellerdfe49862023-07-17 12:27:13 +0200819 /* do not allow to shrink below initial brk value */
820 if (brk_val < initial_target_brk) {
Akihiko Odakicb9d5d12023-08-02 16:17:51 +0900821 return target_brk;
Helge Dellerdfe49862023-07-17 12:27:13 +0200822 }
823
Helge Deller86f04732022-12-25 09:23:19 +0100824 new_brk = TARGET_PAGE_ALIGN(brk_val);
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900825 old_brk = TARGET_PAGE_ALIGN(target_brk);
Helge Deller86f04732022-12-25 09:23:19 +0100826
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900827 /* new and old target_brk might be on the same page */
828 if (new_brk == old_brk) {
Helge Deller86f04732022-12-25 09:23:19 +0100829 target_brk = brk_val;
830 return target_brk;
831 }
832
Michael Tokarev2cf91b92023-11-14 19:07:15 +0300833 /* Release heap if necessary */
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900834 if (new_brk < old_brk) {
835 target_munmap(new_brk, old_brk - new_brk);
Helge Deller86f04732022-12-25 09:23:19 +0100836
837 target_brk = brk_val;
838 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000839 }
840
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900841 mapped_addr = target_mmap(old_brk, new_brk - old_brk,
842 PROT_READ | PROT_WRITE,
843 MAP_FIXED_NOREPLACE | MAP_ANON | MAP_PRIVATE,
844 -1, 0);
Peter Maydell00faf082011-04-18 16:34:24 +0100845
Akihiko Odaki2aea1372023-08-02 16:17:52 +0900846 if (mapped_addr == old_brk) {
Helge Deller86f04732022-12-25 09:23:19 +0100847 target_brk = brk_val;
Peter Maydell00faf082011-04-18 16:34:24 +0100848 return target_brk;
Peter Maydell00faf082011-04-18 16:34:24 +0100849 }
balrog7ab240a2008-04-26 12:17:34 +0000850
Richard Henderson7dd46c02010-05-03 10:07:49 -0700851#if defined(TARGET_ALPHA)
852 /* We (partially) emulate OSF/1 on Alpha, which requires we
853 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100854 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700855#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100856 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000857 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000858}
859
Alistair Francis859e8a82020-03-12 15:13:49 -0700860#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +0200861 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
ths26edcf42007-12-09 02:25:24 +0000862static inline abi_long copy_from_user_fdset(fd_set *fds,
863 abi_ulong target_fds_addr,
864 int n)
bellard31e31b82003-02-18 22:55:36 +0000865{
ths26edcf42007-12-09 02:25:24 +0000866 int i, nw, j, k;
867 abi_ulong b, *target_fds;
868
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200869 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000870 if (!(target_fds = lock_user(VERIFY_READ,
871 target_fds_addr,
872 sizeof(abi_ulong) * nw,
873 1)))
874 return -TARGET_EFAULT;
875
876 FD_ZERO(fds);
877 k = 0;
878 for (i = 0; i < nw; i++) {
879 /* grab the abi_ulong */
880 __get_user(b, &target_fds[i]);
881 for (j = 0; j < TARGET_ABI_BITS; j++) {
882 /* check the bit inside the abi_ulong */
883 if ((b >> j) & 1)
884 FD_SET(k, fds);
885 k++;
bellard31e31b82003-02-18 22:55:36 +0000886 }
bellard31e31b82003-02-18 22:55:36 +0000887 }
ths26edcf42007-12-09 02:25:24 +0000888
889 unlock_user(target_fds, target_fds_addr, 0);
890
891 return 0;
bellard31e31b82003-02-18 22:55:36 +0000892}
893
Mike Frysinger055e0902011-06-03 17:01:49 -0400894static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
895 abi_ulong target_fds_addr,
896 int n)
897{
898 if (target_fds_addr) {
899 if (copy_from_user_fdset(fds, target_fds_addr, n))
900 return -TARGET_EFAULT;
901 *fds_ptr = fds;
902 } else {
903 *fds_ptr = NULL;
904 }
905 return 0;
906}
907
ths26edcf42007-12-09 02:25:24 +0000908static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
909 const fd_set *fds,
910 int n)
bellard31e31b82003-02-18 22:55:36 +0000911{
bellard31e31b82003-02-18 22:55:36 +0000912 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000913 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000914 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000915
Laurent Vivierb1b2db22016-05-31 18:36:02 +0200916 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +0000917 if (!(target_fds = lock_user(VERIFY_WRITE,
918 target_fds_addr,
919 sizeof(abi_ulong) * nw,
920 0)))
921 return -TARGET_EFAULT;
922
923 k = 0;
924 for (i = 0; i < nw; i++) {
925 v = 0;
926 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000927 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000928 k++;
bellard31e31b82003-02-18 22:55:36 +0000929 }
ths26edcf42007-12-09 02:25:24 +0000930 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000931 }
ths26edcf42007-12-09 02:25:24 +0000932
933 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
934
935 return 0;
bellard31e31b82003-02-18 22:55:36 +0000936}
Alistair Francis859e8a82020-03-12 15:13:49 -0700937#endif
bellard31e31b82003-02-18 22:55:36 +0000938
bellardc596ed12003-07-13 17:32:31 +0000939#if defined(__alpha__)
940#define HOST_HZ 1024
941#else
942#define HOST_HZ 100
943#endif
944
blueswir1992f48a2007-10-14 16:27:31 +0000945static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000946{
947#if HOST_HZ == TARGET_HZ
948 return ticks;
949#else
950 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
951#endif
952}
953
bellard579a97f2007-11-11 14:26:47 +0000954static inline abi_long host_to_target_rusage(abi_ulong target_addr,
955 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000956{
pbrook53a59602006-03-25 19:31:22 +0000957 struct target_rusage *target_rusage;
958
bellard579a97f2007-11-11 14:26:47 +0000959 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
960 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200961 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
962 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
963 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
964 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
965 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
966 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
967 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
968 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
969 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
970 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
971 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
972 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
973 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
974 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
975 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
976 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
977 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
978 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000979 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000980
981 return 0;
bellardb4091862003-05-16 15:39:34 +0000982}
983
Alistair Francis859e8a82020-03-12 15:13:49 -0700984#ifdef TARGET_NR_setrlimit
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200985static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900986{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200987 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300988 rlim_t result;
989
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200990 target_rlim_swap = tswapal(target_rlim);
991 if (target_rlim_swap == TARGET_RLIM_INFINITY)
992 return RLIM_INFINITY;
993
994 result = target_rlim_swap;
995 if (target_rlim_swap != (rlim_t)result)
996 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300997
998 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900999}
Alistair Francis859e8a82020-03-12 15:13:49 -07001000#endif
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001001
Alistair Francis859e8a82020-03-12 15:13:49 -07001002#if defined(TARGET_NR_getrlimit) || defined(TARGET_NR_ugetrlimit)
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001003static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001004{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001005 abi_ulong target_rlim_swap;
1006 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001007
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001008 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001009 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001010 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001011 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001012 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001013
1014 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001015}
Alistair Francis859e8a82020-03-12 15:13:49 -07001016#endif
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001017
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001018static inline int target_to_host_resource(int code)
1019{
1020 switch (code) {
1021 case TARGET_RLIMIT_AS:
1022 return RLIMIT_AS;
1023 case TARGET_RLIMIT_CORE:
1024 return RLIMIT_CORE;
1025 case TARGET_RLIMIT_CPU:
1026 return RLIMIT_CPU;
1027 case TARGET_RLIMIT_DATA:
1028 return RLIMIT_DATA;
1029 case TARGET_RLIMIT_FSIZE:
1030 return RLIMIT_FSIZE;
1031 case TARGET_RLIMIT_LOCKS:
1032 return RLIMIT_LOCKS;
1033 case TARGET_RLIMIT_MEMLOCK:
1034 return RLIMIT_MEMLOCK;
1035 case TARGET_RLIMIT_MSGQUEUE:
1036 return RLIMIT_MSGQUEUE;
1037 case TARGET_RLIMIT_NICE:
1038 return RLIMIT_NICE;
1039 case TARGET_RLIMIT_NOFILE:
1040 return RLIMIT_NOFILE;
1041 case TARGET_RLIMIT_NPROC:
1042 return RLIMIT_NPROC;
1043 case TARGET_RLIMIT_RSS:
1044 return RLIMIT_RSS;
1045 case TARGET_RLIMIT_RTPRIO:
1046 return RLIMIT_RTPRIO;
Fabrice Fontainec3a28d72022-05-23 12:52:39 +02001047#ifdef RLIMIT_RTTIME
Serge Belyshev244fd082022-01-29 22:48:23 +03001048 case TARGET_RLIMIT_RTTIME:
1049 return RLIMIT_RTTIME;
Fabrice Fontainec3a28d72022-05-23 12:52:39 +02001050#endif
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001051 case TARGET_RLIMIT_SIGPENDING:
1052 return RLIMIT_SIGPENDING;
1053 case TARGET_RLIMIT_STACK:
1054 return RLIMIT_STACK;
1055 default:
1056 return code;
1057 }
1058}
1059
ths788f5ec2007-12-09 02:37:05 +00001060static inline abi_long copy_from_user_timeval(struct timeval *tv,
1061 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001062{
pbrook53a59602006-03-25 19:31:22 +00001063 struct target_timeval *target_tv;
1064
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001065 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
bellard579a97f2007-11-11 14:26:47 +00001066 return -TARGET_EFAULT;
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001067 }
ths788f5ec2007-12-09 02:37:05 +00001068
1069 __get_user(tv->tv_sec, &target_tv->tv_sec);
1070 __get_user(tv->tv_usec, &target_tv->tv_usec);
1071
1072 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001073
1074 return 0;
bellard31e31b82003-02-18 22:55:36 +00001075}
1076
ths788f5ec2007-12-09 02:37:05 +00001077static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1078 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001079{
pbrook53a59602006-03-25 19:31:22 +00001080 struct target_timeval *target_tv;
1081
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001082 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
bellard579a97f2007-11-11 14:26:47 +00001083 return -TARGET_EFAULT;
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001084 }
ths788f5ec2007-12-09 02:37:05 +00001085
1086 __put_user(tv->tv_sec, &target_tv->tv_sec);
1087 __put_user(tv->tv_usec, &target_tv->tv_usec);
1088
1089 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001090
1091 return 0;
bellard31e31b82003-02-18 22:55:36 +00001092}
1093
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001094#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
1095static inline abi_long copy_from_user_timeval64(struct timeval *tv,
1096 abi_ulong target_tv_addr)
1097{
1098 struct target__kernel_sock_timeval *target_tv;
1099
1100 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
1101 return -TARGET_EFAULT;
1102 }
1103
1104 __get_user(tv->tv_sec, &target_tv->tv_sec);
1105 __get_user(tv->tv_usec, &target_tv->tv_usec);
1106
1107 unlock_user_struct(target_tv, target_tv_addr, 0);
1108
1109 return 0;
1110}
1111#endif
1112
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001113static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr,
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001114 const struct timeval *tv)
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001115{
1116 struct target__kernel_sock_timeval *target_tv;
1117
1118 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
1119 return -TARGET_EFAULT;
1120 }
1121
1122 __put_user(tv->tv_sec, &target_tv->tv_sec);
1123 __put_user(tv->tv_usec, &target_tv->tv_usec);
1124
1125 unlock_user_struct(target_tv, target_tv_addr, 1);
1126
1127 return 0;
1128}
1129
Alistair Francis859e8a82020-03-12 15:13:49 -07001130#if defined(TARGET_NR_futex) || \
1131 defined(TARGET_NR_rt_sigtimedwait) || \
1132 defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6) || \
1133 defined(TARGET_NR_nanosleep) || defined(TARGET_NR_clock_settime) || \
1134 defined(TARGET_NR_utimensat) || defined(TARGET_NR_mq_timedsend) || \
Matus Kyseld8c08b12020-06-26 14:46:11 +02001135 defined(TARGET_NR_mq_timedreceive) || defined(TARGET_NR_ipc) || \
Filip Bozuta2c86c902020-07-22 17:34:20 +02001136 defined(TARGET_NR_semop) || defined(TARGET_NR_semtimedop) || \
1137 defined(TARGET_NR_timer_settime) || \
1138 (defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD))
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001139static inline abi_long target_to_host_timespec(struct timespec *host_ts,
1140 abi_ulong target_addr)
1141{
1142 struct target_timespec *target_ts;
1143
1144 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) {
1145 return -TARGET_EFAULT;
1146 }
1147 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
1148 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1149 unlock_user_struct(target_ts, target_addr, 0);
1150 return 0;
1151}
Alistair Francis859e8a82020-03-12 15:13:49 -07001152#endif
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001153
Filip Bozuta828cb3a2020-07-22 17:34:21 +02001154#if defined(TARGET_NR_clock_settime64) || defined(TARGET_NR_futex_time64) || \
1155 defined(TARGET_NR_timer_settime64) || \
Filip Bozutad107e372020-08-24 21:37:52 +02001156 defined(TARGET_NR_mq_timedsend_time64) || \
1157 defined(TARGET_NR_mq_timedreceive_time64) || \
Filip Bozuta6ac03b22020-08-24 21:21:15 +02001158 (defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD)) || \
Filip Bozutaddcbde12020-08-24 21:21:16 +02001159 defined(TARGET_NR_clock_nanosleep_time64) || \
Filip Bozutacac46eb2020-08-25 00:30:50 +02001160 defined(TARGET_NR_rt_sigtimedwait_time64) || \
1161 defined(TARGET_NR_utimensat) || \
1162 defined(TARGET_NR_utimensat_time64) || \
Filip Bozutae5ce9682020-08-25 00:30:49 +02001163 defined(TARGET_NR_semtimedop_time64) || \
1164 defined(TARGET_NR_pselect6_time64) || defined(TARGET_NR_ppoll_time64)
Alistair Francisc6c8d102020-03-12 15:13:53 -07001165static inline abi_long target_to_host_timespec64(struct timespec *host_ts,
1166 abi_ulong target_addr)
1167{
1168 struct target__kernel_timespec *target_ts;
1169
1170 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) {
1171 return -TARGET_EFAULT;
1172 }
1173 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
1174 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
Laurent Vivier00576752020-08-27 09:04:49 +02001175 /* in 32bit mode, this drops the padding */
1176 host_ts->tv_nsec = (long)(abi_long)host_ts->tv_nsec;
Alistair Francisc6c8d102020-03-12 15:13:53 -07001177 unlock_user_struct(target_ts, target_addr, 0);
1178 return 0;
1179}
1180#endif
1181
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02001182static inline abi_long host_to_target_timespec(abi_ulong target_addr,
1183 struct timespec *host_ts)
1184{
1185 struct target_timespec *target_ts;
1186
1187 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
1188 return -TARGET_EFAULT;
1189 }
1190 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
1191 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1192 unlock_user_struct(target_ts, target_addr, 1);
1193 return 0;
1194}
1195
1196static inline abi_long host_to_target_timespec64(abi_ulong target_addr,
1197 struct timespec *host_ts)
1198{
1199 struct target__kernel_timespec *target_ts;
1200
1201 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
1202 return -TARGET_EFAULT;
1203 }
1204 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
1205 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
1206 unlock_user_struct(target_ts, target_addr, 1);
1207 return 0;
1208}
1209
Richard Hendersona52f5f82020-02-12 19:22:23 -08001210#if defined(TARGET_NR_gettimeofday)
1211static inline abi_long copy_to_user_timezone(abi_ulong target_tz_addr,
1212 struct timezone *tz)
1213{
1214 struct target_timezone *target_tz;
1215
1216 if (!lock_user_struct(VERIFY_WRITE, target_tz, target_tz_addr, 1)) {
1217 return -TARGET_EFAULT;
1218 }
1219
1220 __put_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1221 __put_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1222
1223 unlock_user_struct(target_tz, target_tz_addr, 1);
1224
1225 return 0;
1226}
1227#endif
1228
Alistair Francis859e8a82020-03-12 15:13:49 -07001229#if defined(TARGET_NR_settimeofday)
Paul Burtonef4467e2014-06-22 11:25:40 +01001230static inline abi_long copy_from_user_timezone(struct timezone *tz,
1231 abi_ulong target_tz_addr)
1232{
1233 struct target_timezone *target_tz;
1234
1235 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1236 return -TARGET_EFAULT;
1237 }
1238
1239 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1240 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1241
1242 unlock_user_struct(target_tz, target_tz_addr, 0);
1243
1244 return 0;
1245}
Alistair Francis859e8a82020-03-12 15:13:49 -07001246#endif
Paul Burtonef4467e2014-06-22 11:25:40 +01001247
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001248#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1249#include <mqueue.h>
1250
aurel3224e10032009-04-15 16:11:43 +00001251static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1252 abi_ulong target_mq_attr_addr)
1253{
1254 struct target_mq_attr *target_mq_attr;
1255
1256 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1257 target_mq_attr_addr, 1))
1258 return -TARGET_EFAULT;
1259
1260 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1261 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1262 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1263 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1264
1265 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1266
1267 return 0;
1268}
1269
1270static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1271 const struct mq_attr *attr)
1272{
1273 struct target_mq_attr *target_mq_attr;
1274
1275 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1276 target_mq_attr_addr, 0))
1277 return -TARGET_EFAULT;
1278
1279 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1280 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1281 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1282 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1283
1284 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1285
1286 return 0;
1287}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001288#endif
bellard31e31b82003-02-18 22:55:36 +00001289
Mike Frysinger055e0902011-06-03 17:01:49 -04001290#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001291/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001292static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001293 abi_ulong rfd_addr, abi_ulong wfd_addr,
1294 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001295{
1296 fd_set rfds, wfds, efds;
1297 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001298 struct timeval tv;
1299 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001300 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001301
Mike Frysinger055e0902011-06-03 17:01:49 -04001302 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1303 if (ret) {
1304 return ret;
pbrook53a59602006-03-25 19:31:22 +00001305 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001306 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1307 if (ret) {
1308 return ret;
pbrook53a59602006-03-25 19:31:22 +00001309 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001310 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1311 if (ret) {
1312 return ret;
pbrook53a59602006-03-25 19:31:22 +00001313 }
ths3b46e622007-09-17 08:09:54 +00001314
ths26edcf42007-12-09 02:25:24 +00001315 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001316 if (copy_from_user_timeval(&tv, target_tv_addr))
1317 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001318 ts.tv_sec = tv.tv_sec;
1319 ts.tv_nsec = tv.tv_usec * 1000;
1320 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001321 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001322 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001323 }
ths26edcf42007-12-09 02:25:24 +00001324
Peter Maydell6df9d382016-05-12 18:47:51 +01001325 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1326 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001327
ths26edcf42007-12-09 02:25:24 +00001328 if (!is_error(ret)) {
1329 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1330 return -TARGET_EFAULT;
1331 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1332 return -TARGET_EFAULT;
1333 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1334 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001335
Peter Maydell6df9d382016-05-12 18:47:51 +01001336 if (target_tv_addr) {
1337 tv.tv_sec = ts.tv_sec;
1338 tv.tv_usec = ts.tv_nsec / 1000;
1339 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1340 return -TARGET_EFAULT;
1341 }
1342 }
bellard31e31b82003-02-18 22:55:36 +00001343 }
bellard579a97f2007-11-11 14:26:47 +00001344
bellard31e31b82003-02-18 22:55:36 +00001345 return ret;
1346}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001347
1348#if defined(TARGET_WANT_OLD_SYS_SELECT)
1349static abi_long do_old_select(abi_ulong arg1)
1350{
1351 struct target_sel_arg_struct *sel;
1352 abi_ulong inp, outp, exp, tvp;
1353 long nsel;
1354
1355 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1356 return -TARGET_EFAULT;
1357 }
1358
1359 nsel = tswapal(sel->n);
1360 inp = tswapal(sel->inp);
1361 outp = tswapal(sel->outp);
1362 exp = tswapal(sel->exp);
1363 tvp = tswapal(sel->tvp);
1364
1365 unlock_user_struct(sel, arg1, 0);
1366
1367 return do_select(nsel, inp, outp, exp, tvp);
1368}
1369#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001370#endif
bellard31e31b82003-02-18 22:55:36 +00001371
Filip Bozutae5ce9682020-08-25 00:30:49 +02001372#if defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
1373static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
1374 abi_long arg4, abi_long arg5, abi_long arg6,
1375 bool time64)
1376{
1377 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
1378 fd_set rfds, wfds, efds;
1379 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1380 struct timespec ts, *ts_ptr;
1381 abi_long ret;
1382
1383 /*
1384 * The 6th arg is actually two args smashed together,
1385 * so we cannot use the C library.
1386 */
Filip Bozutae5ce9682020-08-25 00:30:49 +02001387 struct {
1388 sigset_t *set;
1389 size_t size;
1390 } sig, *sig_ptr;
1391
1392 abi_ulong arg_sigset, arg_sigsize, *arg7;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001393
1394 n = arg1;
1395 rfd_addr = arg2;
1396 wfd_addr = arg3;
1397 efd_addr = arg4;
1398 ts_addr = arg5;
1399
1400 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1401 if (ret) {
1402 return ret;
1403 }
1404 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1405 if (ret) {
1406 return ret;
1407 }
1408 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1409 if (ret) {
1410 return ret;
1411 }
1412
1413 /*
1414 * This takes a timespec, and not a timeval, so we cannot
1415 * use the do_select() helper ...
1416 */
1417 if (ts_addr) {
1418 if (time64) {
1419 if (target_to_host_timespec64(&ts, ts_addr)) {
1420 return -TARGET_EFAULT;
1421 }
1422 } else {
1423 if (target_to_host_timespec(&ts, ts_addr)) {
1424 return -TARGET_EFAULT;
1425 }
1426 }
1427 ts_ptr = &ts;
1428 } else {
1429 ts_ptr = NULL;
1430 }
1431
1432 /* Extract the two packed args for the sigset */
Richard Hendersoncb226032022-03-15 01:43:06 -07001433 sig_ptr = NULL;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001434 if (arg6) {
Filip Bozutae5ce9682020-08-25 00:30:49 +02001435 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
1436 if (!arg7) {
1437 return -TARGET_EFAULT;
1438 }
1439 arg_sigset = tswapal(arg7[0]);
1440 arg_sigsize = tswapal(arg7[1]);
1441 unlock_user(arg7, arg6, 0);
1442
1443 if (arg_sigset) {
Richard Hendersoncb226032022-03-15 01:43:06 -07001444 ret = process_sigsuspend_mask(&sig.set, arg_sigset, arg_sigsize);
1445 if (ret != 0) {
1446 return ret;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001447 }
Richard Hendersoncb226032022-03-15 01:43:06 -07001448 sig_ptr = &sig;
1449 sig.size = SIGSET_T_SIZE;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001450 }
Filip Bozutae5ce9682020-08-25 00:30:49 +02001451 }
1452
1453 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1454 ts_ptr, sig_ptr));
1455
Richard Hendersoncb226032022-03-15 01:43:06 -07001456 if (sig_ptr) {
1457 finish_sigsuspend_mask(ret);
1458 }
1459
Filip Bozutae5ce9682020-08-25 00:30:49 +02001460 if (!is_error(ret)) {
1461 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) {
1462 return -TARGET_EFAULT;
1463 }
1464 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) {
1465 return -TARGET_EFAULT;
1466 }
1467 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) {
1468 return -TARGET_EFAULT;
1469 }
1470 if (time64) {
1471 if (ts_addr && host_to_target_timespec64(ts_addr, &ts)) {
1472 return -TARGET_EFAULT;
1473 }
1474 } else {
1475 if (ts_addr && host_to_target_timespec(ts_addr, &ts)) {
1476 return -TARGET_EFAULT;
1477 }
1478 }
1479 }
1480 return ret;
1481}
1482#endif
1483
1484#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll) || \
1485 defined(TARGET_NR_ppoll_time64)
1486static abi_long do_ppoll(abi_long arg1, abi_long arg2, abi_long arg3,
1487 abi_long arg4, abi_long arg5, bool ppoll, bool time64)
1488{
1489 struct target_pollfd *target_pfd;
1490 unsigned int nfds = arg2;
1491 struct pollfd *pfd;
1492 unsigned int i;
1493 abi_long ret;
1494
1495 pfd = NULL;
1496 target_pfd = NULL;
1497 if (nfds) {
1498 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
1499 return -TARGET_EINVAL;
1500 }
1501 target_pfd = lock_user(VERIFY_WRITE, arg1,
1502 sizeof(struct target_pollfd) * nfds, 1);
1503 if (!target_pfd) {
1504 return -TARGET_EFAULT;
1505 }
1506
1507 pfd = alloca(sizeof(struct pollfd) * nfds);
1508 for (i = 0; i < nfds; i++) {
1509 pfd[i].fd = tswap32(target_pfd[i].fd);
1510 pfd[i].events = tswap16(target_pfd[i].events);
1511 }
1512 }
1513 if (ppoll) {
1514 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
Richard Hendersondb36aa72022-03-15 01:43:08 -07001515 sigset_t *set = NULL;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001516
1517 if (arg3) {
1518 if (time64) {
1519 if (target_to_host_timespec64(timeout_ts, arg3)) {
1520 unlock_user(target_pfd, arg1, 0);
1521 return -TARGET_EFAULT;
1522 }
1523 } else {
1524 if (target_to_host_timespec(timeout_ts, arg3)) {
1525 unlock_user(target_pfd, arg1, 0);
1526 return -TARGET_EFAULT;
1527 }
1528 }
1529 } else {
1530 timeout_ts = NULL;
1531 }
1532
1533 if (arg4) {
Richard Hendersondb36aa72022-03-15 01:43:08 -07001534 ret = process_sigsuspend_mask(&set, arg4, arg5);
1535 if (ret != 0) {
Filip Bozutae5ce9682020-08-25 00:30:49 +02001536 unlock_user(target_pfd, arg1, 0);
Richard Hendersondb36aa72022-03-15 01:43:08 -07001537 return ret;
Filip Bozutae5ce9682020-08-25 00:30:49 +02001538 }
Filip Bozutae5ce9682020-08-25 00:30:49 +02001539 }
1540
1541 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
1542 set, SIGSET_T_SIZE));
1543
Richard Hendersondb36aa72022-03-15 01:43:08 -07001544 if (set) {
1545 finish_sigsuspend_mask(ret);
1546 }
Filip Bozutae5ce9682020-08-25 00:30:49 +02001547 if (!is_error(ret) && arg3) {
1548 if (time64) {
1549 if (host_to_target_timespec64(arg3, timeout_ts)) {
1550 return -TARGET_EFAULT;
1551 }
1552 } else {
1553 if (host_to_target_timespec(arg3, timeout_ts)) {
1554 return -TARGET_EFAULT;
1555 }
1556 }
1557 }
Filip Bozutae5ce9682020-08-25 00:30:49 +02001558 } else {
1559 struct timespec ts, *pts;
1560
1561 if (arg3 >= 0) {
1562 /* Convert ms to secs, ns */
1563 ts.tv_sec = arg3 / 1000;
1564 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
1565 pts = &ts;
1566 } else {
1567 /* -ve poll() timeout means "infinite" */
1568 pts = NULL;
1569 }
1570 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
1571 }
1572
1573 if (!is_error(ret)) {
1574 for (i = 0; i < nfds; i++) {
1575 target_pfd[i].revents = tswap16(pfd[i].revents);
1576 }
1577 }
1578 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
1579 return ret;
1580}
1581#endif
1582
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02001583static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong pipedes,
Richard Hendersonfb41a662010-05-03 10:07:52 -07001584 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001585{
1586 int host_pipe[2];
1587 abi_long ret;
Helge Deller499d8052022-07-19 18:20:42 +02001588 ret = pipe2(host_pipe, flags);
Riku Voipio099d6b02009-05-05 12:10:04 +03001589
1590 if (is_error(ret))
1591 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001592
1593 /* Several targets have special calling conventions for the original
1594 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1595 if (!is_pipe2) {
1596#if defined(TARGET_ALPHA)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02001597 cpu_env->ir[IR_A4] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001598 return host_pipe[0];
1599#elif defined(TARGET_MIPS)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02001600 cpu_env->active_tc.gpr[3] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001601 return host_pipe[0];
1602#elif defined(TARGET_SH4)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02001603 cpu_env->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001604 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001605#elif defined(TARGET_SPARC)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02001606 cpu_env->regwptr[1] = host_pipe[1];
Peter Maydell82f05b62013-07-06 17:39:48 +01001607 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001608#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001609 }
1610
Riku Voipio099d6b02009-05-05 12:10:04 +03001611 if (put_user_s32(host_pipe[0], pipedes)
Helge Deller6f200f52022-07-17 18:21:53 +02001612 || put_user_s32(host_pipe[1], pipedes + sizeof(abi_int)))
Riku Voipio099d6b02009-05-05 12:10:04 +03001613 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001614 return get_errno(ret);
1615}
1616
Laurent Vivier7b36f782015-10-28 21:40:44 +01001617static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001618 abi_ulong target_addr,
1619 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001620{
aurel32607175e2009-04-15 16:11:59 +00001621 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1622 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001623 struct target_sockaddr *target_saddr;
1624
Laurent Vivier7b36f782015-10-28 21:40:44 +01001625 if (fd_trans_target_to_host_addr(fd)) {
1626 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1627 }
1628
bellard579a97f2007-11-11 14:26:47 +00001629 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1630 if (!target_saddr)
1631 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001632
1633 sa_family = tswap16(target_saddr->sa_family);
1634
1635 /* Oops. The caller might send a incomplete sun_path; sun_path
1636 * must be terminated by \0 (see the manual page), but
1637 * unfortunately it is quite common to specify sockaddr_un
1638 * length as "strlen(x->sun_path)" while it should be
1639 * "strlen(...) + 1". We'll fix that here if needed.
1640 * Linux kernel has a similar feature.
1641 */
1642
1643 if (sa_family == AF_UNIX) {
1644 if (len < unix_maxlen && len > 0) {
1645 char *cp = (char*)target_saddr;
1646
1647 if ( cp[len-1] && !cp[len] )
1648 len++;
1649 }
1650 if (len > unix_maxlen)
1651 len = unix_maxlen;
1652 }
1653
pbrook53a59602006-03-25 19:31:22 +00001654 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001655 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001656 if (sa_family == AF_NETLINK) {
1657 struct sockaddr_nl *nladdr;
1658
1659 nladdr = (struct sockaddr_nl *)addr;
1660 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1661 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1662 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001663 struct target_sockaddr_ll *lladdr;
1664
1665 lladdr = (struct target_sockaddr_ll *)addr;
1666 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1667 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
Mathis Marion44cf6732023-03-07 16:42:55 +01001668 } else if (sa_family == AF_INET6) {
1669 struct sockaddr_in6 *in6addr;
1670
1671 in6addr = (struct sockaddr_in6 *)addr;
1672 in6addr->sin6_scope_id = tswap32(in6addr->sin6_scope_id);
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001673 }
pbrook53a59602006-03-25 19:31:22 +00001674 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001675
1676 return 0;
bellard7854b052003-03-29 17:22:23 +00001677}
1678
bellard579a97f2007-11-11 14:26:47 +00001679static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1680 struct sockaddr *addr,
1681 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001682{
pbrook53a59602006-03-25 19:31:22 +00001683 struct target_sockaddr *target_saddr;
1684
Peter Maydella1e22192016-07-07 15:44:43 +01001685 if (len == 0) {
1686 return 0;
1687 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001688 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001689
bellard579a97f2007-11-11 14:26:47 +00001690 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1691 if (!target_saddr)
1692 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001693 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001694 if (len >= offsetof(struct target_sockaddr, sa_family) +
1695 sizeof(target_saddr->sa_family)) {
1696 target_saddr->sa_family = tswap16(addr->sa_family);
1697 }
Philippe Mathieu-Daudéa47401b2019-10-21 13:48:52 +02001698 if (addr->sa_family == AF_NETLINK &&
1699 len >= sizeof(struct target_sockaddr_nl)) {
1700 struct target_sockaddr_nl *target_nl =
1701 (struct target_sockaddr_nl *)target_saddr;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001702 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1703 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001704 } else if (addr->sa_family == AF_PACKET) {
1705 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1706 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1707 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001708 } else if (addr->sa_family == AF_INET6 &&
1709 len >= sizeof(struct target_sockaddr_in6)) {
1710 struct target_sockaddr_in6 *target_in6 =
1711 (struct target_sockaddr_in6 *)target_saddr;
1712 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001713 }
pbrook53a59602006-03-25 19:31:22 +00001714 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001715
1716 return 0;
bellard7854b052003-03-29 17:22:23 +00001717}
1718
bellard5a4a8982007-11-11 17:39:18 +00001719static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1720 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001721{
1722 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001723 abi_long msg_controllen;
1724 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001725 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001726 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001727
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001728 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001729 if (msg_controllen < sizeof (struct target_cmsghdr))
1730 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001731 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001732 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001733 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001734 if (!target_cmsg)
1735 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001736
1737 while (cmsg && target_cmsg) {
1738 void *data = CMSG_DATA(cmsg);
1739 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1740
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001741 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001742 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001743
1744 space += CMSG_SPACE(len);
1745 if (space > msgh->msg_controllen) {
1746 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001747 /* This is a QEMU bug, since we allocated the payload
1748 * area ourselves (unlike overflow in host-to-target
1749 * conversion, which is just the guest giving us a buffer
1750 * that's too small). It can't happen for the payload types
1751 * we currently support; if it becomes an issue in future
1752 * we would need to improve our allocation strategy to
1753 * something more intelligent than "twice the size of the
1754 * target buffer we're reading from".
1755 */
Josh Kunz39be5352020-02-03 18:54:13 -08001756 qemu_log_mask(LOG_UNIMP,
1757 ("Unsupported ancillary data %d/%d: "
1758 "unhandled msg size\n"),
1759 tswap32(target_cmsg->cmsg_level),
1760 tswap32(target_cmsg->cmsg_type));
bellard7854b052003-03-29 17:22:23 +00001761 break;
1762 }
1763
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001764 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1765 cmsg->cmsg_level = SOL_SOCKET;
1766 } else {
1767 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1768 }
bellard7854b052003-03-29 17:22:23 +00001769 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1770 cmsg->cmsg_len = CMSG_LEN(len);
1771
Alex Suykov30b8b682014-12-23 07:52:58 +02001772 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001773 int *fd = (int *)data;
1774 int *target_fd = (int *)target_data;
1775 int i, numfds = len / sizeof(int);
1776
Peter Maydell876e23c2015-05-26 19:46:32 +01001777 for (i = 0; i < numfds; i++) {
1778 __get_user(fd[i], target_fd + i);
1779 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001780 } else if (cmsg->cmsg_level == SOL_SOCKET
1781 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1782 struct ucred *cred = (struct ucred *)data;
1783 struct target_ucred *target_cred =
1784 (struct target_ucred *)target_data;
1785
Peter Maydell876e23c2015-05-26 19:46:32 +01001786 __get_user(cred->pid, &target_cred->pid);
1787 __get_user(cred->uid, &target_cred->uid);
1788 __get_user(cred->gid, &target_cred->gid);
Helge Deller27404b62022-12-12 18:34:15 +01001789 } else if (cmsg->cmsg_level == SOL_ALG) {
1790 uint32_t *dst = (uint32_t *)data;
1791
1792 memcpy(dst, target_data, len);
Michael Tokarev669dcb62023-08-23 08:53:30 +02001793 /* fix endianness of first 32-bit word */
Helge Deller27404b62022-12-12 18:34:15 +01001794 if (len >= sizeof(uint32_t)) {
1795 *dst = tswap32(*dst);
1796 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001797 } else {
Josh Kunz39be5352020-02-03 18:54:13 -08001798 qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
1799 cmsg->cmsg_level, cmsg->cmsg_type);
Alex Suykov30b8b682014-12-23 07:52:58 +02001800 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001801 }
1802
1803 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001804 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1805 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001806 }
bellard5a4a8982007-11-11 17:39:18 +00001807 unlock_user(target_cmsg, target_cmsg_addr, 0);
1808 the_end:
bellard7854b052003-03-29 17:22:23 +00001809 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001810 return 0;
bellard7854b052003-03-29 17:22:23 +00001811}
1812
bellard5a4a8982007-11-11 17:39:18 +00001813static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1814 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001815{
1816 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001817 abi_long msg_controllen;
1818 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001819 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001820 socklen_t space = 0;
1821
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001822 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001823 if (msg_controllen < sizeof (struct target_cmsghdr))
1824 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001825 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001826 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001827 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001828 if (!target_cmsg)
1829 return -TARGET_EFAULT;
1830
bellard7854b052003-03-29 17:22:23 +00001831 while (cmsg && target_cmsg) {
1832 void *data = CMSG_DATA(cmsg);
1833 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1834
Peter Maydellad762b92017-12-15 13:52:56 +00001835 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001836 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001837
Peter Maydellc2aeb252015-05-26 19:46:31 +01001838 /* We never copy a half-header but may copy half-data;
1839 * this is Linux's behaviour in put_cmsg(). Note that
1840 * truncation here is a guest problem (which we report
1841 * to the guest via the CTRUNC bit), unlike truncation
1842 * in target_to_host_cmsg, which is a QEMU bug.
1843 */
Peter Maydell71749702017-12-15 13:52:55 +00001844 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001845 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001846 break;
1847 }
1848
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001849 if (cmsg->cmsg_level == SOL_SOCKET) {
1850 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1851 } else {
1852 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1853 }
bellard7854b052003-03-29 17:22:23 +00001854 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001855
Peter Maydellc2aeb252015-05-26 19:46:31 +01001856 /* Payload types which need a different size of payload on
1857 * the target must adjust tgt_len here.
1858 */
Peter Maydell309786c2018-05-18 19:47:15 +01001859 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001860 switch (cmsg->cmsg_level) {
1861 case SOL_SOCKET:
1862 switch (cmsg->cmsg_type) {
1863 case SO_TIMESTAMP:
1864 tgt_len = sizeof(struct target_timeval);
1865 break;
1866 default:
1867 break;
1868 }
Peter Maydell309786c2018-05-18 19:47:15 +01001869 break;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001870 default:
1871 break;
1872 }
1873
Peter Maydell71749702017-12-15 13:52:55 +00001874 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001875 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001876 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001877 }
1878
1879 /* We must now copy-and-convert len bytes of payload
1880 * into tgt_len bytes of destination space. Bear in mind
1881 * that in both source and destination we may be dealing
1882 * with a truncated value!
1883 */
Huw Davies52b65492014-04-17 14:02:47 +01001884 switch (cmsg->cmsg_level) {
1885 case SOL_SOCKET:
1886 switch (cmsg->cmsg_type) {
1887 case SCM_RIGHTS:
1888 {
1889 int *fd = (int *)data;
1890 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001891 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001892
Peter Maydell876e23c2015-05-26 19:46:32 +01001893 for (i = 0; i < numfds; i++) {
1894 __put_user(fd[i], target_fd + i);
1895 }
Huw Davies52b65492014-04-17 14:02:47 +01001896 break;
1897 }
1898 case SO_TIMESTAMP:
1899 {
1900 struct timeval *tv = (struct timeval *)data;
1901 struct target_timeval *target_tv =
1902 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001903
Peter Maydellc2aeb252015-05-26 19:46:31 +01001904 if (len != sizeof(struct timeval) ||
1905 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001906 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001907 }
Huw Davies52b65492014-04-17 14:02:47 +01001908
1909 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001910 __put_user(tv->tv_sec, &target_tv->tv_sec);
1911 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001912 break;
1913 }
Huw Davies4bc29752014-04-17 14:02:48 +01001914 case SCM_CREDENTIALS:
1915 {
1916 struct ucred *cred = (struct ucred *)data;
1917 struct target_ucred *target_cred =
1918 (struct target_ucred *)target_data;
1919
1920 __put_user(cred->pid, &target_cred->pid);
1921 __put_user(cred->uid, &target_cred->uid);
1922 __put_user(cred->gid, &target_cred->gid);
1923 break;
1924 }
Huw Davies52b65492014-04-17 14:02:47 +01001925 default:
1926 goto unimplemented;
1927 }
1928 break;
1929
Helge Delleree1ac3a2017-02-18 23:31:30 +01001930 case SOL_IP:
1931 switch (cmsg->cmsg_type) {
1932 case IP_TTL:
1933 {
1934 uint32_t *v = (uint32_t *)data;
1935 uint32_t *t_int = (uint32_t *)target_data;
1936
Peter Maydell71749702017-12-15 13:52:55 +00001937 if (len != sizeof(uint32_t) ||
1938 tgt_len != sizeof(uint32_t)) {
1939 goto unimplemented;
1940 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001941 __put_user(*v, t_int);
1942 break;
1943 }
1944 case IP_RECVERR:
1945 {
1946 struct errhdr_t {
1947 struct sock_extended_err ee;
1948 struct sockaddr_in offender;
1949 };
1950 struct errhdr_t *errh = (struct errhdr_t *)data;
1951 struct errhdr_t *target_errh =
1952 (struct errhdr_t *)target_data;
1953
Peter Maydell71749702017-12-15 13:52:55 +00001954 if (len != sizeof(struct errhdr_t) ||
1955 tgt_len != sizeof(struct errhdr_t)) {
1956 goto unimplemented;
1957 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001958 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1959 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1960 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1961 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1962 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1963 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1964 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1965 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1966 (void *) &errh->offender, sizeof(errh->offender));
1967 break;
1968 }
1969 default:
1970 goto unimplemented;
1971 }
1972 break;
1973
1974 case SOL_IPV6:
1975 switch (cmsg->cmsg_type) {
1976 case IPV6_HOPLIMIT:
1977 {
1978 uint32_t *v = (uint32_t *)data;
1979 uint32_t *t_int = (uint32_t *)target_data;
1980
Peter Maydell71749702017-12-15 13:52:55 +00001981 if (len != sizeof(uint32_t) ||
1982 tgt_len != sizeof(uint32_t)) {
1983 goto unimplemented;
1984 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001985 __put_user(*v, t_int);
1986 break;
1987 }
1988 case IPV6_RECVERR:
1989 {
1990 struct errhdr6_t {
1991 struct sock_extended_err ee;
1992 struct sockaddr_in6 offender;
1993 };
1994 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1995 struct errhdr6_t *target_errh =
1996 (struct errhdr6_t *)target_data;
1997
Peter Maydell71749702017-12-15 13:52:55 +00001998 if (len != sizeof(struct errhdr6_t) ||
1999 tgt_len != sizeof(struct errhdr6_t)) {
2000 goto unimplemented;
2001 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002002 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
2003 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
2004 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
2005 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
2006 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
2007 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
2008 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
2009 host_to_target_sockaddr((unsigned long) &target_errh->offender,
2010 (void *) &errh->offender, sizeof(errh->offender));
2011 break;
2012 }
2013 default:
2014 goto unimplemented;
2015 }
2016 break;
2017
Huw Davies52b65492014-04-17 14:02:47 +01002018 default:
2019 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08002020 qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
2021 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002022 memcpy(target_data, data, MIN(len, tgt_len));
2023 if (tgt_len > len) {
2024 memset(target_data + len, 0, tgt_len - len);
2025 }
bellard7854b052003-03-29 17:22:23 +00002026 }
2027
Peter Maydell71749702017-12-15 13:52:55 +00002028 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
2029 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002030 if (msg_controllen < tgt_space) {
2031 tgt_space = msg_controllen;
2032 }
2033 msg_controllen -= tgt_space;
2034 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00002035 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02002036 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
2037 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00002038 }
bellard5a4a8982007-11-11 17:39:18 +00002039 unlock_user(target_cmsg, target_cmsg_addr, space);
2040 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002041 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00002042 return 0;
bellard7854b052003-03-29 17:22:23 +00002043}
2044
ths0da46a62007-10-20 20:23:07 +00002045/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002046static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002047 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002048{
blueswir1992f48a2007-10-14 16:27:31 +00002049 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002050 int val;
ths3b46e622007-09-17 08:09:54 +00002051
bellard8853f862004-02-22 14:57:26 +00002052 switch(level) {
2053 case SOL_TCP:
Shu-Chun Wengfe51b0a2020-12-18 11:32:11 -08002054 case SOL_UDP:
2055 /* TCP and UDP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002056 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002057 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002058
bellard2f619692007-11-16 10:46:05 +00002059 if (get_user_u32(val, optval_addr))
2060 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002061 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2062 break;
2063 case SOL_IP:
2064 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002065 case IP_TOS:
2066 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002067 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002068 case IP_ROUTER_ALERT:
2069 case IP_RECVOPTS:
2070 case IP_RETOPTS:
2071 case IP_PKTINFO:
2072 case IP_MTU_DISCOVER:
2073 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002074 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002075 case IP_RECVTOS:
2076#ifdef IP_FREEBIND
2077 case IP_FREEBIND:
2078#endif
2079 case IP_MULTICAST_TTL:
2080 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002081 val = 0;
2082 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002083 if (get_user_u32(val, optval_addr))
2084 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002085 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002086 if (get_user_u8(val, optval_addr))
2087 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002088 }
2089 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2090 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002091 case IP_ADD_MEMBERSHIP:
2092 case IP_DROP_MEMBERSHIP:
Michael Tokarev124a1342024-03-31 13:07:35 +03002093 {
2094 struct ip_mreqn ip_mreq;
2095 struct target_ip_mreqn *target_smreqn;
2096
2097 QEMU_BUILD_BUG_ON(sizeof(struct ip_mreq) !=
2098 sizeof(struct target_ip_mreq));
2099
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002100 if (optlen < sizeof (struct target_ip_mreq) ||
Michael Tokarev124a1342024-03-31 13:07:35 +03002101 optlen > sizeof (struct target_ip_mreqn)) {
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002102 return -TARGET_EINVAL;
Michael Tokarev124a1342024-03-31 13:07:35 +03002103 }
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002104
Michael Tokarev124a1342024-03-31 13:07:35 +03002105 target_smreqn = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2106 if (!target_smreqn) {
2107 return -TARGET_EFAULT;
2108 }
2109 ip_mreq.imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
2110 ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr;
2111 if (optlen == sizeof(struct target_ip_mreqn)) {
2112 ip_mreq.imr_ifindex = tswapal(target_smreqn->imr_ifindex);
2113 optlen = sizeof(struct ip_mreqn);
2114 }
2115 unlock_user(target_smreqn, optval_addr, 0);
2116
2117 ret = get_errno(setsockopt(sockfd, level, optname, &ip_mreq, optlen));
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002118 break;
Michael Tokarev124a1342024-03-31 13:07:35 +03002119 }
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002120 case IP_BLOCK_SOURCE:
2121 case IP_UNBLOCK_SOURCE:
2122 case IP_ADD_SOURCE_MEMBERSHIP:
2123 case IP_DROP_SOURCE_MEMBERSHIP:
Michael Tokarev166bd922024-03-31 13:07:36 +03002124 {
2125 struct ip_mreq_source *ip_mreq_source;
2126
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002127 if (optlen != sizeof (struct target_ip_mreq_source))
2128 return -TARGET_EINVAL;
2129
2130 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
Peter Maydell74e43b02021-08-09 16:54:24 +01002131 if (!ip_mreq_source) {
2132 return -TARGET_EFAULT;
2133 }
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002134 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2135 unlock_user (ip_mreq_source, optval_addr, 0);
2136 break;
Michael Tokarev166bd922024-03-31 13:07:36 +03002137 }
bellard8853f862004-02-22 14:57:26 +00002138 default:
2139 goto unimplemented;
2140 }
2141 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002142 case SOL_IPV6:
2143 switch (optname) {
2144 case IPV6_MTU_DISCOVER:
2145 case IPV6_MTU:
2146 case IPV6_V6ONLY:
2147 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002148 case IPV6_UNICAST_HOPS:
Laurent Vivier21749c42018-06-27 23:21:52 +02002149 case IPV6_MULTICAST_HOPS:
2150 case IPV6_MULTICAST_LOOP:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002151 case IPV6_RECVERR:
2152 case IPV6_RECVHOPLIMIT:
2153 case IPV6_2292HOPLIMIT:
2154 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002155 case IPV6_ADDRFORM:
2156 case IPV6_2292PKTINFO:
2157 case IPV6_RECVTCLASS:
2158 case IPV6_RECVRTHDR:
2159 case IPV6_2292RTHDR:
2160 case IPV6_RECVHOPOPTS:
2161 case IPV6_2292HOPOPTS:
2162 case IPV6_RECVDSTOPTS:
2163 case IPV6_2292DSTOPTS:
2164 case IPV6_TCLASS:
Shu-Chun Weng22db1212020-12-18 11:32:12 -08002165 case IPV6_ADDR_PREFERENCES:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002166#ifdef IPV6_RECVPATHMTU
2167 case IPV6_RECVPATHMTU:
2168#endif
2169#ifdef IPV6_TRANSPARENT
2170 case IPV6_TRANSPARENT:
2171#endif
2172#ifdef IPV6_FREEBIND
2173 case IPV6_FREEBIND:
2174#endif
2175#ifdef IPV6_RECVORIGDSTADDR
2176 case IPV6_RECVORIGDSTADDR:
2177#endif
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002178 val = 0;
2179 if (optlen < sizeof(uint32_t)) {
2180 return -TARGET_EINVAL;
2181 }
2182 if (get_user_u32(val, optval_addr)) {
2183 return -TARGET_EFAULT;
2184 }
2185 ret = get_errno(setsockopt(sockfd, level, optname,
2186 &val, sizeof(val)));
2187 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002188 case IPV6_PKTINFO:
2189 {
2190 struct in6_pktinfo pki;
2191
2192 if (optlen < sizeof(pki)) {
2193 return -TARGET_EINVAL;
2194 }
2195
2196 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2197 return -TARGET_EFAULT;
2198 }
2199
2200 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2201
2202 ret = get_errno(setsockopt(sockfd, level, optname,
2203 &pki, sizeof(pki)));
2204 break;
2205 }
Neng Chen22bf4ee2019-06-19 16:17:10 +02002206 case IPV6_ADD_MEMBERSHIP:
2207 case IPV6_DROP_MEMBERSHIP:
2208 {
2209 struct ipv6_mreq ipv6mreq;
2210
2211 if (optlen < sizeof(ipv6mreq)) {
2212 return -TARGET_EINVAL;
2213 }
2214
2215 if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) {
2216 return -TARGET_EFAULT;
2217 }
2218
2219 ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface);
2220
2221 ret = get_errno(setsockopt(sockfd, level, optname,
2222 &ipv6mreq, sizeof(ipv6mreq)));
2223 break;
2224 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01002225 default:
2226 goto unimplemented;
2227 }
2228 break;
2229 case SOL_ICMPV6:
2230 switch (optname) {
2231 case ICMPV6_FILTER:
2232 {
2233 struct icmp6_filter icmp6f;
2234
2235 if (optlen > sizeof(icmp6f)) {
2236 optlen = sizeof(icmp6f);
2237 }
2238
2239 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
2240 return -TARGET_EFAULT;
2241 }
2242
2243 for (val = 0; val < 8; val++) {
2244 icmp6f.data[val] = tswap32(icmp6f.data[val]);
2245 }
2246
2247 ret = get_errno(setsockopt(sockfd, level, optname,
2248 &icmp6f, optlen));
2249 break;
2250 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002251 default:
2252 goto unimplemented;
2253 }
2254 break;
Jing Huang920394d2012-07-24 13:59:23 +00002255 case SOL_RAW:
2256 switch (optname) {
2257 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002258 case IPV6_CHECKSUM:
2259 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00002260 if (optlen < sizeof(uint32_t)) {
2261 return -TARGET_EINVAL;
2262 }
2263
2264 if (get_user_u32(val, optval_addr)) {
2265 return -TARGET_EFAULT;
2266 }
2267 ret = get_errno(setsockopt(sockfd, level, optname,
2268 &val, sizeof(val)));
2269 break;
2270
2271 default:
2272 goto unimplemented;
2273 }
2274 break;
Yunqiang Suf31dddd2019-06-19 16:17:11 +02002275#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE)
2276 case SOL_ALG:
2277 switch (optname) {
2278 case ALG_SET_KEY:
2279 {
Michael Tokarev04f6fb82024-03-31 13:07:34 +03002280 char *alg_key = lock_user(VERIFY_READ, optval_addr, optlen, 1);
Yunqiang Suf31dddd2019-06-19 16:17:11 +02002281 if (!alg_key) {
Yunqiang Suf31dddd2019-06-19 16:17:11 +02002282 return -TARGET_EFAULT;
2283 }
2284 ret = get_errno(setsockopt(sockfd, level, optname,
2285 alg_key, optlen));
Michael Tokarev04f6fb82024-03-31 13:07:34 +03002286 unlock_user(alg_key, optval_addr, optlen);
Yunqiang Suf31dddd2019-06-19 16:17:11 +02002287 break;
2288 }
2289 case ALG_SET_AEAD_AUTHSIZE:
2290 {
2291 ret = get_errno(setsockopt(sockfd, level, optname,
2292 NULL, optlen));
2293 break;
2294 }
2295 default:
2296 goto unimplemented;
2297 }
2298 break;
2299#endif
bellard3532fa72006-06-24 15:06:03 +00002300 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002301 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002302 case TARGET_SO_RCVTIMEO:
Michael Tokarev88a722b2024-03-31 13:07:37 +03002303 case TARGET_SO_SNDTIMEO:
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002304 {
2305 struct timeval tv;
2306
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002307 if (optlen != sizeof(struct target_timeval)) {
2308 return -TARGET_EINVAL;
2309 }
2310
2311 if (copy_from_user_timeval(&tv, optval_addr)) {
2312 return -TARGET_EFAULT;
2313 }
2314
Michael Tokarev88a722b2024-03-31 13:07:37 +03002315 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2316 optname == TARGET_SO_RCVTIMEO ?
2317 SO_RCVTIMEO : SO_SNDTIMEO,
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002318 &tv, sizeof(tv)));
2319 return ret;
2320 }
Laurent Vivierf57d4192013-08-30 01:46:41 +02002321 case TARGET_SO_ATTACH_FILTER:
2322 {
2323 struct target_sock_fprog *tfprog;
2324 struct target_sock_filter *tfilter;
2325 struct sock_fprog fprog;
2326 struct sock_filter *filter;
2327 int i;
2328
2329 if (optlen != sizeof(*tfprog)) {
2330 return -TARGET_EINVAL;
2331 }
2332 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2333 return -TARGET_EFAULT;
2334 }
2335 if (!lock_user_struct(VERIFY_READ, tfilter,
2336 tswapal(tfprog->filter), 0)) {
2337 unlock_user_struct(tfprog, optval_addr, 1);
2338 return -TARGET_EFAULT;
2339 }
2340
2341 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302342 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002343 if (filter == NULL) {
2344 unlock_user_struct(tfilter, tfprog->filter, 1);
2345 unlock_user_struct(tfprog, optval_addr, 1);
2346 return -TARGET_ENOMEM;
2347 }
2348 for (i = 0; i < fprog.len; i++) {
2349 filter[i].code = tswap16(tfilter[i].code);
2350 filter[i].jt = tfilter[i].jt;
2351 filter[i].jf = tfilter[i].jf;
2352 filter[i].k = tswap32(tfilter[i].k);
2353 }
2354 fprog.filter = filter;
2355
2356 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2357 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302358 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002359
2360 unlock_user_struct(tfilter, tfprog->filter, 1);
2361 unlock_user_struct(tfprog, optval_addr, 1);
2362 return ret;
2363 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002364 case TARGET_SO_BINDTODEVICE:
2365 {
2366 char *dev_ifname, *addr_ifname;
2367
2368 if (optlen > IFNAMSIZ - 1) {
2369 optlen = IFNAMSIZ - 1;
2370 }
2371 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2372 if (!dev_ifname) {
2373 return -TARGET_EFAULT;
2374 }
2375 optname = SO_BINDTODEVICE;
2376 addr_ifname = alloca(IFNAMSIZ);
2377 memcpy(addr_ifname, dev_ifname, optlen);
2378 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002379 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2380 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002381 unlock_user (dev_ifname, optval_addr, 0);
2382 return ret;
2383 }
Carlo Marcelo Arenas Belón83eb6e52018-08-24 01:56:01 -07002384 case TARGET_SO_LINGER:
2385 {
2386 struct linger lg;
2387 struct target_linger *tlg;
2388
2389 if (optlen != sizeof(struct target_linger)) {
2390 return -TARGET_EINVAL;
2391 }
2392 if (!lock_user_struct(VERIFY_READ, tlg, optval_addr, 1)) {
2393 return -TARGET_EFAULT;
2394 }
2395 __get_user(lg.l_onoff, &tlg->l_onoff);
2396 __get_user(lg.l_linger, &tlg->l_linger);
2397 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
2398 &lg, sizeof(lg)));
2399 unlock_user_struct(tlg, optval_addr, 0);
2400 return ret;
2401 }
bellard8853f862004-02-22 14:57:26 +00002402 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002403 case TARGET_SO_DEBUG:
2404 optname = SO_DEBUG;
2405 break;
2406 case TARGET_SO_REUSEADDR:
2407 optname = SO_REUSEADDR;
2408 break;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002409#ifdef SO_REUSEPORT
2410 case TARGET_SO_REUSEPORT:
2411 optname = SO_REUSEPORT;
2412 break;
2413#endif
bellard3532fa72006-06-24 15:06:03 +00002414 case TARGET_SO_TYPE:
2415 optname = SO_TYPE;
2416 break;
2417 case TARGET_SO_ERROR:
2418 optname = SO_ERROR;
2419 break;
2420 case TARGET_SO_DONTROUTE:
2421 optname = SO_DONTROUTE;
2422 break;
2423 case TARGET_SO_BROADCAST:
2424 optname = SO_BROADCAST;
2425 break;
2426 case TARGET_SO_SNDBUF:
2427 optname = SO_SNDBUF;
2428 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002429 case TARGET_SO_SNDBUFFORCE:
2430 optname = SO_SNDBUFFORCE;
2431 break;
bellard3532fa72006-06-24 15:06:03 +00002432 case TARGET_SO_RCVBUF:
2433 optname = SO_RCVBUF;
2434 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002435 case TARGET_SO_RCVBUFFORCE:
2436 optname = SO_RCVBUFFORCE;
2437 break;
bellard3532fa72006-06-24 15:06:03 +00002438 case TARGET_SO_KEEPALIVE:
2439 optname = SO_KEEPALIVE;
2440 break;
2441 case TARGET_SO_OOBINLINE:
2442 optname = SO_OOBINLINE;
2443 break;
2444 case TARGET_SO_NO_CHECK:
2445 optname = SO_NO_CHECK;
2446 break;
2447 case TARGET_SO_PRIORITY:
2448 optname = SO_PRIORITY;
2449 break;
bellard5e83e8e2005-03-01 22:32:06 +00002450#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002451 case TARGET_SO_BSDCOMPAT:
2452 optname = SO_BSDCOMPAT;
2453 break;
bellard5e83e8e2005-03-01 22:32:06 +00002454#endif
bellard3532fa72006-06-24 15:06:03 +00002455 case TARGET_SO_PASSCRED:
2456 optname = SO_PASSCRED;
2457 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002458 case TARGET_SO_PASSSEC:
2459 optname = SO_PASSSEC;
2460 break;
bellard3532fa72006-06-24 15:06:03 +00002461 case TARGET_SO_TIMESTAMP:
2462 optname = SO_TIMESTAMP;
2463 break;
2464 case TARGET_SO_RCVLOWAT:
2465 optname = SO_RCVLOWAT;
2466 break;
bellard8853f862004-02-22 14:57:26 +00002467 default:
2468 goto unimplemented;
2469 }
bellard3532fa72006-06-24 15:06:03 +00002470 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002471 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002472
bellard2f619692007-11-16 10:46:05 +00002473 if (get_user_u32(val, optval_addr))
2474 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002475 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002476 break;
Josh Kunza2d86682019-10-29 15:43:10 -07002477#ifdef SOL_NETLINK
2478 case SOL_NETLINK:
2479 switch (optname) {
2480 case NETLINK_PKTINFO:
2481 case NETLINK_ADD_MEMBERSHIP:
2482 case NETLINK_DROP_MEMBERSHIP:
2483 case NETLINK_BROADCAST_ERROR:
2484 case NETLINK_NO_ENOBUFS:
2485#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2486 case NETLINK_LISTEN_ALL_NSID:
2487 case NETLINK_CAP_ACK:
2488#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
2489#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
2490 case NETLINK_EXT_ACK:
2491#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2492#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
2493 case NETLINK_GET_STRICT_CHK:
2494#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2495 break;
2496 default:
2497 goto unimplemented;
2498 }
2499 val = 0;
2500 if (optlen < sizeof(uint32_t)) {
2501 return -TARGET_EINVAL;
2502 }
2503 if (get_user_u32(val, optval_addr)) {
2504 return -TARGET_EFAULT;
2505 }
2506 ret = get_errno(setsockopt(sockfd, SOL_NETLINK, optname, &val,
2507 sizeof(val)));
2508 break;
2509#endif /* SOL_NETLINK */
bellard7854b052003-03-29 17:22:23 +00002510 default:
bellard8853f862004-02-22 14:57:26 +00002511 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08002512 qemu_log_mask(LOG_UNIMP, "Unsupported setsockopt level=%d optname=%d\n",
2513 level, optname);
ths6fa13c12007-12-18 02:41:04 +00002514 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002515 }
bellard8853f862004-02-22 14:57:26 +00002516 return ret;
bellard7854b052003-03-29 17:22:23 +00002517}
2518
ths0da46a62007-10-20 20:23:07 +00002519/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002520static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002521 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002522{
blueswir1992f48a2007-10-14 16:27:31 +00002523 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002524 int len, val;
2525 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002526
2527 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002528 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002529 level = SOL_SOCKET;
2530 switch (optname) {
2531 /* These don't just return a single integer */
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002532 case TARGET_SO_PEERNAME:
2533 goto unimplemented;
Andreas Schwab405dc4c2019-05-13 11:06:26 +02002534 case TARGET_SO_RCVTIMEO: {
2535 struct timeval tv;
2536 socklen_t tvlen;
2537
2538 optname = SO_RCVTIMEO;
2539
2540get_timeout:
2541 if (get_user_u32(len, optlen)) {
2542 return -TARGET_EFAULT;
2543 }
2544 if (len < 0) {
2545 return -TARGET_EINVAL;
2546 }
2547
2548 tvlen = sizeof(tv);
2549 ret = get_errno(getsockopt(sockfd, level, optname,
2550 &tv, &tvlen));
2551 if (ret < 0) {
2552 return ret;
2553 }
2554 if (len > sizeof(struct target_timeval)) {
2555 len = sizeof(struct target_timeval);
2556 }
2557 if (copy_to_user_timeval(optval_addr, &tv)) {
2558 return -TARGET_EFAULT;
2559 }
2560 if (put_user_u32(len, optlen)) {
2561 return -TARGET_EFAULT;
2562 }
2563 break;
2564 }
2565 case TARGET_SO_SNDTIMEO:
2566 optname = SO_SNDTIMEO;
2567 goto get_timeout;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002568 case TARGET_SO_PEERCRED: {
2569 struct ucred cr;
2570 socklen_t crlen;
2571 struct target_ucred *tcr;
2572
2573 if (get_user_u32(len, optlen)) {
2574 return -TARGET_EFAULT;
2575 }
2576 if (len < 0) {
2577 return -TARGET_EINVAL;
2578 }
2579
2580 crlen = sizeof(cr);
2581 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2582 &cr, &crlen));
2583 if (ret < 0) {
2584 return ret;
2585 }
2586 if (len > crlen) {
2587 len = crlen;
2588 }
2589 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2590 return -TARGET_EFAULT;
2591 }
2592 __put_user(cr.pid, &tcr->pid);
2593 __put_user(cr.uid, &tcr->uid);
2594 __put_user(cr.gid, &tcr->gid);
2595 unlock_user_struct(tcr, optval_addr, 1);
2596 if (put_user_u32(len, optlen)) {
2597 return -TARGET_EFAULT;
2598 }
2599 break;
2600 }
Laurent Vivier6d485a52020-02-04 22:19:01 +01002601 case TARGET_SO_PEERSEC: {
2602 char *name;
2603
2604 if (get_user_u32(len, optlen)) {
2605 return -TARGET_EFAULT;
2606 }
2607 if (len < 0) {
2608 return -TARGET_EINVAL;
2609 }
2610 name = lock_user(VERIFY_WRITE, optval_addr, len, 0);
2611 if (!name) {
2612 return -TARGET_EFAULT;
2613 }
2614 lv = len;
2615 ret = get_errno(getsockopt(sockfd, level, SO_PEERSEC,
2616 name, &lv));
2617 if (put_user_u32(lv, optlen)) {
2618 ret = -TARGET_EFAULT;
2619 }
2620 unlock_user(name, optval_addr, lv);
2621 break;
2622 }
Carlo Marcelo Arenas Belón83eb6e52018-08-24 01:56:01 -07002623 case TARGET_SO_LINGER:
2624 {
2625 struct linger lg;
2626 socklen_t lglen;
2627 struct target_linger *tlg;
2628
2629 if (get_user_u32(len, optlen)) {
2630 return -TARGET_EFAULT;
2631 }
2632 if (len < 0) {
2633 return -TARGET_EINVAL;
2634 }
2635
2636 lglen = sizeof(lg);
2637 ret = get_errno(getsockopt(sockfd, level, SO_LINGER,
2638 &lg, &lglen));
2639 if (ret < 0) {
2640 return ret;
2641 }
2642 if (len > lglen) {
2643 len = lglen;
2644 }
2645 if (!lock_user_struct(VERIFY_WRITE, tlg, optval_addr, 0)) {
2646 return -TARGET_EFAULT;
2647 }
2648 __put_user(lg.l_onoff, &tlg->l_onoff);
2649 __put_user(lg.l_linger, &tlg->l_linger);
2650 unlock_user_struct(tlg, optval_addr, 1);
2651 if (put_user_u32(len, optlen)) {
2652 return -TARGET_EFAULT;
2653 }
2654 break;
2655 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002656 /* Options with 'int' argument. */
2657 case TARGET_SO_DEBUG:
2658 optname = SO_DEBUG;
2659 goto int_case;
2660 case TARGET_SO_REUSEADDR:
2661 optname = SO_REUSEADDR;
2662 goto int_case;
Yunqiang Su113a9dd2018-10-30 13:55:08 +01002663#ifdef SO_REUSEPORT
2664 case TARGET_SO_REUSEPORT:
2665 optname = SO_REUSEPORT;
2666 goto int_case;
2667#endif
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002668 case TARGET_SO_TYPE:
2669 optname = SO_TYPE;
2670 goto int_case;
2671 case TARGET_SO_ERROR:
2672 optname = SO_ERROR;
2673 goto int_case;
2674 case TARGET_SO_DONTROUTE:
2675 optname = SO_DONTROUTE;
2676 goto int_case;
2677 case TARGET_SO_BROADCAST:
2678 optname = SO_BROADCAST;
2679 goto int_case;
2680 case TARGET_SO_SNDBUF:
2681 optname = SO_SNDBUF;
2682 goto int_case;
2683 case TARGET_SO_RCVBUF:
2684 optname = SO_RCVBUF;
2685 goto int_case;
2686 case TARGET_SO_KEEPALIVE:
2687 optname = SO_KEEPALIVE;
2688 goto int_case;
2689 case TARGET_SO_OOBINLINE:
2690 optname = SO_OOBINLINE;
2691 goto int_case;
2692 case TARGET_SO_NO_CHECK:
2693 optname = SO_NO_CHECK;
2694 goto int_case;
2695 case TARGET_SO_PRIORITY:
2696 optname = SO_PRIORITY;
2697 goto int_case;
2698#ifdef SO_BSDCOMPAT
2699 case TARGET_SO_BSDCOMPAT:
2700 optname = SO_BSDCOMPAT;
2701 goto int_case;
2702#endif
2703 case TARGET_SO_PASSCRED:
2704 optname = SO_PASSCRED;
2705 goto int_case;
2706 case TARGET_SO_TIMESTAMP:
2707 optname = SO_TIMESTAMP;
2708 goto int_case;
2709 case TARGET_SO_RCVLOWAT:
2710 optname = SO_RCVLOWAT;
2711 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002712 case TARGET_SO_ACCEPTCONN:
2713 optname = SO_ACCEPTCONN;
2714 goto int_case;
Jason A. Donenfeldec63e062021-02-04 16:39:25 +01002715 case TARGET_SO_PROTOCOL:
2716 optname = SO_PROTOCOL;
2717 goto int_case;
2718 case TARGET_SO_DOMAIN:
2719 optname = SO_DOMAIN;
2720 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002721 default:
bellard2efbe912005-07-23 15:10:20 +00002722 goto int_case;
2723 }
2724 break;
2725 case SOL_TCP:
Shu-Chun Wengfe51b0a2020-12-18 11:32:11 -08002726 case SOL_UDP:
2727 /* TCP and UDP options all take an 'int' value. */
bellard2efbe912005-07-23 15:10:20 +00002728 int_case:
bellard2f619692007-11-16 10:46:05 +00002729 if (get_user_u32(len, optlen))
2730 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002731 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002732 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002733 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002734 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2735 if (ret < 0)
2736 return ret;
Helge Dellercb88b7c2023-01-27 21:25:27 +01002737 switch (optname) {
2738 case SO_TYPE:
Paul Burton8289d112014-06-22 11:25:33 +01002739 val = host_to_target_sock_type(val);
Helge Dellercb88b7c2023-01-27 21:25:27 +01002740 break;
2741 case SO_ERROR:
2742 val = host_to_target_errno(val);
2743 break;
Paul Burton8289d112014-06-22 11:25:33 +01002744 }
bellard2efbe912005-07-23 15:10:20 +00002745 if (len > lv)
2746 len = lv;
bellard2f619692007-11-16 10:46:05 +00002747 if (len == 4) {
2748 if (put_user_u32(val, optval_addr))
2749 return -TARGET_EFAULT;
2750 } else {
2751 if (put_user_u8(val, optval_addr))
2752 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002753 }
bellard2f619692007-11-16 10:46:05 +00002754 if (put_user_u32(len, optlen))
2755 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002756 break;
2757 case SOL_IP:
2758 switch(optname) {
2759 case IP_TOS:
2760 case IP_TTL:
2761 case IP_HDRINCL:
2762 case IP_ROUTER_ALERT:
2763 case IP_RECVOPTS:
2764 case IP_RETOPTS:
2765 case IP_PKTINFO:
2766 case IP_MTU_DISCOVER:
2767 case IP_RECVERR:
2768 case IP_RECVTOS:
2769#ifdef IP_FREEBIND
2770 case IP_FREEBIND:
2771#endif
2772 case IP_MULTICAST_TTL:
2773 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002774 if (get_user_u32(len, optlen))
2775 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002776 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002777 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002778 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002779 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2780 if (ret < 0)
2781 return ret;
bellard2efbe912005-07-23 15:10:20 +00002782 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002783 len = 1;
bellard2f619692007-11-16 10:46:05 +00002784 if (put_user_u32(len, optlen)
2785 || put_user_u8(val, optval_addr))
2786 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002787 } else {
bellard2efbe912005-07-23 15:10:20 +00002788 if (len > sizeof(int))
2789 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002790 if (put_user_u32(len, optlen)
2791 || put_user_u32(val, optval_addr))
2792 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002793 }
bellard8853f862004-02-22 14:57:26 +00002794 break;
bellard2efbe912005-07-23 15:10:20 +00002795 default:
thsc02f4992007-12-18 02:39:59 +00002796 ret = -TARGET_ENOPROTOOPT;
2797 break;
bellard8853f862004-02-22 14:57:26 +00002798 }
2799 break;
Tom Deseynbd8ed482018-12-13 14:06:11 +01002800 case SOL_IPV6:
2801 switch (optname) {
2802 case IPV6_MTU_DISCOVER:
2803 case IPV6_MTU:
2804 case IPV6_V6ONLY:
2805 case IPV6_RECVPKTINFO:
2806 case IPV6_UNICAST_HOPS:
2807 case IPV6_MULTICAST_HOPS:
2808 case IPV6_MULTICAST_LOOP:
2809 case IPV6_RECVERR:
2810 case IPV6_RECVHOPLIMIT:
2811 case IPV6_2292HOPLIMIT:
2812 case IPV6_CHECKSUM:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002813 case IPV6_ADDRFORM:
2814 case IPV6_2292PKTINFO:
2815 case IPV6_RECVTCLASS:
2816 case IPV6_RECVRTHDR:
2817 case IPV6_2292RTHDR:
2818 case IPV6_RECVHOPOPTS:
2819 case IPV6_2292HOPOPTS:
2820 case IPV6_RECVDSTOPTS:
2821 case IPV6_2292DSTOPTS:
2822 case IPV6_TCLASS:
Shu-Chun Weng22db1212020-12-18 11:32:12 -08002823 case IPV6_ADDR_PREFERENCES:
Helge Dellerb9cce6d2019-03-10 12:12:16 +01002824#ifdef IPV6_RECVPATHMTU
2825 case IPV6_RECVPATHMTU:
2826#endif
2827#ifdef IPV6_TRANSPARENT
2828 case IPV6_TRANSPARENT:
2829#endif
2830#ifdef IPV6_FREEBIND
2831 case IPV6_FREEBIND:
2832#endif
2833#ifdef IPV6_RECVORIGDSTADDR
2834 case IPV6_RECVORIGDSTADDR:
2835#endif
Tom Deseynbd8ed482018-12-13 14:06:11 +01002836 if (get_user_u32(len, optlen))
2837 return -TARGET_EFAULT;
2838 if (len < 0)
2839 return -TARGET_EINVAL;
2840 lv = sizeof(lv);
2841 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2842 if (ret < 0)
2843 return ret;
2844 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
2845 len = 1;
2846 if (put_user_u32(len, optlen)
2847 || put_user_u8(val, optval_addr))
2848 return -TARGET_EFAULT;
2849 } else {
2850 if (len > sizeof(int))
2851 len = sizeof(int);
2852 if (put_user_u32(len, optlen)
2853 || put_user_u32(val, optval_addr))
2854 return -TARGET_EFAULT;
2855 }
2856 break;
2857 default:
2858 ret = -TARGET_ENOPROTOOPT;
2859 break;
2860 }
2861 break;
Josh Kunza2d86682019-10-29 15:43:10 -07002862#ifdef SOL_NETLINK
2863 case SOL_NETLINK:
2864 switch (optname) {
2865 case NETLINK_PKTINFO:
2866 case NETLINK_BROADCAST_ERROR:
2867 case NETLINK_NO_ENOBUFS:
2868#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2869 case NETLINK_LISTEN_ALL_NSID:
2870 case NETLINK_CAP_ACK:
2871#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
2872#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
2873 case NETLINK_EXT_ACK:
2874#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2875#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
2876 case NETLINK_GET_STRICT_CHK:
2877#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
2878 if (get_user_u32(len, optlen)) {
2879 return -TARGET_EFAULT;
2880 }
2881 if (len != sizeof(val)) {
2882 return -TARGET_EINVAL;
2883 }
2884 lv = len;
2885 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2886 if (ret < 0) {
2887 return ret;
2888 }
2889 if (put_user_u32(lv, optlen)
2890 || put_user_u32(val, optval_addr)) {
2891 return -TARGET_EFAULT;
2892 }
2893 break;
2894#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
2895 case NETLINK_LIST_MEMBERSHIPS:
2896 {
2897 uint32_t *results;
2898 int i;
2899 if (get_user_u32(len, optlen)) {
2900 return -TARGET_EFAULT;
2901 }
2902 if (len < 0) {
2903 return -TARGET_EINVAL;
2904 }
2905 results = lock_user(VERIFY_WRITE, optval_addr, len, 1);
Frédéric Fortier13e340c2021-03-28 14:01:35 -04002906 if (!results && len > 0) {
Josh Kunza2d86682019-10-29 15:43:10 -07002907 return -TARGET_EFAULT;
2908 }
2909 lv = len;
2910 ret = get_errno(getsockopt(sockfd, level, optname, results, &lv));
2911 if (ret < 0) {
2912 unlock_user(results, optval_addr, 0);
2913 return ret;
2914 }
Michael Tokarev669dcb62023-08-23 08:53:30 +02002915 /* swap host endianness to target endianness. */
Josh Kunza2d86682019-10-29 15:43:10 -07002916 for (i = 0; i < (len / sizeof(uint32_t)); i++) {
2917 results[i] = tswap32(results[i]);
2918 }
2919 if (put_user_u32(lv, optlen)) {
2920 return -TARGET_EFAULT;
2921 }
2922 unlock_user(results, optval_addr, 0);
2923 break;
2924 }
2925#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
2926 default:
2927 goto unimplemented;
2928 }
Laurent Vivierc0cb8802019-11-12 11:50:55 +01002929 break;
Josh Kunza2d86682019-10-29 15:43:10 -07002930#endif /* SOL_NETLINK */
bellard8853f862004-02-22 14:57:26 +00002931 default:
2932 unimplemented:
Josh Kunz39be5352020-02-03 18:54:13 -08002933 qemu_log_mask(LOG_UNIMP,
2934 "getsockopt level=%d optname=%d not yet supported\n",
2935 level, optname);
thsc02f4992007-12-18 02:39:59 +00002936 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002937 break;
2938 }
2939 return ret;
bellard7854b052003-03-29 17:22:23 +00002940}
2941
Max Filippov9ac22512018-04-04 17:30:41 -07002942/* Convert target low/high pair representing file offset into the host
2943 * low/high pair. This function doesn't handle offsets bigger than 64 bits
2944 * as the kernel doesn't handle them either.
2945 */
2946static void target_to_host_low_high(abi_ulong tlow,
2947 abi_ulong thigh,
2948 unsigned long *hlow,
2949 unsigned long *hhigh)
2950{
2951 uint64_t off = tlow |
2952 ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
2953 TARGET_LONG_BITS / 2;
2954
2955 *hlow = off;
2956 *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
2957}
2958
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002959static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01002960 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002961{
2962 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002963 struct iovec *vec;
2964 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002965 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002966 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002967 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002968
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002969 if (count == 0) {
2970 errno = 0;
2971 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002972 }
Peter Maydelldab32b32016-07-15 14:57:26 +01002973 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002974 errno = EINVAL;
2975 return NULL;
2976 }
2977
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302978 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002979 if (vec == NULL) {
2980 errno = ENOMEM;
2981 return NULL;
2982 }
2983
2984 target_vec = lock_user(VERIFY_READ, target_addr,
2985 count * sizeof(struct target_iovec), 1);
2986 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002987 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002988 goto fail2;
2989 }
2990
2991 /* ??? If host page size > target page size, this will result in a
2992 value larger than what we can actually support. */
2993 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2994 total_len = 0;
2995
2996 for (i = 0; i < count; i++) {
2997 abi_ulong base = tswapal(target_vec[i].iov_base);
2998 abi_long len = tswapal(target_vec[i].iov_len);
2999
3000 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003001 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003002 goto fail;
3003 } else if (len == 0) {
3004 /* Zero length pointer is ignored. */
3005 vec[i].iov_base = 0;
3006 } else {
3007 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003008 /* If the first buffer pointer is bad, this is a fault. But
3009 * subsequent bad buffers will result in a partial write; this
3010 * is realized by filling the vector with null pointers and
3011 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003012 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003013 if (i == 0) {
3014 err = EFAULT;
3015 goto fail;
3016 } else {
3017 bad_address = true;
3018 }
3019 }
3020 if (bad_address) {
3021 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003022 }
3023 if (len > max_len - total_len) {
3024 len = max_len - total_len;
3025 }
3026 }
3027 vec[i].iov_len = len;
3028 total_len += len;
3029 }
3030
3031 unlock_user(target_vec, target_addr, 0);
3032 return vec;
3033
3034 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003035 while (--i >= 0) {
3036 if (tswapal(target_vec[i].iov_len) > 0) {
3037 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3038 }
3039 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003040 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003041 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303042 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003043 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003044 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003045}
3046
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003047static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003048 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003049{
3050 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003051 int i;
3052
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003053 target_vec = lock_user(VERIFY_READ, target_addr,
3054 count * sizeof(struct target_iovec), 1);
3055 if (target_vec) {
3056 for (i = 0; i < count; i++) {
3057 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003058 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003059 if (len < 0) {
3060 break;
3061 }
balrogd732dcb2008-10-28 10:21:03 +00003062 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3063 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003064 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003065 }
bellard579a97f2007-11-11 14:26:47 +00003066
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303067 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003068}
3069
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003070static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003071{
3072 int host_type = 0;
3073 int target_type = *type;
3074
3075 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3076 case TARGET_SOCK_DGRAM:
3077 host_type = SOCK_DGRAM;
3078 break;
3079 case TARGET_SOCK_STREAM:
3080 host_type = SOCK_STREAM;
3081 break;
3082 default:
3083 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3084 break;
3085 }
3086 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003087#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003088 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003089#else
3090 return -TARGET_EINVAL;
3091#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003092 }
3093 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003094#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003095 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003096#elif !defined(O_NONBLOCK)
3097 return -TARGET_EINVAL;
3098#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003099 }
3100 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003101 return 0;
3102}
3103
3104/* Try to emulate socket type flags after socket creation. */
3105static int sock_flags_fixup(int fd, int target_type)
3106{
3107#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3108 if (target_type & TARGET_SOCK_NONBLOCK) {
3109 int flags = fcntl(fd, F_GETFL);
3110 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3111 close(fd);
3112 return -TARGET_EINVAL;
3113 }
3114 }
3115#endif
3116 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003117}
3118
ths0da46a62007-10-20 20:23:07 +00003119/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003120static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003121{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003122 int target_type = type;
3123 int ret;
3124
3125 ret = target_to_host_sock_type(&type);
3126 if (ret) {
3127 return ret;
3128 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003129
Laurent Vivier575b22b2016-06-02 22:14:15 +02003130 if (domain == PF_NETLINK && !(
3131#ifdef CONFIG_RTNETLINK
3132 protocol == NETLINK_ROUTE ||
3133#endif
3134 protocol == NETLINK_KOBJECT_UEVENT ||
3135 protocol == NETLINK_AUDIT)) {
Josh Kunz71e24432020-07-06 17:10:36 -07003136 return -TARGET_EPROTONOSUPPORT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003137 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003138
3139 if (domain == AF_PACKET ||
3140 (domain == AF_INET && type == SOCK_PACKET)) {
3141 protocol = tswap16(protocol);
3142 }
3143
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003144 ret = get_errno(socket(domain, type, protocol));
3145 if (ret >= 0) {
3146 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003147 if (type == SOCK_PACKET) {
3148 /* Manage an obsolete case :
3149 * if socket type is SOCK_PACKET, bind by name
3150 */
3151 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003152 } else if (domain == PF_NETLINK) {
3153 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003154#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003155 case NETLINK_ROUTE:
3156 fd_trans_register(ret, &target_netlink_route_trans);
3157 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003158#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003159 case NETLINK_KOBJECT_UEVENT:
3160 /* nothing to do: messages are strings */
3161 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003162 case NETLINK_AUDIT:
3163 fd_trans_register(ret, &target_netlink_audit_trans);
3164 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003165 default:
3166 g_assert_not_reached();
3167 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003168 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003169 }
3170 return ret;
bellard3532fa72006-06-24 15:06:03 +00003171}
3172
ths0da46a62007-10-20 20:23:07 +00003173/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003174static abi_long do_bind(int sockfd, abi_ulong target_addr,
3175 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003176{
aurel328f7aeaf2009-01-30 19:47:57 +00003177 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003178 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003179
Blue Swirl38724252010-09-18 05:53:14 +00003180 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003181 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003182 }
aurel328f7aeaf2009-01-30 19:47:57 +00003183
aurel32607175e2009-04-15 16:11:59 +00003184 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003185
Laurent Vivier7b36f782015-10-28 21:40:44 +01003186 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003187 if (ret)
3188 return ret;
3189
bellard3532fa72006-06-24 15:06:03 +00003190 return get_errno(bind(sockfd, addr, addrlen));
3191}
3192
ths0da46a62007-10-20 20:23:07 +00003193/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003194static abi_long do_connect(int sockfd, abi_ulong target_addr,
3195 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003196{
aurel328f7aeaf2009-01-30 19:47:57 +00003197 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003198 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003199
Blue Swirl38724252010-09-18 05:53:14 +00003200 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003201 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003202 }
aurel328f7aeaf2009-01-30 19:47:57 +00003203
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003204 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003205
Laurent Vivier7b36f782015-10-28 21:40:44 +01003206 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003207 if (ret)
3208 return ret;
3209
Peter Maydell2a3c7612016-06-06 19:58:03 +01003210 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003211}
3212
Alexander Graff19e00d2014-03-02 19:36:42 +00003213/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3214static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3215 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003216{
balrog6de645c2008-10-28 10:26:29 +00003217 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003218 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003219 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003220 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003221 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003222
bellard3532fa72006-06-24 15:06:03 +00003223 if (msgp->msg_name) {
3224 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003225 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003226 ret = target_to_host_sockaddr(fd, msg.msg_name,
3227 tswapal(msgp->msg_name),
3228 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003229 if (ret == -TARGET_EFAULT) {
3230 /* For connected sockets msg_name and msg_namelen must
3231 * be ignored, so returning EFAULT immediately is wrong.
3232 * Instead, pass a bad msg_name to the host kernel, and
3233 * let it decide whether to return EFAULT or not.
3234 */
3235 msg.msg_name = (void *)-1;
3236 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003237 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003238 }
bellard3532fa72006-06-24 15:06:03 +00003239 } else {
3240 msg.msg_name = NULL;
3241 msg.msg_namelen = 0;
3242 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003243 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003244 msg.msg_control = alloca(msg.msg_controllen);
Jonas Schievink1d3d1b22018-07-12 00:12:44 +02003245 memset(msg.msg_control, 0, msg.msg_controllen);
3246
bellard3532fa72006-06-24 15:06:03 +00003247 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003248
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003249 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003250 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003251
3252 if (count > IOV_MAX) {
3253 /* sendrcvmsg returns a different errno for this condition than
3254 * readv/writev, so we must catch it here before lock_iovec() does.
3255 */
3256 ret = -TARGET_EMSGSIZE;
3257 goto out2;
3258 }
3259
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003260 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3261 target_vec, count, send);
3262 if (vec == NULL) {
3263 ret = -host_to_target_errno(errno);
Helge Deller3f0744f2022-12-12 18:34:16 +01003264 /* allow sending packet without any iov, e.g. with MSG_MORE flag */
3265 if (!send || ret) {
3266 goto out2;
3267 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003268 }
bellard3532fa72006-06-24 15:06:03 +00003269 msg.msg_iovlen = count;
3270 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003271
bellard3532fa72006-06-24 15:06:03 +00003272 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003273 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003274 void *host_msg;
3275
3276 host_msg = g_malloc(msg.msg_iov->iov_len);
3277 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3278 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003279 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003280 if (ret >= 0) {
3281 msg.msg_iov->iov_base = host_msg;
3282 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3283 }
3284 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003285 } else {
3286 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003287 if (ret == 0) {
3288 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3289 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003290 }
bellard3532fa72006-06-24 15:06:03 +00003291 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003292 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003293 if (!is_error(ret)) {
3294 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003295 if (fd_trans_host_to_target_data(fd)) {
3296 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02003297 MIN(msg.msg_iov->iov_len, len));
Icenowy Zheng16c81dd2022-10-28 16:12:20 +08003298 }
3299 if (!is_error(ret)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003300 ret = host_to_target_cmsg(msgp, &msg);
3301 }
Jing Huangca619062012-07-24 13:58:02 +00003302 if (!is_error(ret)) {
3303 msgp->msg_namelen = tswap32(msg.msg_namelen);
Andreas Schwab24894f32019-02-12 17:34:35 +01003304 msgp->msg_flags = tswap32(msg.msg_flags);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003305 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003306 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3307 msg.msg_name, msg.msg_namelen);
3308 if (ret) {
3309 goto out;
3310 }
3311 }
3312
balrog6de645c2008-10-28 10:26:29 +00003313 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003314 }
balrog6de645c2008-10-28 10:26:29 +00003315 }
bellard3532fa72006-06-24 15:06:03 +00003316 }
Jing Huangca619062012-07-24 13:58:02 +00003317
3318out:
Helge Deller3f0744f2022-12-12 18:34:16 +01003319 if (vec) {
3320 unlock_iovec(vec, target_vec, count, !send);
3321 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003322out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003323 return ret;
3324}
3325
3326static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3327 int flags, int send)
3328{
3329 abi_long ret;
3330 struct target_msghdr *msgp;
3331
3332 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3333 msgp,
3334 target_msg,
3335 send ? 1 : 0)) {
3336 return -TARGET_EFAULT;
3337 }
3338 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003339 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003340 return ret;
3341}
3342
Alexander Graff19e00d2014-03-02 19:36:42 +00003343/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3344 * so it might not have this *mmsg-specific flag either.
3345 */
3346#ifndef MSG_WAITFORONE
3347#define MSG_WAITFORONE 0x10000
3348#endif
3349
3350static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3351 unsigned int vlen, unsigned int flags,
3352 int send)
3353{
3354 struct target_mmsghdr *mmsgp;
3355 abi_long ret = 0;
3356 int i;
3357
3358 if (vlen > UIO_MAXIOV) {
3359 vlen = UIO_MAXIOV;
3360 }
3361
3362 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3363 if (!mmsgp) {
3364 return -TARGET_EFAULT;
3365 }
3366
3367 for (i = 0; i < vlen; i++) {
3368 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3369 if (is_error(ret)) {
3370 break;
3371 }
3372 mmsgp[i].msg_len = tswap32(ret);
3373 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3374 if (flags & MSG_WAITFORONE) {
3375 flags |= MSG_DONTWAIT;
3376 }
3377 }
3378
3379 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3380
3381 /* Return number of datagrams sent if we sent any at all;
3382 * otherwise return the error.
3383 */
3384 if (i) {
3385 return i;
3386 }
3387 return ret;
3388}
Alexander Graff19e00d2014-03-02 19:36:42 +00003389
Peter Maydella94b4982013-02-08 04:35:04 +00003390/* do_accept4() Must return target values and target errnos. */
3391static abi_long do_accept4(int fd, abi_ulong target_addr,
3392 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003393{
Andreas Schwabcd813362019-02-14 12:43:40 +01003394 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003395 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003396 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003397 int host_flags;
3398
Helge Dellerdca4c832023-07-08 07:24:00 +02003399 if (flags & ~(TARGET_SOCK_CLOEXEC | TARGET_SOCK_NONBLOCK)) {
3400 return -TARGET_EINVAL;
3401 }
3402
3403 host_flags = 0;
3404 if (flags & TARGET_SOCK_NONBLOCK) {
3405 host_flags |= SOCK_NONBLOCK;
3406 }
3407 if (flags & TARGET_SOCK_CLOEXEC) {
3408 host_flags |= SOCK_CLOEXEC;
3409 }
pbrook1be9e1d2006-11-19 15:26:04 +00003410
Peter Maydella94b4982013-02-08 04:35:04 +00003411 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003412 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003413 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003414
Matus Kysele554eb42020-09-30 17:16:16 +02003415 /* linux returns EFAULT if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003416 if (get_user_u32(addrlen, target_addrlen_addr))
Matus Kysele554eb42020-09-30 17:16:16 +02003417 return -TARGET_EFAULT;
bellard2f619692007-11-16 10:46:05 +00003418
Blue Swirl38724252010-09-18 05:53:14 +00003419 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003420 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003421 }
aurel328f7aeaf2009-01-30 19:47:57 +00003422
Richard Hendersonc7169b02021-02-12 10:48:47 -08003423 if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
Matus Kysele554eb42020-09-30 17:16:16 +02003424 return -TARGET_EFAULT;
Richard Hendersonc7169b02021-02-12 10:48:47 -08003425 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003426
bellard2f619692007-11-16 10:46:05 +00003427 addr = alloca(addrlen);
3428
Andreas Schwabcd813362019-02-14 12:43:40 +01003429 ret_addrlen = addrlen;
3430 ret = get_errno(safe_accept4(fd, addr, &ret_addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003431 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003432 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3433 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003434 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003435 }
pbrook1be9e1d2006-11-19 15:26:04 +00003436 }
3437 return ret;
3438}
3439
ths0da46a62007-10-20 20:23:07 +00003440/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003441static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003442 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003443{
Andreas Schwabcd813362019-02-14 12:43:40 +01003444 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003445 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003446 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003447
bellard2f619692007-11-16 10:46:05 +00003448 if (get_user_u32(addrlen, target_addrlen_addr))
3449 return -TARGET_EFAULT;
3450
Blue Swirl38724252010-09-18 05:53:14 +00003451 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003452 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003453 }
aurel328f7aeaf2009-01-30 19:47:57 +00003454
Richard Hendersonc7169b02021-02-12 10:48:47 -08003455 if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
Arnaud Patard917507b2009-06-19 10:44:45 +03003456 return -TARGET_EFAULT;
Richard Hendersonc7169b02021-02-12 10:48:47 -08003457 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003458
bellard2f619692007-11-16 10:46:05 +00003459 addr = alloca(addrlen);
3460
Andreas Schwabcd813362019-02-14 12:43:40 +01003461 ret_addrlen = addrlen;
3462 ret = get_errno(getpeername(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003463 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003464 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3465 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003466 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003467 }
pbrook1be9e1d2006-11-19 15:26:04 +00003468 }
3469 return ret;
3470}
3471
ths0da46a62007-10-20 20:23:07 +00003472/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003473static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003474 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003475{
Andreas Schwabcd813362019-02-14 12:43:40 +01003476 socklen_t addrlen, ret_addrlen;
bellard2f619692007-11-16 10:46:05 +00003477 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003478 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003479
bellard2f619692007-11-16 10:46:05 +00003480 if (get_user_u32(addrlen, target_addrlen_addr))
3481 return -TARGET_EFAULT;
3482
Blue Swirl38724252010-09-18 05:53:14 +00003483 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003484 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003485 }
aurel328f7aeaf2009-01-30 19:47:57 +00003486
Richard Hendersonc7169b02021-02-12 10:48:47 -08003487 if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
Arnaud Patard917507b2009-06-19 10:44:45 +03003488 return -TARGET_EFAULT;
Richard Hendersonc7169b02021-02-12 10:48:47 -08003489 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003490
bellard2f619692007-11-16 10:46:05 +00003491 addr = alloca(addrlen);
3492
Andreas Schwabcd813362019-02-14 12:43:40 +01003493 ret_addrlen = addrlen;
3494 ret = get_errno(getsockname(fd, addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003495 if (!is_error(ret)) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003496 host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
3497 if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
bellard2f619692007-11-16 10:46:05 +00003498 ret = -TARGET_EFAULT;
Andreas Schwabcd813362019-02-14 12:43:40 +01003499 }
pbrook1be9e1d2006-11-19 15:26:04 +00003500 }
3501 return ret;
3502}
3503
ths0da46a62007-10-20 20:23:07 +00003504/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003505static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003506 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003507{
3508 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003509 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003510
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003511 target_to_host_sock_type(&type);
3512
pbrook1be9e1d2006-11-19 15:26:04 +00003513 ret = get_errno(socketpair(domain, type, protocol, tab));
3514 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003515 if (put_user_s32(tab[0], target_tab_addr)
3516 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3517 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003518 }
3519 return ret;
3520}
3521
ths0da46a62007-10-20 20:23:07 +00003522/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003523static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3524 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003525{
3526 void *addr;
3527 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003528 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003529 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003530
Blue Swirl38724252010-09-18 05:53:14 +00003531 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003532 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003533 }
aurel328f7aeaf2009-01-30 19:47:57 +00003534
bellard579a97f2007-11-11 14:26:47 +00003535 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3536 if (!host_msg)
3537 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003538 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003539 copy_msg = host_msg;
3540 host_msg = g_malloc(len);
3541 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003542 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3543 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003544 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003545 }
3546 }
pbrook1be9e1d2006-11-19 15:26:04 +00003547 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003548 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003549 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003550 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003551 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003552 }
Peter Maydell66687532016-06-06 19:58:04 +01003553 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003554 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003555 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003556 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003557fail:
3558 if (copy_msg) {
3559 g_free(host_msg);
3560 host_msg = copy_msg;
3561 }
pbrook1be9e1d2006-11-19 15:26:04 +00003562 unlock_user(host_msg, msg, 0);
3563 return ret;
3564}
3565
ths0da46a62007-10-20 20:23:07 +00003566/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003567static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3568 abi_ulong target_addr,
3569 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003570{
Andreas Schwabcd813362019-02-14 12:43:40 +01003571 socklen_t addrlen, ret_addrlen;
pbrook1be9e1d2006-11-19 15:26:04 +00003572 void *addr;
3573 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003574 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003575
Zach Reizner4a1e6bc2021-03-26 22:11:16 -04003576 if (!msg) {
3577 host_msg = NULL;
3578 } else {
3579 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3580 if (!host_msg) {
3581 return -TARGET_EFAULT;
3582 }
3583 }
pbrook1be9e1d2006-11-19 15:26:04 +00003584 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003585 if (get_user_u32(addrlen, target_addrlen)) {
3586 ret = -TARGET_EFAULT;
3587 goto fail;
3588 }
Blue Swirl38724252010-09-18 05:53:14 +00003589 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003590 ret = -TARGET_EINVAL;
3591 goto fail;
3592 }
pbrook1be9e1d2006-11-19 15:26:04 +00003593 addr = alloca(addrlen);
Andreas Schwabcd813362019-02-14 12:43:40 +01003594 ret_addrlen = addrlen;
Peter Maydell66687532016-06-06 19:58:04 +01003595 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
Andreas Schwabcd813362019-02-14 12:43:40 +01003596 addr, &ret_addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003597 } else {
3598 addr = NULL; /* To keep compiler quiet. */
Andreas Schwabcd813362019-02-14 12:43:40 +01003599 addrlen = 0; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003600 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003601 }
3602 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003603 if (fd_trans_host_to_target_data(fd)) {
Laurent Vivier2a03d3e2018-08-20 19:15:54 +02003604 abi_long trans;
3605 trans = fd_trans_host_to_target_data(fd)(host_msg, MIN(ret, len));
3606 if (is_error(trans)) {
3607 ret = trans;
3608 goto fail;
3609 }
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003610 }
pbrook1be9e1d2006-11-19 15:26:04 +00003611 if (target_addr) {
Andreas Schwabcd813362019-02-14 12:43:40 +01003612 host_to_target_sockaddr(target_addr, addr,
3613 MIN(addrlen, ret_addrlen));
3614 if (put_user_u32(ret_addrlen, target_addrlen)) {
bellard2f619692007-11-16 10:46:05 +00003615 ret = -TARGET_EFAULT;
3616 goto fail;
3617 }
pbrook1be9e1d2006-11-19 15:26:04 +00003618 }
3619 unlock_user(host_msg, msg, len);
3620 } else {
bellard2f619692007-11-16 10:46:05 +00003621fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003622 unlock_user(host_msg, msg, 0);
3623 }
3624 return ret;
3625}
3626
j_mayer32407102007-09-26 23:01:49 +00003627#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003628/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003629static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003630{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003631 static const unsigned nargs[] = { /* number of arguments per operation */
3632 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
3633 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
3634 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
3635 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
3636 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
3637 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
3638 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
3639 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
3640 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
3641 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
3642 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
3643 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
3644 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
3645 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3646 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3647 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
3648 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
3649 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
3650 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
3651 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003652 };
3653 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003654 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00003655
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003656 /* check the range of the first argument num */
3657 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
3658 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
3659 return -TARGET_EINVAL;
3660 }
3661 /* ensure we have space for args */
3662 if (nargs[num] > ARRAY_SIZE(a)) {
3663 return -TARGET_EINVAL;
3664 }
3665 /* collect the arguments in a[] according to nargs[] */
3666 for (i = 0; i < nargs[num]; ++i) {
3667 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
3668 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01003669 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003670 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003671 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003672 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003673 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003674 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003675 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003676 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003677 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003678 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003679 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003680 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003681 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003682 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003683 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003684 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003685 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003686 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003687 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003688 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003689 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003690 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003691 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003692 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003693 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003694 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003695 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003696 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003697 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003698 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003699 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003700 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003701 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003702 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003703 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
3704 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3705 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
3706 return do_sendrecvmsg(a[0], a[1], a[2], 0);
3707 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
3708 return do_accept4(a[0], a[1], a[2], a[3]);
3709 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
3710 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
3711 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
3712 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00003713 default:
Josh Kunz39be5352020-02-03 18:54:13 -08003714 qemu_log_mask(LOG_UNIMP, "Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003715 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00003716 }
bellard31e31b82003-02-18 22:55:36 +00003717}
j_mayer32407102007-09-26 23:01:49 +00003718#endif
bellard31e31b82003-02-18 22:55:36 +00003719
Peter Maydell005eb2a2016-07-15 16:50:47 +01003720#ifndef TARGET_SEMID64_DS
3721/* asm-generic version of this struct */
3722struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00003723{
3724 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003725 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003726#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003727 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003728#endif
blueswir1992f48a2007-10-14 16:27:31 +00003729 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003730#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00003731 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003732#endif
blueswir1992f48a2007-10-14 16:27:31 +00003733 abi_ulong sem_nsems;
3734 abi_ulong __unused3;
3735 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003736};
Peter Maydell005eb2a2016-07-15 16:50:47 +01003737#endif
ths3eb6b042007-06-03 14:26:27 +00003738
bellard579a97f2007-11-11 14:26:47 +00003739static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3740 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003741{
3742 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003743 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003744
bellard579a97f2007-11-11 14:26:47 +00003745 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3746 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003747 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003748 host_ip->__key = tswap32(target_ip->__key);
3749 host_ip->uid = tswap32(target_ip->uid);
3750 host_ip->gid = tswap32(target_ip->gid);
3751 host_ip->cuid = tswap32(target_ip->cuid);
3752 host_ip->cgid = tswap32(target_ip->cgid);
3753#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3754 host_ip->mode = tswap32(target_ip->mode);
3755#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003756 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003757#endif
3758#if defined(TARGET_PPC)
3759 host_ip->__seq = tswap32(target_ip->__seq);
3760#else
3761 host_ip->__seq = tswap16(target_ip->__seq);
3762#endif
ths3eb6b042007-06-03 14:26:27 +00003763 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003764 return 0;
ths3eb6b042007-06-03 14:26:27 +00003765}
3766
bellard579a97f2007-11-11 14:26:47 +00003767static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3768 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003769{
3770 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01003771 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003772
bellard579a97f2007-11-11 14:26:47 +00003773 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3774 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003775 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003776 target_ip->__key = tswap32(host_ip->__key);
3777 target_ip->uid = tswap32(host_ip->uid);
3778 target_ip->gid = tswap32(host_ip->gid);
3779 target_ip->cuid = tswap32(host_ip->cuid);
3780 target_ip->cgid = tswap32(host_ip->cgid);
3781#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3782 target_ip->mode = tswap32(host_ip->mode);
3783#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003784 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003785#endif
3786#if defined(TARGET_PPC)
3787 target_ip->__seq = tswap32(host_ip->__seq);
3788#else
3789 target_ip->__seq = tswap16(host_ip->__seq);
3790#endif
ths3eb6b042007-06-03 14:26:27 +00003791 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003792 return 0;
ths3eb6b042007-06-03 14:26:27 +00003793}
3794
bellard579a97f2007-11-11 14:26:47 +00003795static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3796 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003797{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003798 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003799
bellard579a97f2007-11-11 14:26:47 +00003800 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3801 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003802 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3803 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003804 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3805 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3806 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003807 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003808 return 0;
ths3eb6b042007-06-03 14:26:27 +00003809}
3810
bellard579a97f2007-11-11 14:26:47 +00003811static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3812 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003813{
Peter Maydell005eb2a2016-07-15 16:50:47 +01003814 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00003815
bellard579a97f2007-11-11 14:26:47 +00003816 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3817 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003818 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003819 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003820 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3821 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3822 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003823 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003824 return 0;
ths3eb6b042007-06-03 14:26:27 +00003825}
3826
aurel32e5289082009-04-18 16:16:12 +00003827struct target_seminfo {
3828 int semmap;
3829 int semmni;
3830 int semmns;
3831 int semmnu;
3832 int semmsl;
3833 int semopm;
3834 int semume;
3835 int semusz;
3836 int semvmx;
3837 int semaem;
3838};
3839
3840static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3841 struct seminfo *host_seminfo)
3842{
3843 struct target_seminfo *target_seminfo;
3844 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3845 return -TARGET_EFAULT;
3846 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3847 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3848 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3849 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3850 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3851 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3852 __put_user(host_seminfo->semume, &target_seminfo->semume);
3853 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3854 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3855 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3856 unlock_user_struct(target_seminfo, target_addr, 1);
3857 return 0;
3858}
3859
thsfa294812007-02-02 22:05:00 +00003860union semun {
3861 int val;
ths3eb6b042007-06-03 14:26:27 +00003862 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003863 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003864 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003865};
3866
ths3eb6b042007-06-03 14:26:27 +00003867union target_semun {
3868 int val;
aurel32e5289082009-04-18 16:16:12 +00003869 abi_ulong buf;
3870 abi_ulong array;
3871 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003872};
3873
aurel32e5289082009-04-18 16:16:12 +00003874static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3875 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003876{
aurel32e5289082009-04-18 16:16:12 +00003877 int nsems;
3878 unsigned short *array;
3879 union semun semun;
3880 struct semid_ds semid_ds;
3881 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003882
aurel32e5289082009-04-18 16:16:12 +00003883 semun.buf = &semid_ds;
3884
3885 ret = semctl(semid, 0, IPC_STAT, semun);
3886 if (ret == -1)
3887 return get_errno(ret);
3888
3889 nsems = semid_ds.sem_nsems;
3890
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303891 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003892 if (!*host_array) {
3893 return -TARGET_ENOMEM;
3894 }
aurel32e5289082009-04-18 16:16:12 +00003895 array = lock_user(VERIFY_READ, target_addr,
3896 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003897 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303898 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003899 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003900 }
aurel32e5289082009-04-18 16:16:12 +00003901
3902 for(i=0; i<nsems; i++) {
3903 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003904 }
aurel32e5289082009-04-18 16:16:12 +00003905 unlock_user(array, target_addr, 0);
3906
bellard579a97f2007-11-11 14:26:47 +00003907 return 0;
ths3eb6b042007-06-03 14:26:27 +00003908}
3909
aurel32e5289082009-04-18 16:16:12 +00003910static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3911 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003912{
aurel32e5289082009-04-18 16:16:12 +00003913 int nsems;
3914 unsigned short *array;
3915 union semun semun;
3916 struct semid_ds semid_ds;
3917 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003918
aurel32e5289082009-04-18 16:16:12 +00003919 semun.buf = &semid_ds;
3920
3921 ret = semctl(semid, 0, IPC_STAT, semun);
3922 if (ret == -1)
3923 return get_errno(ret);
3924
3925 nsems = semid_ds.sem_nsems;
3926
3927 array = lock_user(VERIFY_WRITE, target_addr,
3928 nsems*sizeof(unsigned short), 0);
3929 if (!array)
3930 return -TARGET_EFAULT;
3931
3932 for(i=0; i<nsems; i++) {
3933 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003934 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303935 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003936 unlock_user(array, target_addr, 1);
3937
bellard579a97f2007-11-11 14:26:47 +00003938 return 0;
ths3eb6b042007-06-03 14:26:27 +00003939}
3940
aurel32e5289082009-04-18 16:16:12 +00003941static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003942 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003943{
Stefan Weild1c002b2015-02-08 15:40:58 +01003944 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003945 union semun arg;
3946 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303947 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003948 struct seminfo seminfo;
3949 abi_long ret = -TARGET_EINVAL;
3950 abi_long err;
3951 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003952
3953 switch( cmd ) {
3954 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003955 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003956 /* In 64 bit cross-endian situations, we will erroneously pick up
3957 * the wrong half of the union for the "val" element. To rectify
3958 * this, the entire 8-byte structure is byteswapped, followed by
3959 * a swap of the 4 byte val field. In other cases, the data is
3960 * already in proper host byte order. */
3961 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3962 target_su.buf = tswapal(target_su.buf);
3963 arg.val = tswap32(target_su.val);
3964 } else {
3965 arg.val = target_su.val;
3966 }
aurel32e5289082009-04-18 16:16:12 +00003967 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003968 break;
3969 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003970 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003971 err = target_to_host_semarray(semid, &array, target_su.array);
3972 if (err)
3973 return err;
3974 arg.array = array;
3975 ret = get_errno(semctl(semid, semnum, cmd, arg));
3976 err = host_to_target_semarray(semid, target_su.array, &array);
3977 if (err)
3978 return err;
ths3eb6b042007-06-03 14:26:27 +00003979 break;
3980 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003981 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003982 case SEM_STAT:
3983 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3984 if (err)
3985 return err;
3986 arg.buf = &dsarg;
3987 ret = get_errno(semctl(semid, semnum, cmd, arg));
3988 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3989 if (err)
3990 return err;
ths3eb6b042007-06-03 14:26:27 +00003991 break;
aurel32e5289082009-04-18 16:16:12 +00003992 case IPC_INFO:
3993 case SEM_INFO:
3994 arg.__buf = &seminfo;
3995 ret = get_errno(semctl(semid, semnum, cmd, arg));
3996 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3997 if (err)
3998 return err;
3999 break;
4000 case IPC_RMID:
4001 case GETPID:
4002 case GETNCNT:
4003 case GETZCNT:
4004 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4005 break;
ths3eb6b042007-06-03 14:26:27 +00004006 }
4007
4008 return ret;
4009}
4010
aurel32e5289082009-04-18 16:16:12 +00004011struct target_sembuf {
4012 unsigned short sem_num;
4013 short sem_op;
4014 short sem_flg;
4015};
4016
4017static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4018 abi_ulong target_addr,
4019 unsigned nsops)
4020{
4021 struct target_sembuf *target_sembuf;
4022 int i;
4023
4024 target_sembuf = lock_user(VERIFY_READ, target_addr,
4025 nsops*sizeof(struct target_sembuf), 1);
4026 if (!target_sembuf)
4027 return -TARGET_EFAULT;
4028
4029 for(i=0; i<nsops; i++) {
4030 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4031 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4032 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4033 }
4034
4035 unlock_user(target_sembuf, target_addr, 0);
4036
4037 return 0;
4038}
4039
Matus Kyseld8c08b12020-06-26 14:46:11 +02004040#if defined(TARGET_NR_ipc) || defined(TARGET_NR_semop) || \
Filip Bozutacac46eb2020-08-25 00:30:50 +02004041 defined(TARGET_NR_semtimedop) || defined(TARGET_NR_semtimedop_time64)
Matus Kyseld8c08b12020-06-26 14:46:11 +02004042
4043/*
4044 * This macro is required to handle the s390 variants, which passes the
4045 * arguments in a different order than default.
4046 */
4047#ifdef __s390x__
4048#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \
4049 (__nsops), (__timeout), (__sops)
4050#else
4051#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \
4052 (__nsops), 0, (__sops), (__timeout)
4053#endif
4054
4055static inline abi_long do_semtimedop(int semid,
4056 abi_long ptr,
4057 unsigned nsops,
Filip Bozutacac46eb2020-08-25 00:30:50 +02004058 abi_long timeout, bool time64)
aurel32e5289082009-04-18 16:16:12 +00004059{
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004060 struct sembuf *sops;
Matus Kyseld8c08b12020-06-26 14:46:11 +02004061 struct timespec ts, *pts = NULL;
Laurent Vivier524fa342019-05-29 10:48:04 +02004062 abi_long ret;
aurel32e5289082009-04-18 16:16:12 +00004063
Matus Kyseld8c08b12020-06-26 14:46:11 +02004064 if (timeout) {
4065 pts = &ts;
Filip Bozutacac46eb2020-08-25 00:30:50 +02004066 if (time64) {
4067 if (target_to_host_timespec64(pts, timeout)) {
4068 return -TARGET_EFAULT;
4069 }
4070 } else {
4071 if (target_to_host_timespec(pts, timeout)) {
4072 return -TARGET_EFAULT;
4073 }
Matus Kyseld8c08b12020-06-26 14:46:11 +02004074 }
4075 }
4076
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004077 if (nsops > TARGET_SEMOPM) {
4078 return -TARGET_E2BIG;
4079 }
4080
4081 sops = g_new(struct sembuf, nsops);
4082
4083 if (target_to_host_sembuf(sops, ptr, nsops)) {
4084 g_free(sops);
aurel32e5289082009-04-18 16:16:12 +00004085 return -TARGET_EFAULT;
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004086 }
aurel32e5289082009-04-18 16:16:12 +00004087
Laurent Vivier524fa342019-05-29 10:48:04 +02004088 ret = -TARGET_ENOSYS;
4089#ifdef __NR_semtimedop
Matus Kyseld8c08b12020-06-26 14:46:11 +02004090 ret = get_errno(safe_semtimedop(semid, sops, nsops, pts));
Laurent Vivier524fa342019-05-29 10:48:04 +02004091#endif
4092#ifdef __NR_ipc
4093 if (ret == -TARGET_ENOSYS) {
Matus Kyseld8c08b12020-06-26 14:46:11 +02004094 ret = get_errno(safe_ipc(IPCOP_semtimedop, semid,
4095 SEMTIMEDOP_IPC_ARGS(nsops, sops, (long)pts)));
Laurent Vivier524fa342019-05-29 10:48:04 +02004096 }
4097#endif
Filip Bozuta0a7ec842020-08-18 20:07:22 +02004098 g_free(sops);
Laurent Vivier524fa342019-05-29 10:48:04 +02004099 return ret;
aurel32e5289082009-04-18 16:16:12 +00004100}
Matus Kyseld8c08b12020-06-26 14:46:11 +02004101#endif
aurel32e5289082009-04-18 16:16:12 +00004102
ths1bc012f2007-06-03 14:27:49 +00004103struct target_msqid_ds
4104{
aurel321c54ff92008-10-13 21:08:44 +00004105 struct target_ipc_perm msg_perm;
4106 abi_ulong msg_stime;
4107#if TARGET_ABI_BITS == 32
4108 abi_ulong __unused1;
4109#endif
4110 abi_ulong msg_rtime;
4111#if TARGET_ABI_BITS == 32
4112 abi_ulong __unused2;
4113#endif
4114 abi_ulong msg_ctime;
4115#if TARGET_ABI_BITS == 32
4116 abi_ulong __unused3;
4117#endif
4118 abi_ulong __msg_cbytes;
4119 abi_ulong msg_qnum;
4120 abi_ulong msg_qbytes;
4121 abi_ulong msg_lspid;
4122 abi_ulong msg_lrpid;
4123 abi_ulong __unused4;
4124 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004125};
4126
bellard579a97f2007-11-11 14:26:47 +00004127static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4128 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004129{
4130 struct target_msqid_ds *target_md;
4131
bellard579a97f2007-11-11 14:26:47 +00004132 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4133 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004134 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4135 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004136 host_md->msg_stime = tswapal(target_md->msg_stime);
4137 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4138 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4139 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4140 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4141 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4142 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4143 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004144 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004145 return 0;
ths1bc012f2007-06-03 14:27:49 +00004146}
4147
bellard579a97f2007-11-11 14:26:47 +00004148static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4149 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004150{
4151 struct target_msqid_ds *target_md;
4152
bellard579a97f2007-11-11 14:26:47 +00004153 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4154 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004155 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4156 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004157 target_md->msg_stime = tswapal(host_md->msg_stime);
4158 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4159 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4160 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4161 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4162 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4163 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4164 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004165 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004166 return 0;
ths1bc012f2007-06-03 14:27:49 +00004167}
4168
aurel321c54ff92008-10-13 21:08:44 +00004169struct target_msginfo {
4170 int msgpool;
4171 int msgmap;
4172 int msgmax;
4173 int msgmnb;
4174 int msgmni;
4175 int msgssz;
4176 int msgtql;
4177 unsigned short int msgseg;
4178};
4179
4180static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4181 struct msginfo *host_msginfo)
4182{
4183 struct target_msginfo *target_msginfo;
4184 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4185 return -TARGET_EFAULT;
4186 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4187 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4188 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4189 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4190 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4191 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4192 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4193 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4194 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004195 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004196}
4197
4198static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004199{
4200 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004201 struct msginfo msginfo;
4202 abi_long ret = -TARGET_EINVAL;
4203
4204 cmd &= 0xff;
4205
4206 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004207 case IPC_STAT:
4208 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004209 case MSG_STAT:
4210 if (target_to_host_msqid_ds(&dsarg,ptr))
4211 return -TARGET_EFAULT;
4212 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4213 if (host_to_target_msqid_ds(ptr,&dsarg))
4214 return -TARGET_EFAULT;
4215 break;
4216 case IPC_RMID:
4217 ret = get_errno(msgctl(msgid, cmd, NULL));
4218 break;
4219 case IPC_INFO:
4220 case MSG_INFO:
4221 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4222 if (host_to_target_msginfo(ptr, &msginfo))
4223 return -TARGET_EFAULT;
4224 break;
ths1bc012f2007-06-03 14:27:49 +00004225 }
aurel321c54ff92008-10-13 21:08:44 +00004226
ths1bc012f2007-06-03 14:27:49 +00004227 return ret;
4228}
4229
4230struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004231 abi_long mtype;
4232 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004233};
4234
blueswir1992f48a2007-10-14 16:27:31 +00004235static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004236 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004237{
4238 struct target_msgbuf *target_mb;
4239 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004240 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004241
Tom Mustaedcc5f92014-08-12 13:53:37 -05004242 if (msgsz < 0) {
4243 return -TARGET_EINVAL;
4244 }
4245
bellard579a97f2007-11-11 14:26:47 +00004246 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4247 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304248 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004249 if (!host_mb) {
4250 unlock_user_struct(target_mb, msgp, 0);
4251 return -TARGET_ENOMEM;
4252 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004253 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004254 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Laurent Vivier524fa342019-05-29 10:48:04 +02004255 ret = -TARGET_ENOSYS;
4256#ifdef __NR_msgsnd
Peter Maydell89f9fe42016-06-06 19:58:05 +01004257 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02004258#endif
4259#ifdef __NR_ipc
4260 if (ret == -TARGET_ENOSYS) {
Matus Kyseld8c08b12020-06-26 14:46:11 +02004261#ifdef __s390x__
4262 ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
4263 host_mb));
4264#else
Laurent Vivier524fa342019-05-29 10:48:04 +02004265 ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
4266 host_mb, 0));
Matus Kyseld8c08b12020-06-26 14:46:11 +02004267#endif
Laurent Vivier524fa342019-05-29 10:48:04 +02004268 }
4269#endif
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304270 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004271 unlock_user_struct(target_mb, msgp, 0);
4272
4273 return ret;
4274}
4275
Matus Kyseld8c08b12020-06-26 14:46:11 +02004276#ifdef __NR_ipc
4277#if defined(__sparc__)
4278/* SPARC for msgrcv it does not use the kludge on final 2 arguments. */
4279#define MSGRCV_ARGS(__msgp, __msgtyp) __msgp, __msgtyp
4280#elif defined(__s390x__)
4281/* The s390 sys_ipc variant has only five parameters. */
4282#define MSGRCV_ARGS(__msgp, __msgtyp) \
4283 ((long int[]){(long int)__msgp, __msgtyp})
4284#else
4285#define MSGRCV_ARGS(__msgp, __msgtyp) \
4286 ((long int[]){(long int)__msgp, __msgtyp}), 0
4287#endif
4288#endif
4289
blueswir1992f48a2007-10-14 16:27:31 +00004290static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004291 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004292 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004293{
4294 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004295 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004296 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004297 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004298
Peter Maydell99874f62016-05-20 19:00:56 +01004299 if (msgsz < 0) {
4300 return -TARGET_EINVAL;
4301 }
4302
bellard579a97f2007-11-11 14:26:47 +00004303 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4304 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004305
Peter Maydell415d8472016-05-20 19:00:57 +01004306 host_mb = g_try_malloc(msgsz + sizeof(long));
4307 if (!host_mb) {
4308 ret = -TARGET_ENOMEM;
4309 goto end;
4310 }
Laurent Vivier524fa342019-05-29 10:48:04 +02004311 ret = -TARGET_ENOSYS;
4312#ifdef __NR_msgrcv
Peter Maydell89f9fe42016-06-06 19:58:05 +01004313 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
Laurent Vivier524fa342019-05-29 10:48:04 +02004314#endif
4315#ifdef __NR_ipc
4316 if (ret == -TARGET_ENOSYS) {
4317 ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz,
Matus Kyseld8c08b12020-06-26 14:46:11 +02004318 msgflg, MSGRCV_ARGS(host_mb, msgtyp)));
Laurent Vivier524fa342019-05-29 10:48:04 +02004319 }
4320#endif
aurel321c54ff92008-10-13 21:08:44 +00004321
bellard579a97f2007-11-11 14:26:47 +00004322 if (ret > 0) {
4323 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4324 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4325 if (!target_mtext) {
4326 ret = -TARGET_EFAULT;
4327 goto end;
4328 }
aurel321c54ff92008-10-13 21:08:44 +00004329 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004330 unlock_user(target_mtext, target_mtext_addr, ret);
4331 }
aurel321c54ff92008-10-13 21:08:44 +00004332
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004333 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004334
bellard579a97f2007-11-11 14:26:47 +00004335end:
4336 if (target_mb)
4337 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004338 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004339 return ret;
4340}
4341
Riku Voipio88a8c982009-04-03 10:42:00 +03004342static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4343 abi_ulong target_addr)
4344{
4345 struct target_shmid_ds *target_sd;
4346
4347 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4348 return -TARGET_EFAULT;
4349 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4350 return -TARGET_EFAULT;
4351 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4352 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4353 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4354 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4355 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4356 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4357 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4358 unlock_user_struct(target_sd, target_addr, 0);
4359 return 0;
4360}
4361
4362static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4363 struct shmid_ds *host_sd)
4364{
4365 struct target_shmid_ds *target_sd;
4366
4367 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4368 return -TARGET_EFAULT;
4369 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4370 return -TARGET_EFAULT;
4371 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4372 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4373 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4374 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4375 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4376 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4377 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4378 unlock_user_struct(target_sd, target_addr, 1);
4379 return 0;
4380}
4381
4382struct target_shminfo {
4383 abi_ulong shmmax;
4384 abi_ulong shmmin;
4385 abi_ulong shmmni;
4386 abi_ulong shmseg;
4387 abi_ulong shmall;
4388};
4389
4390static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4391 struct shminfo *host_shminfo)
4392{
4393 struct target_shminfo *target_shminfo;
4394 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4395 return -TARGET_EFAULT;
4396 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4397 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4398 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4399 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4400 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4401 unlock_user_struct(target_shminfo, target_addr, 1);
4402 return 0;
4403}
4404
4405struct target_shm_info {
4406 int used_ids;
4407 abi_ulong shm_tot;
4408 abi_ulong shm_rss;
4409 abi_ulong shm_swp;
4410 abi_ulong swap_attempts;
4411 abi_ulong swap_successes;
4412};
4413
4414static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4415 struct shm_info *host_shm_info)
4416{
4417 struct target_shm_info *target_shm_info;
4418 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4419 return -TARGET_EFAULT;
4420 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4421 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4422 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4423 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4424 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4425 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4426 unlock_user_struct(target_shm_info, target_addr, 1);
4427 return 0;
4428}
4429
4430static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4431{
4432 struct shmid_ds dsarg;
4433 struct shminfo shminfo;
4434 struct shm_info shm_info;
4435 abi_long ret = -TARGET_EINVAL;
4436
4437 cmd &= 0xff;
4438
4439 switch(cmd) {
4440 case IPC_STAT:
4441 case IPC_SET:
4442 case SHM_STAT:
4443 if (target_to_host_shmid_ds(&dsarg, buf))
4444 return -TARGET_EFAULT;
4445 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4446 if (host_to_target_shmid_ds(buf, &dsarg))
4447 return -TARGET_EFAULT;
4448 break;
4449 case IPC_INFO:
4450 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4451 if (host_to_target_shminfo(buf, &shminfo))
4452 return -TARGET_EFAULT;
4453 break;
4454 case SHM_INFO:
4455 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4456 if (host_to_target_shm_info(buf, &shm_info))
4457 return -TARGET_EFAULT;
4458 break;
4459 case IPC_RMID:
4460 case SHM_LOCK:
4461 case SHM_UNLOCK:
4462 ret = get_errno(shmctl(shmid, cmd, NULL));
4463 break;
4464 }
4465
4466 return ret;
4467}
4468
aurel321c54ff92008-10-13 21:08:44 +00004469#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004470/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004471/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004472static abi_long do_ipc(CPUArchState *cpu_env,
4473 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004474 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004475 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004476{
4477 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004478 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004479
4480 version = call >> 16;
4481 call &= 0xffff;
4482
4483 switch (call) {
thsfa294812007-02-02 22:05:00 +00004484 case IPCOP_semop:
Filip Bozutacac46eb2020-08-25 00:30:50 +02004485 ret = do_semtimedop(first, ptr, second, 0, false);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004486 break;
4487 case IPCOP_semtimedop:
4488 /*
4489 * The s390 sys_ipc variant has only five parameters instead of six
4490 * (as for default variant) and the only difference is the handling of
4491 * SEMTIMEDOP where on s390 the third parameter is used as a pointer
4492 * to a struct timespec where the generic variant uses fifth parameter.
4493 */
4494#if defined(TARGET_S390X)
Filip Bozutacac46eb2020-08-25 00:30:50 +02004495 ret = do_semtimedop(first, ptr, second, third, TARGET_ABI_BITS == 64);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004496#else
Filip Bozutacac46eb2020-08-25 00:30:50 +02004497 ret = do_semtimedop(first, ptr, second, fifth, TARGET_ABI_BITS == 64);
Matus Kyseld8c08b12020-06-26 14:46:11 +02004498#endif
thsfa294812007-02-02 22:05:00 +00004499 break;
4500
4501 case IPCOP_semget:
4502 ret = get_errno(semget(first, second, third));
4503 break;
4504
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004505 case IPCOP_semctl: {
4506 /* The semun argument to semctl is passed by value, so dereference the
4507 * ptr argument. */
4508 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004509 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004510 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004511 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004512 }
thsd96372e2007-02-02 22:05:44 +00004513
aurel321c54ff92008-10-13 21:08:44 +00004514 case IPCOP_msgget:
4515 ret = get_errno(msgget(first, second));
4516 break;
thsd96372e2007-02-02 22:05:44 +00004517
aurel321c54ff92008-10-13 21:08:44 +00004518 case IPCOP_msgsnd:
4519 ret = do_msgsnd(first, ptr, second, third);
4520 break;
thsd96372e2007-02-02 22:05:44 +00004521
aurel321c54ff92008-10-13 21:08:44 +00004522 case IPCOP_msgctl:
4523 ret = do_msgctl(first, second, ptr);
4524 break;
thsd96372e2007-02-02 22:05:44 +00004525
aurel321c54ff92008-10-13 21:08:44 +00004526 case IPCOP_msgrcv:
4527 switch (version) {
4528 case 0:
4529 {
4530 struct target_ipc_kludge {
4531 abi_long msgp;
4532 abi_long msgtyp;
4533 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004534
aurel321c54ff92008-10-13 21:08:44 +00004535 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4536 ret = -TARGET_EFAULT;
4537 break;
ths1bc012f2007-06-03 14:27:49 +00004538 }
aurel321c54ff92008-10-13 21:08:44 +00004539
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004540 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004541
4542 unlock_user_struct(tmp, ptr, 0);
4543 break;
4544 }
4545 default:
4546 ret = do_msgrcv(first, ptr, second, fifth, third);
4547 }
4548 break;
thsd96372e2007-02-02 22:05:44 +00004549
bellard8853f862004-02-22 14:57:26 +00004550 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004551 switch (version) {
4552 default:
bellard5a4a8982007-11-11 17:39:18 +00004553 {
4554 abi_ulong raddr;
Richard Henderson225a2062023-08-20 09:24:14 -07004555 raddr = target_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03004556 if (is_error(raddr))
4557 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004558 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004559 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004560 break;
4561 }
4562 case 1:
4563 ret = -TARGET_EINVAL;
4564 break;
bellard5a4a8982007-11-11 17:39:18 +00004565 }
bellard8853f862004-02-22 14:57:26 +00004566 break;
4567 case IPCOP_shmdt:
Richard Henderson225a2062023-08-20 09:24:14 -07004568 ret = target_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004569 break;
4570
4571 case IPCOP_shmget:
4572 /* IPC_* flag values are the same on all linux platforms */
4573 ret = get_errno(shmget(first, second, third));
4574 break;
4575
4576 /* IPC_* and SHM_* command values are the same on all linux platforms */
4577 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004578 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004579 break;
4580 default:
Josh Kunz39be5352020-02-03 18:54:13 -08004581 qemu_log_mask(LOG_UNIMP, "Unsupported ipc call: %d (version %d)\n",
4582 call, version);
ths0da46a62007-10-20 20:23:07 +00004583 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004584 break;
4585 }
4586 return ret;
4587}
j_mayer32407102007-09-26 23:01:49 +00004588#endif
bellard8853f862004-02-22 14:57:26 +00004589
bellard31e31b82003-02-18 22:55:36 +00004590/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004591
Blue Swirl001faf32009-05-13 17:53:17 +00004592#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004593#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4594enum {
4595#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004596STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004597};
4598#undef STRUCT
4599#undef STRUCT_SPECIAL
4600
Blue Swirl001faf32009-05-13 17:53:17 +00004601#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004602#define STRUCT_SPECIAL(name)
4603#include "syscall_types.h"
4604#undef STRUCT
4605#undef STRUCT_SPECIAL
4606
bellard31e31b82003-02-18 22:55:36 +00004607#define MAX_STRUCT_SIZE 4096
4608
Peter Maydelldace20d2011-01-10 13:11:24 +00004609#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004610/* So fiemap access checks don't overflow on 32 bit systems.
4611 * This is very slightly smaller than the limit imposed by
4612 * the underlying kernel.
4613 */
4614#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4615 / sizeof(struct fiemap_extent))
4616
4617static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004618 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004619{
4620 /* The parameter for this ioctl is a struct fiemap followed
4621 * by an array of struct fiemap_extent whose size is set
4622 * in fiemap->fm_extent_count. The array is filled in by the
4623 * ioctl.
4624 */
4625 int target_size_in, target_size_out;
4626 struct fiemap *fm;
4627 const argtype *arg_type = ie->arg_type;
4628 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4629 void *argptr, *p;
4630 abi_long ret;
4631 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4632 uint32_t outbufsz;
4633 int free_fm = 0;
4634
4635 assert(arg_type[0] == TYPE_PTR);
4636 assert(ie->access == IOC_RW);
4637 arg_type++;
4638 target_size_in = thunk_type_size(arg_type, 0);
4639 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4640 if (!argptr) {
4641 return -TARGET_EFAULT;
4642 }
4643 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4644 unlock_user(argptr, arg, 0);
4645 fm = (struct fiemap *)buf_temp;
4646 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4647 return -TARGET_EINVAL;
4648 }
4649
4650 outbufsz = sizeof (*fm) +
4651 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4652
4653 if (outbufsz > MAX_STRUCT_SIZE) {
4654 /* We can't fit all the extents into the fixed size buffer.
4655 * Allocate one that is large enough and use it instead.
4656 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304657 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004658 if (!fm) {
4659 return -TARGET_ENOMEM;
4660 }
4661 memcpy(fm, buf_temp, sizeof(struct fiemap));
4662 free_fm = 1;
4663 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004664 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004665 if (!is_error(ret)) {
4666 target_size_out = target_size_in;
4667 /* An extent_count of 0 means we were only counting the extents
4668 * so there are no structs to copy
4669 */
4670 if (fm->fm_extent_count != 0) {
4671 target_size_out += fm->fm_mapped_extents * extent_size;
4672 }
4673 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4674 if (!argptr) {
4675 ret = -TARGET_EFAULT;
4676 } else {
4677 /* Convert the struct fiemap */
4678 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4679 if (fm->fm_extent_count != 0) {
4680 p = argptr + target_size_in;
4681 /* ...and then all the struct fiemap_extents */
4682 for (i = 0; i < fm->fm_mapped_extents; i++) {
4683 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4684 THUNK_TARGET);
4685 p += extent_size;
4686 }
4687 }
4688 unlock_user(argptr, arg, target_size_out);
4689 }
4690 }
4691 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304692 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004693 }
4694 return ret;
4695}
Peter Maydelldace20d2011-01-10 13:11:24 +00004696#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004697
Laurent Vivier059c2f22011-03-30 00:12:12 +02004698static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004699 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004700{
4701 const argtype *arg_type = ie->arg_type;
4702 int target_size;
4703 void *argptr;
4704 int ret;
4705 struct ifconf *host_ifconf;
4706 uint32_t outbufsz;
4707 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
Stefan4df7b7f2021-01-09 19:59:42 +01004708 const argtype ifreq_max_type[] = { MK_STRUCT(STRUCT_ifmap_ifreq) };
Laurent Vivier059c2f22011-03-30 00:12:12 +02004709 int target_ifreq_size;
4710 int nb_ifreq;
4711 int free_buf = 0;
4712 int i;
4713 int target_ifc_len;
4714 abi_long target_ifc_buf;
4715 int host_ifc_len;
4716 char *host_ifc_buf;
4717
4718 assert(arg_type[0] == TYPE_PTR);
4719 assert(ie->access == IOC_RW);
4720
4721 arg_type++;
4722 target_size = thunk_type_size(arg_type, 0);
4723
4724 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4725 if (!argptr)
4726 return -TARGET_EFAULT;
4727 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4728 unlock_user(argptr, arg, 0);
4729
4730 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004731 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
Stefan4df7b7f2021-01-09 19:59:42 +01004732 target_ifreq_size = thunk_type_size(ifreq_max_type, 0);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004733
Kan Li22e4a2672018-10-24 20:13:03 +00004734 if (target_ifc_buf != 0) {
4735 target_ifc_len = host_ifconf->ifc_len;
4736 nb_ifreq = target_ifc_len / target_ifreq_size;
4737 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4738
4739 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4740 if (outbufsz > MAX_STRUCT_SIZE) {
4741 /*
4742 * We can't fit all the extents into the fixed size buffer.
4743 * Allocate one that is large enough and use it instead.
4744 */
Ahmed Abouzied7a5626a2022-01-04 16:38:41 +02004745 host_ifconf = g_try_malloc(outbufsz);
Kan Li22e4a2672018-10-24 20:13:03 +00004746 if (!host_ifconf) {
4747 return -TARGET_ENOMEM;
4748 }
4749 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4750 free_buf = 1;
Laurent Vivier059c2f22011-03-30 00:12:12 +02004751 }
Kan Li22e4a2672018-10-24 20:13:03 +00004752 host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004753
Kan Li22e4a2672018-10-24 20:13:03 +00004754 host_ifconf->ifc_len = host_ifc_len;
4755 } else {
4756 host_ifc_buf = NULL;
4757 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004758 host_ifconf->ifc_buf = host_ifc_buf;
4759
Peter Maydell49ca6f32016-06-06 19:58:14 +01004760 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02004761 if (!is_error(ret)) {
4762 /* convert host ifc_len to target ifc_len */
4763
4764 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4765 target_ifc_len = nb_ifreq * target_ifreq_size;
4766 host_ifconf->ifc_len = target_ifc_len;
4767
4768 /* restore target ifc_buf */
4769
4770 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4771
4772 /* copy struct ifconf to target user */
4773
4774 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4775 if (!argptr)
4776 return -TARGET_EFAULT;
4777 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4778 unlock_user(argptr, arg, target_size);
4779
Kan Li22e4a2672018-10-24 20:13:03 +00004780 if (target_ifc_buf != 0) {
4781 /* copy ifreq[] to target user */
4782 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4783 for (i = 0; i < nb_ifreq ; i++) {
4784 thunk_convert(argptr + i * target_ifreq_size,
4785 host_ifc_buf + i * sizeof(struct ifreq),
4786 ifreq_arg_type, THUNK_TARGET);
4787 }
4788 unlock_user(argptr, target_ifc_buf, target_ifc_len);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004789 }
Laurent Vivier059c2f22011-03-30 00:12:12 +02004790 }
4791
4792 if (free_buf) {
Ahmed Abouzied7a5626a2022-01-04 16:38:41 +02004793 g_free(host_ifconf);
Laurent Vivier059c2f22011-03-30 00:12:12 +02004794 }
4795
4796 return ret;
4797}
4798
Cortland Tölvaa1333672018-10-08 09:35:21 -07004799#if defined(CONFIG_USBFS)
4800#if HOST_LONG_BITS > 64
4801#error USBDEVFS thunks do not support >64 bit hosts yet.
4802#endif
4803struct live_urb {
4804 uint64_t target_urb_adr;
4805 uint64_t target_buf_adr;
4806 char *target_buf_ptr;
4807 struct usbdevfs_urb host_urb;
4808};
4809
4810static GHashTable *usbdevfs_urb_hashtable(void)
4811{
4812 static GHashTable *urb_hashtable;
4813
4814 if (!urb_hashtable) {
4815 urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
4816 }
4817 return urb_hashtable;
4818}
4819
4820static void urb_hashtable_insert(struct live_urb *urb)
4821{
4822 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4823 g_hash_table_insert(urb_hashtable, urb, urb);
4824}
4825
4826static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
4827{
4828 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4829 return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
4830}
4831
4832static void urb_hashtable_remove(struct live_urb *urb)
4833{
4834 GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
4835 g_hash_table_remove(urb_hashtable, urb);
4836}
4837
4838static abi_long
4839do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
4840 int fd, int cmd, abi_long arg)
4841{
4842 const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
4843 const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
4844 struct live_urb *lurb;
4845 void *argptr;
4846 uint64_t hurb;
4847 int target_size;
4848 uintptr_t target_urb_adr;
4849 abi_long ret;
4850
4851 target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
4852
4853 memset(buf_temp, 0, sizeof(uint64_t));
4854 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
4855 if (is_error(ret)) {
4856 return ret;
4857 }
4858
4859 memcpy(&hurb, buf_temp, sizeof(uint64_t));
4860 lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
4861 if (!lurb->target_urb_adr) {
4862 return -TARGET_EFAULT;
4863 }
4864 urb_hashtable_remove(lurb);
4865 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
4866 lurb->host_urb.buffer_length);
4867 lurb->target_buf_ptr = NULL;
4868
4869 /* restore the guest buffer pointer */
4870 lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
4871
4872 /* update the guest urb struct */
4873 argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
4874 if (!argptr) {
4875 g_free(lurb);
4876 return -TARGET_EFAULT;
4877 }
4878 thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
4879 unlock_user(argptr, lurb->target_urb_adr, target_size);
4880
4881 target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
4882 /* write back the urb handle */
4883 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4884 if (!argptr) {
4885 g_free(lurb);
4886 return -TARGET_EFAULT;
4887 }
4888
4889 /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
4890 target_urb_adr = lurb->target_urb_adr;
4891 thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
4892 unlock_user(argptr, arg, target_size);
4893
4894 g_free(lurb);
4895 return ret;
4896}
4897
4898static abi_long
4899do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
4900 uint8_t *buf_temp __attribute__((unused)),
4901 int fd, int cmd, abi_long arg)
4902{
4903 struct live_urb *lurb;
4904
4905 /* map target address back to host URB with metadata. */
4906 lurb = urb_hashtable_lookup(arg);
4907 if (!lurb) {
4908 return -TARGET_EFAULT;
4909 }
4910 return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
4911}
4912
4913static abi_long
4914do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
4915 int fd, int cmd, abi_long arg)
4916{
4917 const argtype *arg_type = ie->arg_type;
4918 int target_size;
4919 abi_long ret;
4920 void *argptr;
4921 int rw_dir;
4922 struct live_urb *lurb;
4923
4924 /*
4925 * each submitted URB needs to map to a unique ID for the
4926 * kernel, and that unique ID needs to be a pointer to
4927 * host memory. hence, we need to malloc for each URB.
4928 * isochronous transfers have a variable length struct.
4929 */
4930 arg_type++;
4931 target_size = thunk_type_size(arg_type, THUNK_TARGET);
4932
4933 /* construct host copy of urb and metadata */
Markus Armbrusterb21e2382022-03-15 15:41:56 +01004934 lurb = g_try_new0(struct live_urb, 1);
Cortland Tölvaa1333672018-10-08 09:35:21 -07004935 if (!lurb) {
4936 return -TARGET_ENOMEM;
4937 }
4938
4939 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4940 if (!argptr) {
4941 g_free(lurb);
4942 return -TARGET_EFAULT;
4943 }
4944 thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
4945 unlock_user(argptr, arg, 0);
4946
4947 lurb->target_urb_adr = arg;
4948 lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
4949
4950 /* buffer space used depends on endpoint type so lock the entire buffer */
4951 /* control type urbs should check the buffer contents for true direction */
4952 rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
4953 lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
4954 lurb->host_urb.buffer_length, 1);
4955 if (lurb->target_buf_ptr == NULL) {
4956 g_free(lurb);
4957 return -TARGET_EFAULT;
4958 }
4959
4960 /* update buffer pointer in host copy */
4961 lurb->host_urb.buffer = lurb->target_buf_ptr;
4962
4963 ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
4964 if (is_error(ret)) {
4965 unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
4966 g_free(lurb);
4967 } else {
4968 urb_hashtable_insert(lurb);
4969 }
4970
4971 return ret;
4972}
4973#endif /* CONFIG_USBFS */
4974
Alexander Graf56e904e2012-01-31 18:42:06 +01004975static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004976 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004977{
4978 void *argptr;
4979 struct dm_ioctl *host_dm;
4980 abi_long guest_data;
4981 uint32_t guest_data_size;
4982 int target_size;
4983 const argtype *arg_type = ie->arg_type;
4984 abi_long ret;
4985 void *big_buf = NULL;
4986 char *host_data;
4987
4988 arg_type++;
4989 target_size = thunk_type_size(arg_type, 0);
4990 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4991 if (!argptr) {
4992 ret = -TARGET_EFAULT;
4993 goto out;
4994 }
4995 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4996 unlock_user(argptr, arg, 0);
4997
4998 /* buf_temp is too small, so fetch things into a bigger buffer */
4999 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5000 memcpy(big_buf, buf_temp, target_size);
5001 buf_temp = big_buf;
5002 host_dm = big_buf;
5003
5004 guest_data = arg + host_dm->data_start;
5005 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005006 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005007 goto out;
5008 }
5009 guest_data_size = host_dm->data_size - host_dm->data_start;
5010 host_data = (char*)host_dm + host_dm->data_start;
5011
5012 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005013 if (!argptr) {
5014 ret = -TARGET_EFAULT;
5015 goto out;
5016 }
5017
Alexander Graf56e904e2012-01-31 18:42:06 +01005018 switch (ie->host_cmd) {
5019 case DM_REMOVE_ALL:
5020 case DM_LIST_DEVICES:
5021 case DM_DEV_CREATE:
5022 case DM_DEV_REMOVE:
5023 case DM_DEV_SUSPEND:
5024 case DM_DEV_STATUS:
5025 case DM_DEV_WAIT:
5026 case DM_TABLE_STATUS:
5027 case DM_TABLE_CLEAR:
5028 case DM_TABLE_DEPS:
5029 case DM_LIST_VERSIONS:
5030 /* no input data */
5031 break;
5032 case DM_DEV_RENAME:
5033 case DM_DEV_SET_GEOMETRY:
5034 /* data contains only strings */
5035 memcpy(host_data, argptr, guest_data_size);
5036 break;
5037 case DM_TARGET_MSG:
5038 memcpy(host_data, argptr, guest_data_size);
5039 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5040 break;
5041 case DM_TABLE_LOAD:
5042 {
5043 void *gspec = argptr;
5044 void *cur_data = host_data;
Laurent Viviereb2929c2023-09-25 17:10:27 +02005045 const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5046 int spec_size = thunk_type_size(dm_arg_type, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005047 int i;
5048
5049 for (i = 0; i < host_dm->target_count; i++) {
5050 struct dm_target_spec *spec = cur_data;
5051 uint32_t next;
5052 int slen;
5053
Laurent Viviereb2929c2023-09-25 17:10:27 +02005054 thunk_convert(spec, gspec, dm_arg_type, THUNK_HOST);
Alexander Graf56e904e2012-01-31 18:42:06 +01005055 slen = strlen((char*)gspec + spec_size) + 1;
5056 next = spec->next;
5057 spec->next = sizeof(*spec) + slen;
5058 strcpy((char*)&spec[1], gspec + spec_size);
5059 gspec += next;
5060 cur_data += spec->next;
5061 }
5062 break;
5063 }
5064 default:
5065 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005066 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005067 goto out;
5068 }
5069 unlock_user(argptr, guest_data, 0);
5070
Peter Maydell49ca6f32016-06-06 19:58:14 +01005071 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005072 if (!is_error(ret)) {
5073 guest_data = arg + host_dm->data_start;
5074 guest_data_size = host_dm->data_size - host_dm->data_start;
5075 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5076 switch (ie->host_cmd) {
5077 case DM_REMOVE_ALL:
5078 case DM_DEV_CREATE:
5079 case DM_DEV_REMOVE:
5080 case DM_DEV_RENAME:
5081 case DM_DEV_SUSPEND:
5082 case DM_DEV_STATUS:
5083 case DM_TABLE_LOAD:
5084 case DM_TABLE_CLEAR:
5085 case DM_TARGET_MSG:
5086 case DM_DEV_SET_GEOMETRY:
5087 /* no return data */
5088 break;
5089 case DM_LIST_DEVICES:
5090 {
5091 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5092 uint32_t remaining_data = guest_data_size;
5093 void *cur_data = argptr;
Laurent Viviereb2929c2023-09-25 17:10:27 +02005094 const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
Alexander Graf56e904e2012-01-31 18:42:06 +01005095 int nl_size = 12; /* can't use thunk_size due to alignment */
5096
5097 while (1) {
5098 uint32_t next = nl->next;
5099 if (next) {
5100 nl->next = nl_size + (strlen(nl->name) + 1);
5101 }
5102 if (remaining_data < nl->next) {
5103 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5104 break;
5105 }
Laurent Viviereb2929c2023-09-25 17:10:27 +02005106 thunk_convert(cur_data, nl, dm_arg_type, THUNK_TARGET);
Alexander Graf56e904e2012-01-31 18:42:06 +01005107 strcpy(cur_data + nl_size, nl->name);
5108 cur_data += nl->next;
5109 remaining_data -= nl->next;
5110 if (!next) {
5111 break;
5112 }
5113 nl = (void*)nl + next;
5114 }
5115 break;
5116 }
5117 case DM_DEV_WAIT:
5118 case DM_TABLE_STATUS:
5119 {
5120 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5121 void *cur_data = argptr;
Laurent Viviereb2929c2023-09-25 17:10:27 +02005122 const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5123 int spec_size = thunk_type_size(dm_arg_type, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005124 int i;
5125
5126 for (i = 0; i < host_dm->target_count; i++) {
5127 uint32_t next = spec->next;
5128 int slen = strlen((char*)&spec[1]) + 1;
5129 spec->next = (cur_data - argptr) + spec_size + slen;
5130 if (guest_data_size < spec->next) {
5131 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5132 break;
5133 }
Laurent Viviereb2929c2023-09-25 17:10:27 +02005134 thunk_convert(cur_data, spec, dm_arg_type, THUNK_TARGET);
Alexander Graf56e904e2012-01-31 18:42:06 +01005135 strcpy(cur_data + spec_size, (char*)&spec[1]);
5136 cur_data = argptr + spec->next;
5137 spec = (void*)host_dm + host_dm->data_start + next;
5138 }
5139 break;
5140 }
5141 case DM_TABLE_DEPS:
5142 {
5143 void *hdata = (void*)host_dm + host_dm->data_start;
5144 int count = *(uint32_t*)hdata;
5145 uint64_t *hdev = hdata + 8;
5146 uint64_t *gdev = argptr + 8;
5147 int i;
5148
5149 *(uint32_t*)argptr = tswap32(count);
5150 for (i = 0; i < count; i++) {
5151 *gdev = tswap64(*hdev);
5152 gdev++;
5153 hdev++;
5154 }
5155 break;
5156 }
5157 case DM_LIST_VERSIONS:
5158 {
5159 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5160 uint32_t remaining_data = guest_data_size;
5161 void *cur_data = argptr;
Laurent Viviereb2929c2023-09-25 17:10:27 +02005162 const argtype dm_arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5163 int vers_size = thunk_type_size(dm_arg_type, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005164
5165 while (1) {
5166 uint32_t next = vers->next;
5167 if (next) {
5168 vers->next = vers_size + (strlen(vers->name) + 1);
5169 }
5170 if (remaining_data < vers->next) {
5171 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5172 break;
5173 }
Laurent Viviereb2929c2023-09-25 17:10:27 +02005174 thunk_convert(cur_data, vers, dm_arg_type, THUNK_TARGET);
Alexander Graf56e904e2012-01-31 18:42:06 +01005175 strcpy(cur_data + vers_size, vers->name);
5176 cur_data += vers->next;
5177 remaining_data -= vers->next;
5178 if (!next) {
5179 break;
5180 }
5181 vers = (void*)vers + next;
5182 }
5183 break;
5184 }
5185 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005186 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005187 ret = -TARGET_EINVAL;
5188 goto out;
5189 }
5190 unlock_user(argptr, guest_data, guest_data_size);
5191
5192 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5193 if (!argptr) {
5194 ret = -TARGET_EFAULT;
5195 goto out;
5196 }
5197 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5198 unlock_user(argptr, arg, target_size);
5199 }
5200out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005201 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005202 return ret;
5203}
5204
Alexander Grafa59b5e32014-08-22 13:15:50 +02005205static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005206 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005207{
5208 void *argptr;
5209 int target_size;
5210 const argtype *arg_type = ie->arg_type;
5211 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5212 abi_long ret;
5213
5214 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5215 struct blkpg_partition host_part;
5216
5217 /* Read and convert blkpg */
5218 arg_type++;
5219 target_size = thunk_type_size(arg_type, 0);
5220 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5221 if (!argptr) {
5222 ret = -TARGET_EFAULT;
5223 goto out;
5224 }
5225 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5226 unlock_user(argptr, arg, 0);
5227
5228 switch (host_blkpg->op) {
5229 case BLKPG_ADD_PARTITION:
5230 case BLKPG_DEL_PARTITION:
5231 /* payload is struct blkpg_partition */
5232 break;
5233 default:
5234 /* Unknown opcode */
5235 ret = -TARGET_EINVAL;
5236 goto out;
5237 }
5238
5239 /* Read and convert blkpg->data */
5240 arg = (abi_long)(uintptr_t)host_blkpg->data;
5241 target_size = thunk_type_size(part_arg_type, 0);
5242 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5243 if (!argptr) {
5244 ret = -TARGET_EFAULT;
5245 goto out;
5246 }
5247 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5248 unlock_user(argptr, arg, 0);
5249
5250 /* Swizzle the data pointer to our local copy and call! */
5251 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005252 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005253
5254out:
5255 return ret;
5256}
5257
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005258static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005259 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005260{
5261 const argtype *arg_type = ie->arg_type;
5262 const StructEntry *se;
5263 const argtype *field_types;
5264 const int *dst_offsets, *src_offsets;
5265 int target_size;
5266 void *argptr;
Marc-André Lureaub78c5222019-03-05 16:15:00 +01005267 abi_ulong *target_rt_dev_ptr = NULL;
5268 unsigned long *host_rt_dev_ptr = NULL;
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005269 abi_long ret;
5270 int i;
5271
5272 assert(ie->access == IOC_W);
5273 assert(*arg_type == TYPE_PTR);
5274 arg_type++;
5275 assert(*arg_type == TYPE_STRUCT);
5276 target_size = thunk_type_size(arg_type, 0);
5277 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5278 if (!argptr) {
5279 return -TARGET_EFAULT;
5280 }
5281 arg_type++;
5282 assert(*arg_type == (int)STRUCT_rtentry);
5283 se = struct_entries + *arg_type++;
5284 assert(se->convert[0] == NULL);
5285 /* convert struct here to be able to catch rt_dev string */
5286 field_types = se->field_types;
5287 dst_offsets = se->field_offsets[THUNK_HOST];
5288 src_offsets = se->field_offsets[THUNK_TARGET];
5289 for (i = 0; i < se->nb_fields; i++) {
5290 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5291 assert(*field_types == TYPE_PTRVOID);
Markus Armbruster3d558332022-11-23 14:38:11 +01005292 target_rt_dev_ptr = argptr + src_offsets[i];
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005293 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5294 if (*target_rt_dev_ptr != 0) {
5295 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5296 tswapal(*target_rt_dev_ptr));
5297 if (!*host_rt_dev_ptr) {
5298 unlock_user(argptr, arg, 0);
5299 return -TARGET_EFAULT;
5300 }
5301 } else {
5302 *host_rt_dev_ptr = 0;
5303 }
5304 field_types++;
5305 continue;
5306 }
5307 field_types = thunk_convert(buf_temp + dst_offsets[i],
5308 argptr + src_offsets[i],
5309 field_types, THUNK_HOST);
5310 }
5311 unlock_user(argptr, arg, 0);
5312
Peter Maydell49ca6f32016-06-06 19:58:14 +01005313 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Marc-André Lureaub78c5222019-03-05 16:15:00 +01005314
5315 assert(host_rt_dev_ptr != NULL);
5316 assert(target_rt_dev_ptr != NULL);
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005317 if (*host_rt_dev_ptr != 0) {
5318 unlock_user((void *)*host_rt_dev_ptr,
5319 *target_rt_dev_ptr, 0);
5320 }
5321 return ret;
5322}
5323
Paul Burtonca56f5b2014-06-22 11:25:47 +01005324static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005325 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005326{
5327 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005328 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005329}
5330
Daniel P. Berrangé6d5d5dd2019-07-18 15:06:41 +02005331static abi_long do_ioctl_SIOCGSTAMP(const IOCTLEntry *ie, uint8_t *buf_temp,
5332 int fd, int cmd, abi_long arg)
5333{
5334 struct timeval tv;
5335 abi_long ret;
5336
5337 ret = get_errno(safe_ioctl(fd, SIOCGSTAMP, &tv));
5338 if (is_error(ret)) {
5339 return ret;
5340 }
5341
5342 if (cmd == (int)TARGET_SIOCGSTAMP_OLD) {
5343 if (copy_to_user_timeval(arg, &tv)) {
5344 return -TARGET_EFAULT;
5345 }
5346 } else {
5347 if (copy_to_user_timeval64(arg, &tv)) {
5348 return -TARGET_EFAULT;
5349 }
5350 }
5351
5352 return ret;
5353}
5354
5355static abi_long do_ioctl_SIOCGSTAMPNS(const IOCTLEntry *ie, uint8_t *buf_temp,
5356 int fd, int cmd, abi_long arg)
5357{
5358 struct timespec ts;
5359 abi_long ret;
5360
5361 ret = get_errno(safe_ioctl(fd, SIOCGSTAMPNS, &ts));
5362 if (is_error(ret)) {
5363 return ret;
5364 }
5365
5366 if (cmd == (int)TARGET_SIOCGSTAMPNS_OLD) {
5367 if (host_to_target_timespec(arg, &ts)) {
5368 return -TARGET_EFAULT;
5369 }
5370 } else{
5371 if (host_to_target_timespec64(arg, &ts)) {
5372 return -TARGET_EFAULT;
5373 }
5374 }
5375
5376 return ret;
5377}
5378
Andreas Schwab2b74f622018-01-29 11:47:06 +01005379#ifdef TIOCGPTPEER
5380static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5381 int fd, int cmd, abi_long arg)
5382{
5383 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5384 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5385}
5386#endif
5387
Chen Gange865b972020-06-05 09:32:21 +08005388#ifdef HAVE_DRM_H
5389
5390static void unlock_drm_version(struct drm_version *host_ver,
5391 struct target_drm_version *target_ver,
5392 bool copy)
5393{
5394 unlock_user(host_ver->name, target_ver->name,
5395 copy ? host_ver->name_len : 0);
5396 unlock_user(host_ver->date, target_ver->date,
5397 copy ? host_ver->date_len : 0);
5398 unlock_user(host_ver->desc, target_ver->desc,
5399 copy ? host_ver->desc_len : 0);
5400}
5401
5402static inline abi_long target_to_host_drmversion(struct drm_version *host_ver,
5403 struct target_drm_version *target_ver)
5404{
5405 memset(host_ver, 0, sizeof(*host_ver));
5406
5407 __get_user(host_ver->name_len, &target_ver->name_len);
5408 if (host_ver->name_len) {
5409 host_ver->name = lock_user(VERIFY_WRITE, target_ver->name,
5410 target_ver->name_len, 0);
5411 if (!host_ver->name) {
5412 return -EFAULT;
5413 }
5414 }
5415
5416 __get_user(host_ver->date_len, &target_ver->date_len);
5417 if (host_ver->date_len) {
5418 host_ver->date = lock_user(VERIFY_WRITE, target_ver->date,
5419 target_ver->date_len, 0);
5420 if (!host_ver->date) {
5421 goto err;
5422 }
5423 }
5424
5425 __get_user(host_ver->desc_len, &target_ver->desc_len);
5426 if (host_ver->desc_len) {
5427 host_ver->desc = lock_user(VERIFY_WRITE, target_ver->desc,
5428 target_ver->desc_len, 0);
5429 if (!host_ver->desc) {
5430 goto err;
5431 }
5432 }
5433
5434 return 0;
5435err:
5436 unlock_drm_version(host_ver, target_ver, false);
5437 return -EFAULT;
5438}
5439
5440static inline void host_to_target_drmversion(
5441 struct target_drm_version *target_ver,
5442 struct drm_version *host_ver)
5443{
5444 __put_user(host_ver->version_major, &target_ver->version_major);
5445 __put_user(host_ver->version_minor, &target_ver->version_minor);
5446 __put_user(host_ver->version_patchlevel, &target_ver->version_patchlevel);
5447 __put_user(host_ver->name_len, &target_ver->name_len);
5448 __put_user(host_ver->date_len, &target_ver->date_len);
5449 __put_user(host_ver->desc_len, &target_ver->desc_len);
5450 unlock_drm_version(host_ver, target_ver, true);
5451}
5452
5453static abi_long do_ioctl_drm(const IOCTLEntry *ie, uint8_t *buf_temp,
5454 int fd, int cmd, abi_long arg)
5455{
5456 struct drm_version *ver;
5457 struct target_drm_version *target_ver;
5458 abi_long ret;
5459
5460 switch (ie->host_cmd) {
5461 case DRM_IOCTL_VERSION:
5462 if (!lock_user_struct(VERIFY_WRITE, target_ver, arg, 0)) {
5463 return -TARGET_EFAULT;
5464 }
5465 ver = (struct drm_version *)buf_temp;
5466 ret = target_to_host_drmversion(ver, target_ver);
5467 if (!is_error(ret)) {
5468 ret = get_errno(safe_ioctl(fd, ie->host_cmd, ver));
5469 if (is_error(ret)) {
5470 unlock_drm_version(ver, target_ver, false);
5471 } else {
5472 host_to_target_drmversion(target_ver, ver);
5473 }
5474 }
5475 unlock_user_struct(target_ver, arg, 0);
5476 return ret;
5477 }
5478 return -TARGET_ENOSYS;
5479}
5480
Chen Gang913b03c2020-08-02 21:39:38 +08005481static abi_long do_ioctl_drm_i915_getparam(const IOCTLEntry *ie,
5482 struct drm_i915_getparam *gparam,
5483 int fd, abi_long arg)
5484{
5485 abi_long ret;
5486 int value;
5487 struct target_drm_i915_getparam *target_gparam;
5488
5489 if (!lock_user_struct(VERIFY_READ, target_gparam, arg, 0)) {
5490 return -TARGET_EFAULT;
5491 }
5492
5493 __get_user(gparam->param, &target_gparam->param);
5494 gparam->value = &value;
5495 ret = get_errno(safe_ioctl(fd, ie->host_cmd, gparam));
5496 put_user_s32(value, target_gparam->value);
5497
5498 unlock_user_struct(target_gparam, arg, 0);
5499 return ret;
5500}
5501
5502static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp,
5503 int fd, int cmd, abi_long arg)
5504{
5505 switch (ie->host_cmd) {
5506 case DRM_IOCTL_I915_GETPARAM:
5507 return do_ioctl_drm_i915_getparam(ie,
5508 (struct drm_i915_getparam *)buf_temp,
5509 fd, arg);
5510 default:
5511 return -TARGET_ENOSYS;
5512 }
5513}
5514
Chen Gange865b972020-06-05 09:32:21 +08005515#endif
5516
Shu-Chun Weng6addf062020-09-28 18:48:01 -07005517static abi_long do_ioctl_TUNSETTXFILTER(const IOCTLEntry *ie, uint8_t *buf_temp,
5518 int fd, int cmd, abi_long arg)
5519{
5520 struct tun_filter *filter = (struct tun_filter *)buf_temp;
5521 struct tun_filter *target_filter;
5522 char *target_addr;
5523
5524 assert(ie->access == IOC_W);
5525
5526 target_filter = lock_user(VERIFY_READ, arg, sizeof(*target_filter), 1);
5527 if (!target_filter) {
5528 return -TARGET_EFAULT;
5529 }
5530 filter->flags = tswap16(target_filter->flags);
5531 filter->count = tswap16(target_filter->count);
5532 unlock_user(target_filter, arg, 0);
5533
5534 if (filter->count) {
5535 if (offsetof(struct tun_filter, addr) + filter->count * ETH_ALEN >
5536 MAX_STRUCT_SIZE) {
5537 return -TARGET_EFAULT;
5538 }
5539
5540 target_addr = lock_user(VERIFY_READ,
5541 arg + offsetof(struct tun_filter, addr),
5542 filter->count * ETH_ALEN, 1);
5543 if (!target_addr) {
5544 return -TARGET_EFAULT;
5545 }
5546 memcpy(filter->addr, target_addr, filter->count * ETH_ALEN);
5547 unlock_user(target_addr, arg + offsetof(struct tun_filter, addr), 0);
5548 }
5549
5550 return get_errno(safe_ioctl(fd, ie->host_cmd, filter));
5551}
5552
Filip Bozuta79482e592020-06-19 14:47:27 +02005553IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005554#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005555 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5556#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5557 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005558#define IOCTL_IGNORE(cmd) \
5559 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005560#include "ioctls.h"
5561 { 0, 0, },
5562};
5563
pbrook53a59602006-03-25 19:31:22 +00005564/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005565/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005566static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005567{
5568 const IOCTLEntry *ie;
5569 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005570 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005571 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005572 int target_size;
5573 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005574
5575 ie = ioctl_entries;
5576 for(;;) {
5577 if (ie->target_cmd == 0) {
Josh Kunz39be5352020-02-03 18:54:13 -08005578 qemu_log_mask(
5579 LOG_UNIMP, "Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
Thomas Weißschuh59d11722023-04-26 09:06:59 +02005580 return -TARGET_ENOTTY;
bellard31e31b82003-02-18 22:55:36 +00005581 }
5582 if (ie->target_cmd == cmd)
5583 break;
5584 ie++;
5585 }
5586 arg_type = ie->arg_type;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005587 if (ie->do_ioctl) {
5588 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005589 } else if (!ie->host_cmd) {
5590 /* Some architectures define BSD ioctls in their headers
5591 that are not implemented in Linux. */
Thomas Weißschuh59d11722023-04-26 09:06:59 +02005592 return -TARGET_ENOTTY;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005593 }
5594
bellard31e31b82003-02-18 22:55:36 +00005595 switch(arg_type[0]) {
5596 case TYPE_NULL:
5597 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005598 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005599 break;
5600 case TYPE_PTRVOID:
5601 case TYPE_INT:
Filip Bozutac858e532020-01-15 20:36:47 +01005602 case TYPE_LONG:
5603 case TYPE_ULONG:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005604 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005605 break;
5606 case TYPE_PTR:
5607 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005608 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005609 switch(ie->access) {
5610 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005611 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005612 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005613 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5614 if (!argptr)
5615 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005616 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5617 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005618 }
5619 break;
5620 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005621 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5622 if (!argptr)
5623 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005624 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5625 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005626 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005627 break;
5628 default:
5629 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005630 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5631 if (!argptr)
5632 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005633 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5634 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005635 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005636 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005637 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5638 if (!argptr)
5639 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005640 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5641 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005642 }
5643 break;
5644 }
5645 break;
5646 default:
Josh Kunz39be5352020-02-03 18:54:13 -08005647 qemu_log_mask(LOG_UNIMP,
5648 "Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5649 (long)cmd, arg_type[0]);
Thomas Weißschuh59d11722023-04-26 09:06:59 +02005650 ret = -TARGET_ENOTTY;
bellard31e31b82003-02-18 22:55:36 +00005651 break;
5652 }
5653 return ret;
5654}
5655
blueswir1b39bc502008-10-05 10:51:10 +00005656static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005657 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5658 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5659 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5660 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5661 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5662 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5663 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5664 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5665 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5666 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5667 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5668 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5669 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5670 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
Filip Bozutac218b4e2020-07-23 23:02:32 +02005671 { TARGET_IUTF8, TARGET_IUTF8, IUTF8, IUTF8},
bellard31e31b82003-02-18 22:55:36 +00005672};
5673
blueswir1b39bc502008-10-05 10:51:10 +00005674static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005675 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5676 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5677 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5678 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5679 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5680 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5681 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5682 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5683 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5684 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5685 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5686 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5687 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5688 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5689 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5690 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5691 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5692 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5693 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5694 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5695 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5696 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5697 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5698 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
bellard31e31b82003-02-18 22:55:36 +00005699};
5700
blueswir1b39bc502008-10-05 10:51:10 +00005701static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005702 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5703 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5704 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5705 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5706 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5707 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5708 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5709 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5710 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5711 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5712 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5713 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5714 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5715 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5716 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5717 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5718 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5719 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5720 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5721 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5722 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5723 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5724 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5725 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5726 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5727 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5728 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5729 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5730 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5731 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5732 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
bellard31e31b82003-02-18 22:55:36 +00005733};
5734
blueswir1b39bc502008-10-05 10:51:10 +00005735static const bitmask_transtbl lflag_tbl[] = {
Filip Bozutac218b4e2020-07-23 23:02:32 +02005736 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5737 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5738 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5739 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5740 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5741 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5742 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5743 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5744 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5745 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5746 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5747 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5748 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5749 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5750 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5751 { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC},
bellard31e31b82003-02-18 22:55:36 +00005752};
5753
5754static void target_to_host_termios (void *dst, const void *src)
5755{
5756 struct host_termios *host = dst;
5757 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005758
ths5fafdf22007-09-16 21:08:06 +00005759 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005760 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005761 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005762 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005763 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005764 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005765 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005766 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5767 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005768
Arnaud Patard44607122009-04-21 17:39:08 +03005769 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005770 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5771 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005772 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005773 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005774 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005775 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005776 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005777 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005778 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005779 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5780 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005781 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5782 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5783 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5784 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5785 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005786 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005787}
ths3b46e622007-09-17 08:09:54 +00005788
bellard31e31b82003-02-18 22:55:36 +00005789static void host_to_target_termios (void *dst, const void *src)
5790{
5791 struct target_termios *target = dst;
5792 const struct host_termios *host = src;
5793
ths5fafdf22007-09-16 21:08:06 +00005794 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005795 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005796 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005797 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005798 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005799 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005800 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005801 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5802 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005803
Arnaud Patard44607122009-04-21 17:39:08 +03005804 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005805 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5806 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5807 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5808 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5809 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5810 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5811 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5812 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5813 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5814 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5815 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5816 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5817 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5818 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5819 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5820 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5821 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5822}
5823
blueswir18e853dc2008-10-05 10:49:32 +00005824static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005825 .convert = { host_to_target_termios, target_to_host_termios },
5826 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5827 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
Filip Bozuta888468d2020-07-23 23:02:33 +02005828 .print = print_termios,
bellard31e31b82003-02-18 22:55:36 +00005829};
5830
Richard Henderson4b840f92023-07-07 21:40:36 +01005831/* If the host does not provide these bits, they may be safely discarded. */
5832#ifndef MAP_SYNC
5833#define MAP_SYNC 0
5834#endif
5835#ifndef MAP_UNINITIALIZED
5836#define MAP_UNINITIALIZED 0
5837#endif
5838
Philippe Mathieu-Daudé180d4ef2021-05-17 07:52:43 +02005839static const bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005840 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5841 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5842 MAP_ANONYMOUS, MAP_ANONYMOUS },
5843 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5844 MAP_GROWSDOWN, MAP_GROWSDOWN },
5845 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5846 MAP_DENYWRITE, MAP_DENYWRITE },
5847 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5848 MAP_EXECUTABLE, MAP_EXECUTABLE },
5849 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
5850 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
5851 MAP_NORESERVE, MAP_NORESERVE },
5852 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
5853 /* MAP_STACK had been ignored by the kernel for quite some time.
5854 Recognize it for the target insofar as we do not want to pass
5855 it through to the host. */
5856 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
Richard Henderson4b840f92023-07-07 21:40:36 +01005857 { TARGET_MAP_NONBLOCK, TARGET_MAP_NONBLOCK, MAP_NONBLOCK, MAP_NONBLOCK },
5858 { TARGET_MAP_POPULATE, TARGET_MAP_POPULATE, MAP_POPULATE, MAP_POPULATE },
5859 { TARGET_MAP_FIXED_NOREPLACE, TARGET_MAP_FIXED_NOREPLACE,
5860 MAP_FIXED_NOREPLACE, MAP_FIXED_NOREPLACE },
5861 { TARGET_MAP_UNINITIALIZED, TARGET_MAP_UNINITIALIZED,
5862 MAP_UNINITIALIZED, MAP_UNINITIALIZED },
bellard5286db72003-06-05 00:57:30 +00005863};
5864
Laurent Vivier9d12f792020-03-10 11:33:55 +01005865/*
Richard Henderson9ab8d0712023-08-07 18:22:35 -07005866 * Arrange for legacy / undefined architecture specific flags to be
5867 * ignored by mmap handling code.
5868 */
5869#ifndef TARGET_MAP_32BIT
5870#define TARGET_MAP_32BIT 0
5871#endif
5872#ifndef TARGET_MAP_HUGE_2MB
5873#define TARGET_MAP_HUGE_2MB 0
5874#endif
5875#ifndef TARGET_MAP_HUGE_1GB
5876#define TARGET_MAP_HUGE_1GB 0
5877#endif
5878
5879static abi_long do_mmap(abi_ulong addr, abi_ulong len, int prot,
5880 int target_flags, int fd, off_t offset)
5881{
5882 /*
5883 * The historical set of flags that all mmap types implicitly support.
5884 */
5885 enum {
5886 TARGET_LEGACY_MAP_MASK = TARGET_MAP_SHARED
5887 | TARGET_MAP_PRIVATE
5888 | TARGET_MAP_FIXED
5889 | TARGET_MAP_ANONYMOUS
5890 | TARGET_MAP_DENYWRITE
5891 | TARGET_MAP_EXECUTABLE
5892 | TARGET_MAP_UNINITIALIZED
5893 | TARGET_MAP_GROWSDOWN
5894 | TARGET_MAP_LOCKED
5895 | TARGET_MAP_NORESERVE
5896 | TARGET_MAP_POPULATE
5897 | TARGET_MAP_NONBLOCK
5898 | TARGET_MAP_STACK
5899 | TARGET_MAP_HUGETLB
5900 | TARGET_MAP_32BIT
5901 | TARGET_MAP_HUGE_2MB
5902 | TARGET_MAP_HUGE_1GB
5903 };
5904 int host_flags;
5905
5906 switch (target_flags & TARGET_MAP_TYPE) {
5907 case TARGET_MAP_PRIVATE:
5908 host_flags = MAP_PRIVATE;
5909 break;
5910 case TARGET_MAP_SHARED:
5911 host_flags = MAP_SHARED;
5912 break;
5913 case TARGET_MAP_SHARED_VALIDATE:
5914 /*
5915 * MAP_SYNC is only supported for MAP_SHARED_VALIDATE, and is
5916 * therefore omitted from mmap_flags_tbl and TARGET_LEGACY_MAP_MASK.
5917 */
5918 if (target_flags & ~(TARGET_LEGACY_MAP_MASK | TARGET_MAP_SYNC)) {
5919 return -TARGET_EOPNOTSUPP;
5920 }
5921 host_flags = MAP_SHARED_VALIDATE;
5922 if (target_flags & TARGET_MAP_SYNC) {
5923 host_flags |= MAP_SYNC;
5924 }
5925 break;
5926 default:
5927 return -TARGET_EINVAL;
5928 }
5929 host_flags |= target_to_host_bitmask(target_flags, mmap_flags_tbl);
5930
5931 return get_errno(target_mmap(addr, len, prot, host_flags, fd, offset));
5932}
5933
5934/*
Laurent Vivier9d12f792020-03-10 11:33:55 +01005935 * NOTE: TARGET_ABI32 is defined for TARGET_I386 (but not for TARGET_X86_64)
5936 * TARGET_I386 is defined if TARGET_X86_64 is defined
5937 */
bellard2ab83ea2003-06-15 19:56:46 +00005938#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005939
5940/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005941static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005942
bellard03acab62007-11-11 14:57:14 +00005943static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005944{
5945 int size;
pbrook53a59602006-03-25 19:31:22 +00005946 void *p;
bellard6dbad632003-03-16 18:05:05 +00005947
5948 if (!ldt_table)
5949 return 0;
5950 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5951 if (size > bytecount)
5952 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005953 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5954 if (!p)
bellard03acab62007-11-11 14:57:14 +00005955 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005956 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005957 memcpy(p, ldt_table, size);
5958 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005959 return size;
5960}
5961
5962/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005963static abi_long write_ldt(CPUX86State *env,
5964 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005965{
5966 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005967 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005968 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005969 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005970 uint32_t *lp, entry_1, entry_2;
5971
5972 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005973 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005974 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005975 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005976 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005977 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005978 ldt_info.limit = tswap32(target_ldt_info->limit);
5979 ldt_info.flags = tswap32(target_ldt_info->flags);
5980 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005981
bellard6dbad632003-03-16 18:05:05 +00005982 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005983 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005984 seg_32bit = ldt_info.flags & 1;
5985 contents = (ldt_info.flags >> 1) & 3;
5986 read_exec_only = (ldt_info.flags >> 3) & 1;
5987 limit_in_pages = (ldt_info.flags >> 4) & 1;
5988 seg_not_present = (ldt_info.flags >> 5) & 1;
5989 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005990#ifdef TARGET_ABI32
5991 lm = 0;
5992#else
5993 lm = (ldt_info.flags >> 7) & 1;
5994#endif
bellard6dbad632003-03-16 18:05:05 +00005995 if (contents == 3) {
5996 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005997 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005998 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005999 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006000 }
6001 /* allocate the LDT */
6002 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006003 env->ldt.base = target_mmap(0,
6004 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6005 PROT_READ|PROT_WRITE,
6006 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6007 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006008 return -TARGET_ENOMEM;
Richard Henderson3e8f1622021-02-12 10:48:43 -08006009 memset(g2h_untagged(env->ldt.base), 0,
balroge4415702008-11-10 02:55:33 +00006010 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006011 env->ldt.limit = 0xffff;
Richard Henderson3e8f1622021-02-12 10:48:43 -08006012 ldt_table = g2h_untagged(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006013 }
6014
6015 /* NOTE: same code as Linux kernel */
6016 /* Allow LDTs to be cleared by the user. */
6017 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6018 if (oldmode ||
6019 (contents == 0 &&
6020 read_exec_only == 1 &&
6021 seg_32bit == 0 &&
6022 limit_in_pages == 0 &&
6023 seg_not_present == 1 &&
6024 useable == 0 )) {
6025 entry_1 = 0;
6026 entry_2 = 0;
6027 goto install;
6028 }
6029 }
ths3b46e622007-09-17 08:09:54 +00006030
bellard6dbad632003-03-16 18:05:05 +00006031 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6032 (ldt_info.limit & 0x0ffff);
6033 entry_2 = (ldt_info.base_addr & 0xff000000) |
6034 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6035 (ldt_info.limit & 0xf0000) |
6036 ((read_exec_only ^ 1) << 9) |
6037 (contents << 10) |
6038 ((seg_not_present ^ 1) << 15) |
6039 (seg_32bit << 22) |
6040 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006041 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006042 0x7000;
6043 if (!oldmode)
6044 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006045
bellard6dbad632003-03-16 18:05:05 +00006046 /* Install the new entry ... */
6047install:
6048 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6049 lp[0] = tswap32(entry_1);
6050 lp[1] = tswap32(entry_2);
6051 return 0;
6052}
6053
6054/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006055static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6056 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006057{
bellard03acab62007-11-11 14:57:14 +00006058 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006059
bellard6dbad632003-03-16 18:05:05 +00006060 switch (func) {
6061 case 0:
6062 ret = read_ldt(ptr, bytecount);
6063 break;
6064 case 1:
6065 ret = write_ldt(env, ptr, bytecount, 1);
6066 break;
6067 case 0x11:
6068 ret = write_ldt(env, ptr, bytecount, 0);
6069 break;
bellard03acab62007-11-11 14:57:14 +00006070 default:
6071 ret = -TARGET_ENOSYS;
6072 break;
bellard6dbad632003-03-16 18:05:05 +00006073 }
6074 return ret;
6075}
bellard1b6b0292003-03-22 17:31:38 +00006076
Laurent Vivier9d12f792020-03-10 11:33:55 +01006077#if defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006078abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006079{
Richard Henderson3e8f1622021-02-12 10:48:43 -08006080 uint64_t *gdt_table = g2h_untagged(env->gdt.base);
bellard8d18e892007-11-14 15:18:40 +00006081 struct target_modify_ldt_ldt_s ldt_info;
6082 struct target_modify_ldt_ldt_s *target_ldt_info;
6083 int seg_32bit, contents, read_exec_only, limit_in_pages;
6084 int seg_not_present, useable, lm;
6085 uint32_t *lp, entry_1, entry_2;
6086 int i;
6087
6088 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6089 if (!target_ldt_info)
6090 return -TARGET_EFAULT;
6091 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006092 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006093 ldt_info.limit = tswap32(target_ldt_info->limit);
6094 ldt_info.flags = tswap32(target_ldt_info->flags);
6095 if (ldt_info.entry_number == -1) {
6096 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6097 if (gdt_table[i] == 0) {
6098 ldt_info.entry_number = i;
6099 target_ldt_info->entry_number = tswap32(i);
6100 break;
6101 }
6102 }
6103 }
6104 unlock_user_struct(target_ldt_info, ptr, 1);
6105
6106 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6107 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6108 return -TARGET_EINVAL;
6109 seg_32bit = ldt_info.flags & 1;
6110 contents = (ldt_info.flags >> 1) & 3;
6111 read_exec_only = (ldt_info.flags >> 3) & 1;
6112 limit_in_pages = (ldt_info.flags >> 4) & 1;
6113 seg_not_present = (ldt_info.flags >> 5) & 1;
6114 useable = (ldt_info.flags >> 6) & 1;
6115#ifdef TARGET_ABI32
6116 lm = 0;
6117#else
6118 lm = (ldt_info.flags >> 7) & 1;
6119#endif
6120
6121 if (contents == 3) {
6122 if (seg_not_present == 0)
6123 return -TARGET_EINVAL;
6124 }
6125
6126 /* NOTE: same code as Linux kernel */
6127 /* Allow LDTs to be cleared by the user. */
6128 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6129 if ((contents == 0 &&
6130 read_exec_only == 1 &&
6131 seg_32bit == 0 &&
6132 limit_in_pages == 0 &&
6133 seg_not_present == 1 &&
6134 useable == 0 )) {
6135 entry_1 = 0;
6136 entry_2 = 0;
6137 goto install;
6138 }
6139 }
6140
6141 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6142 (ldt_info.limit & 0x0ffff);
6143 entry_2 = (ldt_info.base_addr & 0xff000000) |
6144 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6145 (ldt_info.limit & 0xf0000) |
6146 ((read_exec_only ^ 1) << 9) |
6147 (contents << 10) |
6148 ((seg_not_present ^ 1) << 15) |
6149 (seg_32bit << 22) |
6150 (limit_in_pages << 23) |
6151 (useable << 20) |
6152 (lm << 21) |
6153 0x7000;
6154
6155 /* Install the new entry ... */
6156install:
6157 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6158 lp[0] = tswap32(entry_1);
6159 lp[1] = tswap32(entry_2);
6160 return 0;
6161}
6162
blueswir18fcd3692008-08-17 20:26:25 +00006163static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006164{
6165 struct target_modify_ldt_ldt_s *target_ldt_info;
Richard Henderson3e8f1622021-02-12 10:48:43 -08006166 uint64_t *gdt_table = g2h_untagged(env->gdt.base);
bellard8d18e892007-11-14 15:18:40 +00006167 uint32_t base_addr, limit, flags;
6168 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6169 int seg_not_present, useable, lm;
6170 uint32_t *lp, entry_1, entry_2;
6171
6172 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6173 if (!target_ldt_info)
6174 return -TARGET_EFAULT;
6175 idx = tswap32(target_ldt_info->entry_number);
6176 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6177 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6178 unlock_user_struct(target_ldt_info, ptr, 1);
6179 return -TARGET_EINVAL;
6180 }
6181 lp = (uint32_t *)(gdt_table + idx);
6182 entry_1 = tswap32(lp[0]);
6183 entry_2 = tswap32(lp[1]);
6184
6185 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6186 contents = (entry_2 >> 10) & 3;
6187 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6188 seg_32bit = (entry_2 >> 22) & 1;
6189 limit_in_pages = (entry_2 >> 23) & 1;
6190 useable = (entry_2 >> 20) & 1;
6191#ifdef TARGET_ABI32
6192 lm = 0;
6193#else
6194 lm = (entry_2 >> 21) & 1;
6195#endif
6196 flags = (seg_32bit << 0) | (contents << 1) |
6197 (read_exec_only << 3) | (limit_in_pages << 4) |
6198 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6199 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6200 base_addr = (entry_1 >> 16) |
6201 (entry_2 & 0xff000000) |
6202 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006203 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006204 target_ldt_info->limit = tswap32(limit);
6205 target_ldt_info->flags = tswap32(flags);
6206 unlock_user_struct(target_ldt_info, ptr, 1);
6207 return 0;
6208}
6209
Laurent Vivier9d12f792020-03-10 11:33:55 +01006210abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
6211{
Helge Deller538fabc2020-04-25 00:00:33 +02006212 return -TARGET_ENOSYS;
Laurent Vivier9d12f792020-03-10 11:33:55 +01006213}
6214#else
Peter Maydell2667e712013-07-16 18:44:59 +01006215abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006216{
Juan Quintela1add8692011-06-16 17:37:09 +01006217 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006218 abi_ulong val;
6219 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006220
bellardd2fd1af2007-11-14 18:08:56 +00006221 switch(code) {
6222 case TARGET_ARCH_SET_GS:
6223 case TARGET_ARCH_SET_FS:
6224 if (code == TARGET_ARCH_SET_GS)
6225 idx = R_GS;
6226 else
6227 idx = R_FS;
6228 cpu_x86_load_seg(env, idx, 0);
6229 env->segs[idx].base = addr;
6230 break;
6231 case TARGET_ARCH_GET_GS:
6232 case TARGET_ARCH_GET_FS:
6233 if (code == TARGET_ARCH_GET_GS)
6234 idx = R_GS;
6235 else
6236 idx = R_FS;
6237 val = env->segs[idx].base;
6238 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006239 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006240 break;
6241 default:
6242 ret = -TARGET_EINVAL;
6243 break;
6244 }
Juan Quintela1add8692011-06-16 17:37:09 +01006245 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006246}
Laurent Vivier9d12f792020-03-10 11:33:55 +01006247#endif /* defined(TARGET_ABI32 */
bellard2ab83ea2003-06-15 19:56:46 +00006248#endif /* defined(TARGET_I386) */
6249
Richard Henderson87e9bf22021-12-27 07:01:22 -08006250/*
6251 * These constants are generic. Supply any that are missing from the host.
6252 */
6253#ifndef PR_SET_NAME
6254# define PR_SET_NAME 15
6255# define PR_GET_NAME 16
6256#endif
6257#ifndef PR_SET_FP_MODE
6258# define PR_SET_FP_MODE 45
6259# define PR_GET_FP_MODE 46
6260# define PR_FP_MODE_FR (1 << 0)
6261# define PR_FP_MODE_FRE (1 << 1)
6262#endif
6263#ifndef PR_SVE_SET_VL
6264# define PR_SVE_SET_VL 50
6265# define PR_SVE_GET_VL 51
6266# define PR_SVE_VL_LEN_MASK 0xffff
6267# define PR_SVE_VL_INHERIT (1 << 17)
6268#endif
6269#ifndef PR_PAC_RESET_KEYS
6270# define PR_PAC_RESET_KEYS 54
6271# define PR_PAC_APIAKEY (1 << 0)
6272# define PR_PAC_APIBKEY (1 << 1)
6273# define PR_PAC_APDAKEY (1 << 2)
6274# define PR_PAC_APDBKEY (1 << 3)
6275# define PR_PAC_APGAKEY (1 << 4)
6276#endif
6277#ifndef PR_SET_TAGGED_ADDR_CTRL
6278# define PR_SET_TAGGED_ADDR_CTRL 55
6279# define PR_GET_TAGGED_ADDR_CTRL 56
6280# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
6281#endif
Richard Henderson220717a2021-12-27 07:01:23 -08006282#ifndef PR_SET_IO_FLUSHER
6283# define PR_SET_IO_FLUSHER 57
6284# define PR_GET_IO_FLUSHER 58
6285#endif
6286#ifndef PR_SET_SYSCALL_USER_DISPATCH
6287# define PR_SET_SYSCALL_USER_DISPATCH 59
6288#endif
Richard Henderson24d87c12022-07-08 20:45:37 +05306289#ifndef PR_SME_SET_VL
6290# define PR_SME_SET_VL 63
6291# define PR_SME_GET_VL 64
6292# define PR_SME_VL_LEN_MASK 0xffff
6293# define PR_SME_VL_INHERIT (1 << 17)
6294#endif
Richard Henderson87e9bf22021-12-27 07:01:22 -08006295
6296#include "target_prctl.h"
6297
6298static abi_long do_prctl_inval0(CPUArchState *env)
6299{
6300 return -TARGET_EINVAL;
6301}
6302
6303static abi_long do_prctl_inval1(CPUArchState *env, abi_long arg2)
6304{
6305 return -TARGET_EINVAL;
6306}
6307
6308#ifndef do_prctl_get_fp_mode
6309#define do_prctl_get_fp_mode do_prctl_inval0
6310#endif
6311#ifndef do_prctl_set_fp_mode
6312#define do_prctl_set_fp_mode do_prctl_inval1
6313#endif
Richard Hendersonfd72f5d2022-07-08 20:45:36 +05306314#ifndef do_prctl_sve_get_vl
6315#define do_prctl_sve_get_vl do_prctl_inval0
Richard Henderson87e9bf22021-12-27 07:01:22 -08006316#endif
Richard Hendersonfd72f5d2022-07-08 20:45:36 +05306317#ifndef do_prctl_sve_set_vl
6318#define do_prctl_sve_set_vl do_prctl_inval1
Richard Henderson87e9bf22021-12-27 07:01:22 -08006319#endif
6320#ifndef do_prctl_reset_keys
6321#define do_prctl_reset_keys do_prctl_inval1
6322#endif
6323#ifndef do_prctl_set_tagged_addr_ctrl
6324#define do_prctl_set_tagged_addr_ctrl do_prctl_inval1
6325#endif
6326#ifndef do_prctl_get_tagged_addr_ctrl
6327#define do_prctl_get_tagged_addr_ctrl do_prctl_inval0
6328#endif
Richard Henderson6e8dcac2021-12-27 07:01:24 -08006329#ifndef do_prctl_get_unalign
6330#define do_prctl_get_unalign do_prctl_inval1
6331#endif
6332#ifndef do_prctl_set_unalign
6333#define do_prctl_set_unalign do_prctl_inval1
6334#endif
Richard Henderson24d87c12022-07-08 20:45:37 +05306335#ifndef do_prctl_sme_get_vl
6336#define do_prctl_sme_get_vl do_prctl_inval0
6337#endif
6338#ifndef do_prctl_sme_set_vl
6339#define do_prctl_sme_set_vl do_prctl_inval1
6340#endif
Richard Henderson87e9bf22021-12-27 07:01:22 -08006341
6342static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
6343 abi_long arg3, abi_long arg4, abi_long arg5)
6344{
6345 abi_long ret;
6346
6347 switch (option) {
6348 case PR_GET_PDEATHSIG:
6349 {
6350 int deathsig;
6351 ret = get_errno(prctl(PR_GET_PDEATHSIG, &deathsig,
6352 arg3, arg4, arg5));
Richard Henderson1edebb32022-01-06 14:57:36 -08006353 if (!is_error(ret) &&
6354 put_user_s32(host_to_target_signal(deathsig), arg2)) {
Richard Henderson87e9bf22021-12-27 07:01:22 -08006355 return -TARGET_EFAULT;
6356 }
6357 return ret;
6358 }
Richard Hendersonf746c652022-01-06 14:57:37 -08006359 case PR_SET_PDEATHSIG:
6360 return get_errno(prctl(PR_SET_PDEATHSIG, target_to_host_signal(arg2),
6361 arg3, arg4, arg5));
Richard Henderson87e9bf22021-12-27 07:01:22 -08006362 case PR_GET_NAME:
6363 {
6364 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
6365 if (!name) {
6366 return -TARGET_EFAULT;
6367 }
6368 ret = get_errno(prctl(PR_GET_NAME, (uintptr_t)name,
6369 arg3, arg4, arg5));
6370 unlock_user(name, arg2, 16);
6371 return ret;
6372 }
6373 case PR_SET_NAME:
6374 {
6375 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
6376 if (!name) {
6377 return -TARGET_EFAULT;
6378 }
6379 ret = get_errno(prctl(PR_SET_NAME, (uintptr_t)name,
6380 arg3, arg4, arg5));
6381 unlock_user(name, arg2, 0);
6382 return ret;
6383 }
6384 case PR_GET_FP_MODE:
6385 return do_prctl_get_fp_mode(env);
6386 case PR_SET_FP_MODE:
6387 return do_prctl_set_fp_mode(env, arg2);
6388 case PR_SVE_GET_VL:
Richard Hendersonfd72f5d2022-07-08 20:45:36 +05306389 return do_prctl_sve_get_vl(env);
Richard Henderson87e9bf22021-12-27 07:01:22 -08006390 case PR_SVE_SET_VL:
Richard Hendersonfd72f5d2022-07-08 20:45:36 +05306391 return do_prctl_sve_set_vl(env, arg2);
Richard Henderson24d87c12022-07-08 20:45:37 +05306392 case PR_SME_GET_VL:
6393 return do_prctl_sme_get_vl(env);
6394 case PR_SME_SET_VL:
6395 return do_prctl_sme_set_vl(env, arg2);
Richard Henderson87e9bf22021-12-27 07:01:22 -08006396 case PR_PAC_RESET_KEYS:
6397 if (arg3 || arg4 || arg5) {
6398 return -TARGET_EINVAL;
6399 }
6400 return do_prctl_reset_keys(env, arg2);
6401 case PR_SET_TAGGED_ADDR_CTRL:
6402 if (arg3 || arg4 || arg5) {
6403 return -TARGET_EINVAL;
6404 }
6405 return do_prctl_set_tagged_addr_ctrl(env, arg2);
6406 case PR_GET_TAGGED_ADDR_CTRL:
6407 if (arg2 || arg3 || arg4 || arg5) {
6408 return -TARGET_EINVAL;
6409 }
6410 return do_prctl_get_tagged_addr_ctrl(env);
Richard Henderson220717a2021-12-27 07:01:23 -08006411
Richard Henderson6e8dcac2021-12-27 07:01:24 -08006412 case PR_GET_UNALIGN:
6413 return do_prctl_get_unalign(env, arg2);
6414 case PR_SET_UNALIGN:
6415 return do_prctl_set_unalign(env, arg2);
6416
Richard Henderson4f4e5562022-01-06 14:57:38 -08006417 case PR_CAP_AMBIENT:
6418 case PR_CAPBSET_READ:
6419 case PR_CAPBSET_DROP:
Richard Henderson220717a2021-12-27 07:01:23 -08006420 case PR_GET_DUMPABLE:
6421 case PR_SET_DUMPABLE:
6422 case PR_GET_KEEPCAPS:
6423 case PR_SET_KEEPCAPS:
Richard Henderson4f4e5562022-01-06 14:57:38 -08006424 case PR_GET_SECUREBITS:
6425 case PR_SET_SECUREBITS:
Richard Henderson220717a2021-12-27 07:01:23 -08006426 case PR_GET_TIMING:
6427 case PR_SET_TIMING:
6428 case PR_GET_TIMERSLACK:
6429 case PR_SET_TIMERSLACK:
6430 case PR_MCE_KILL:
6431 case PR_MCE_KILL_GET:
6432 case PR_GET_NO_NEW_PRIVS:
6433 case PR_SET_NO_NEW_PRIVS:
6434 case PR_GET_IO_FLUSHER:
6435 case PR_SET_IO_FLUSHER:
Richard Henderson07726f52024-03-01 14:52:30 -10006436 case PR_SET_CHILD_SUBREAPER:
Richard Henderson91511bd2024-03-01 14:56:45 -10006437 case PR_GET_SPECULATION_CTRL:
6438 case PR_SET_SPECULATION_CTRL:
Richard Henderson220717a2021-12-27 07:01:23 -08006439 /* Some prctl options have no pointer arguments and we can pass on. */
6440 return get_errno(prctl(option, arg2, arg3, arg4, arg5));
6441
6442 case PR_GET_CHILD_SUBREAPER:
Richard Henderson07726f52024-03-01 14:52:30 -10006443 {
6444 int val;
6445 ret = get_errno(prctl(PR_GET_CHILD_SUBREAPER, &val,
6446 arg3, arg4, arg5));
6447 if (!is_error(ret) && put_user_s32(val, arg2)) {
6448 return -TARGET_EFAULT;
6449 }
6450 return ret;
6451 }
6452
Richard Henderson220717a2021-12-27 07:01:23 -08006453 case PR_GET_TID_ADDRESS:
Richard Henderson8de24b12024-03-01 15:04:39 -10006454 {
Philippe Mathieu-Daudé59272462024-04-25 11:12:19 +02006455 TaskState *ts = get_task_state(env_cpu(env));
Richard Henderson8de24b12024-03-01 15:04:39 -10006456 return put_user_ual(ts->child_tidptr, arg2);
6457 }
Richard Henderson220717a2021-12-27 07:01:23 -08006458
6459 case PR_GET_FPEXC:
6460 case PR_SET_FPEXC:
6461 /* Was used for SPE on PowerPC. */
6462 return -TARGET_EINVAL;
6463
6464 case PR_GET_ENDIAN:
6465 case PR_SET_ENDIAN:
6466 case PR_GET_FPEMU:
6467 case PR_SET_FPEMU:
6468 case PR_SET_MM:
Richard Henderson87e9bf22021-12-27 07:01:22 -08006469 case PR_GET_SECCOMP:
6470 case PR_SET_SECCOMP:
Richard Henderson220717a2021-12-27 07:01:23 -08006471 case PR_SET_SYSCALL_USER_DISPATCH:
6472 case PR_GET_THP_DISABLE:
6473 case PR_SET_THP_DISABLE:
6474 case PR_GET_TSC:
6475 case PR_SET_TSC:
Richard Henderson220717a2021-12-27 07:01:23 -08006476 /* Disable to prevent the target disabling stuff we need. */
Richard Henderson87e9bf22021-12-27 07:01:22 -08006477 return -TARGET_EINVAL;
Richard Henderson220717a2021-12-27 07:01:23 -08006478
Richard Henderson87e9bf22021-12-27 07:01:22 -08006479 default:
Richard Henderson220717a2021-12-27 07:01:23 -08006480 qemu_log_mask(LOG_UNIMP, "Unsupported prctl: " TARGET_ABI_FMT_ld "\n",
6481 option);
6482 return -TARGET_EINVAL;
Richard Henderson87e9bf22021-12-27 07:01:22 -08006483 }
6484}
6485
Riku Voipio05098a92011-03-04 15:27:29 +02006486#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006487
pbrookd865bab2008-06-07 22:12:17 +00006488
6489static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6490typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006491 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006492 pthread_mutex_t mutex;
6493 pthread_cond_t cond;
6494 pthread_t thread;
6495 uint32_t tid;
6496 abi_ulong child_tidptr;
6497 abi_ulong parent_tidptr;
6498 sigset_t sigmask;
6499} new_thread_info;
6500
6501static void *clone_func(void *arg)
6502{
6503 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006504 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006505 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006506 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006507
Emilio G. Cota70903762015-08-23 20:23:41 -04006508 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006509 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006510 env = info->env;
Richard Henderson29a0af62019-03-22 16:07:18 -07006511 cpu = env_cpu(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006512 thread_cpu = cpu;
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00006513 ts = get_task_state(cpu);
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006514 info->tid = sys_gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006515 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006516 if (info->child_tidptr)
6517 put_user_u32(info->tid, info->child_tidptr);
6518 if (info->parent_tidptr)
6519 put_user_u32(info->tid, info->parent_tidptr);
Richard Henderson5ebdd772019-03-14 13:10:53 -07006520 qemu_guest_random_seed_thread_part2(cpu->random_seed);
pbrookd865bab2008-06-07 22:12:17 +00006521 /* Enable signals. */
6522 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6523 /* Signal to the parent that we're ready. */
6524 pthread_mutex_lock(&info->mutex);
6525 pthread_cond_broadcast(&info->cond);
6526 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006527 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006528 pthread_mutex_lock(&clone_lock);
6529 pthread_mutex_unlock(&clone_lock);
6530 cpu_loop(env);
6531 /* never exits */
6532 return NULL;
6533}
bellard1b6b0292003-03-22 17:31:38 +00006534
ths0da46a62007-10-20 20:23:07 +00006535/* do_fork() Must return host values and target errnos (unlike most
6536 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006537static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006538 abi_ulong parent_tidptr, target_ulong newtls,
6539 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006540{
Richard Henderson29a0af62019-03-22 16:07:18 -07006541 CPUState *cpu = env_cpu(env);
bellard1b6b0292003-03-22 17:31:38 +00006542 int ret;
bellard5cd43932003-03-29 16:54:36 +00006543 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006544 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006545 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006546 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006547
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006548 flags &= ~CLONE_IGNORED_FLAGS;
6549
balrog436d1242008-09-21 02:39:45 +00006550 /* Emulate vfork() with fork() */
6551 if (flags & CLONE_VFORK)
6552 flags &= ~(CLONE_VFORK | CLONE_VM);
6553
bellard1b6b0292003-03-22 17:31:38 +00006554 if (flags & CLONE_VM) {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00006555 TaskState *parent_ts = get_task_state(cpu);
pbrookd865bab2008-06-07 22:12:17 +00006556 new_thread_info info;
6557 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006558
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006559 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6560 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6561 return -TARGET_EINVAL;
6562 }
6563
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006564 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006565 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006566
6567 /* Grab a mutex so that thread setup appears atomic. */
6568 pthread_mutex_lock(&clone_lock);
6569
Richard Henderson6cc9d672021-03-01 19:21:08 -08006570 /*
6571 * If this is our first additional thread, we need to ensure we
6572 * generate code for parallel execution and flush old translations.
6573 * Do this now so that the copy gets CF_PARALLEL too.
6574 */
Philippe Mathieu-Daudéb254c342024-01-10 18:09:56 +01006575 if (!tcg_cflags_has(cpu, CF_PARALLEL)) {
6576 tcg_cflags_set(cpu, CF_PARALLEL);
Richard Henderson6cc9d672021-03-01 19:21:08 -08006577 tb_flush(cpu);
6578 }
6579
bellard1b6b0292003-03-22 17:31:38 +00006580 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006581 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006582 /* Init regs that differ from the parent. */
Richard Henderson608999d2019-11-06 12:33:15 +01006583 cpu_clone_regs_child(new_env, newsp, flags);
Richard Henderson07a6ecf2019-11-06 12:33:16 +01006584 cpu_clone_regs_parent(env, flags);
Richard Henderson29a0af62019-03-22 16:07:18 -07006585 new_cpu = env_cpu(new_env);
Andreas Färber0429a972013-08-26 18:14:44 +02006586 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006587 ts->bprm = parent_ts->bprm;
6588 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006589 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006590
Peter Maydell7cfbd382016-08-02 18:41:26 +01006591 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006592 ts->child_tidptr = child_tidptr;
6593 }
6594
Peter Maydell7cfbd382016-08-02 18:41:26 +01006595 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006596 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006597 }
pbrookd865bab2008-06-07 22:12:17 +00006598
pbrookd865bab2008-06-07 22:12:17 +00006599 memset(&info, 0, sizeof(info));
6600 pthread_mutex_init(&info.mutex, NULL);
6601 pthread_mutex_lock(&info.mutex);
6602 pthread_cond_init(&info.cond, NULL);
6603 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006604 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006605 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006606 }
6607 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006608 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006609 }
pbrookd865bab2008-06-07 22:12:17 +00006610
6611 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006612 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6613 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006614 /* It is not safe to deliver signals until the child has finished
6615 initializing, so temporarily block all signals. */
6616 sigfillset(&sigmask);
6617 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
Richard Henderson5ebdd772019-03-14 13:10:53 -07006618 cpu->random_seed = qemu_guest_random_seed_thread_part1();
pbrookd865bab2008-06-07 22:12:17 +00006619
6620 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006621 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006622
6623 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6624 pthread_attr_destroy(&attr);
6625 if (ret == 0) {
6626 /* Wait for the child to initialize. */
6627 pthread_cond_wait(&info.cond, &info.mutex);
6628 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006629 } else {
6630 ret = -1;
6631 }
6632 pthread_mutex_unlock(&info.mutex);
6633 pthread_cond_destroy(&info.cond);
6634 pthread_mutex_destroy(&info.mutex);
6635 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006636 } else {
6637 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006638 if (flags & CLONE_INVALID_FORK_FLAGS) {
6639 return -TARGET_EINVAL;
6640 }
6641
6642 /* We can't support custom termination signals */
6643 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006644 return -TARGET_EINVAL;
6645 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006646
Helge Deller895ce8b2022-11-29 12:08:20 +01006647#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open)
6648 if (flags & CLONE_PIDFD) {
6649 return -TARGET_EINVAL;
6650 }
6651#endif
6652
6653 /* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */
6654 if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) {
6655 return -TARGET_EINVAL;
6656 }
6657
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006658 if (block_signals()) {
Richard Hendersonaf254a22021-11-22 19:47:33 +01006659 return -QEMU_ERESTARTSYS;
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006660 }
6661
pbrookd865bab2008-06-07 22:12:17 +00006662 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006663 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006664 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006665 /* Child Process. */
Richard Henderson608999d2019-11-06 12:33:15 +01006666 cpu_clone_regs_child(env, newsp, flags);
Ilya Leoshkevich4edc98f2024-03-05 12:09:42 +00006667 fork_end(ret);
aurel322b1319c2008-12-18 22:44:04 +00006668 /* There is a race condition here. The parent process could
6669 theoretically read the TID in the child process before the child
6670 tid is set. This would require using either ptrace
6671 (not implemented) or having *_tidptr to point at a shared memory
6672 mapping. We can't repeat the spinlock hack used above because
6673 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006674 if (flags & CLONE_CHILD_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006675 put_user_u32(sys_gettid(), child_tidptr);
pbrookd865bab2008-06-07 22:12:17 +00006676 if (flags & CLONE_PARENT_SETTID)
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +00006677 put_user_u32(sys_gettid(), parent_tidptr);
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00006678 ts = get_task_state(cpu);
pbrookd865bab2008-06-07 22:12:17 +00006679 if (flags & CLONE_SETTLS)
6680 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006681 if (flags & CLONE_CHILD_CLEARTID)
6682 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006683 } else {
Richard Henderson07a6ecf2019-11-06 12:33:16 +01006684 cpu_clone_regs_parent(env, flags);
Helge Deller895ce8b2022-11-29 12:08:20 +01006685 if (flags & CLONE_PIDFD) {
6686 int pid_fd = 0;
6687#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
6688 int pid_child = ret;
6689 pid_fd = pidfd_open(pid_child, 0);
6690 if (pid_fd >= 0) {
6691 fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
6692 | FD_CLOEXEC);
6693 } else {
6694 pid_fd = 0;
6695 }
6696#endif
6697 put_user_u32(pid_fd, parent_tidptr);
Ilya Leoshkevich4edc98f2024-03-05 12:09:42 +00006698 }
6699 fork_end(ret);
pbrookd865bab2008-06-07 22:12:17 +00006700 }
Ilya Leoshkevich7de08162023-02-14 15:08:26 +01006701 g_assert(!cpu_in_exclusive_context(cpu));
bellard1b6b0292003-03-22 17:31:38 +00006702 }
6703 return ret;
6704}
6705
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006706/* warning : doesn't handle linux specific flags... */
6707static int target_to_host_fcntl_cmd(int cmd)
6708{
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006709 int ret;
6710
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006711 switch(cmd) {
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006712 case TARGET_F_DUPFD:
6713 case TARGET_F_GETFD:
6714 case TARGET_F_SETFD:
6715 case TARGET_F_GETFL:
6716 case TARGET_F_SETFL:
Andreas Schwab2d92c682020-05-25 09:59:28 +02006717 case TARGET_F_OFD_GETLK:
6718 case TARGET_F_OFD_SETLK:
6719 case TARGET_F_OFD_SETLKW:
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006720 ret = cmd;
6721 break;
6722 case TARGET_F_GETLK:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006723 ret = F_GETLK;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006724 break;
6725 case TARGET_F_SETLK:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006726 ret = F_SETLK;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006727 break;
6728 case TARGET_F_SETLKW:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006729 ret = F_SETLKW;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006730 break;
6731 case TARGET_F_GETOWN:
6732 ret = F_GETOWN;
6733 break;
6734 case TARGET_F_SETOWN:
6735 ret = F_SETOWN;
6736 break;
6737 case TARGET_F_GETSIG:
6738 ret = F_GETSIG;
6739 break;
6740 case TARGET_F_SETSIG:
6741 ret = F_SETSIG;
6742 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006743#if TARGET_ABI_BITS == 32
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006744 case TARGET_F_GETLK64:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006745 ret = F_GETLK;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006746 break;
6747 case TARGET_F_SETLK64:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006748 ret = F_SETLK;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006749 break;
6750 case TARGET_F_SETLKW64:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006751 ret = F_SETLKW;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006752 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006753#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006754 case TARGET_F_SETLEASE:
6755 ret = F_SETLEASE;
6756 break;
6757 case TARGET_F_GETLEASE:
6758 ret = F_GETLEASE;
6759 break;
malcfbd5de92009-09-06 06:31:59 +04006760#ifdef F_DUPFD_CLOEXEC
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006761 case TARGET_F_DUPFD_CLOEXEC:
6762 ret = F_DUPFD_CLOEXEC;
6763 break;
malcfbd5de92009-09-06 06:31:59 +04006764#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006765 case TARGET_F_NOTIFY:
6766 ret = F_NOTIFY;
6767 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006768#ifdef F_GETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006769 case TARGET_F_GETOWN_EX:
6770 ret = F_GETOWN_EX;
6771 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006772#endif
6773#ifdef F_SETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006774 case TARGET_F_SETOWN_EX:
6775 ret = F_SETOWN_EX;
6776 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006777#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006778#ifdef F_SETPIPE_SZ
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006779 case TARGET_F_SETPIPE_SZ:
6780 ret = F_SETPIPE_SZ;
6781 break;
6782 case TARGET_F_GETPIPE_SZ:
6783 ret = F_GETPIPE_SZ;
6784 break;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006785#endif
Shu-Chun Weng2bb963f2020-12-18 11:32:10 -08006786#ifdef F_ADD_SEALS
6787 case TARGET_F_ADD_SEALS:
6788 ret = F_ADD_SEALS;
6789 break;
6790 case TARGET_F_GET_SEALS:
6791 ret = F_GET_SEALS;
6792 break;
6793#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006794 default:
6795 ret = -TARGET_EINVAL;
6796 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006797 }
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006798
6799#if defined(__powerpc64__)
6800 /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
6801 * is not supported by kernel. The glibc fcntl call actually adjusts
6802 * them to 5, 6 and 7 before making the syscall(). Since we make the
6803 * syscall directly, adjust to what is supported by the kernel.
6804 */
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006805 if (ret >= F_GETLK && ret <= F_SETLKW) {
6806 ret -= F_GETLK - 5;
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006807 }
6808#endif
6809
6810 return ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006811}
6812
Laurent Vivierae68ad92018-05-10 01:11:21 +02006813#define FLOCK_TRANSTBL \
6814 switch (type) { \
6815 TRANSTBL_CONVERT(F_RDLCK); \
6816 TRANSTBL_CONVERT(F_WRLCK); \
6817 TRANSTBL_CONVERT(F_UNLCK); \
Laurent Vivierae68ad92018-05-10 01:11:21 +02006818 }
6819
6820static int target_to_host_flock(int type)
6821{
6822#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
6823 FLOCK_TRANSTBL
6824#undef TRANSTBL_CONVERT
6825 return -TARGET_EINVAL;
6826}
6827
6828static int host_to_target_flock(int type)
6829{
6830#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
6831 FLOCK_TRANSTBL
6832#undef TRANSTBL_CONVERT
6833 /* if we don't know how to convert the value coming
6834 * from the host we copy to the target field as-is
6835 */
6836 return type;
6837}
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006838
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006839static inline abi_long copy_from_user_flock(struct flock *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006840 abi_ulong target_flock_addr)
6841{
6842 struct target_flock *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006843 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006844
6845 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6846 return -TARGET_EFAULT;
6847 }
6848
6849 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006850 l_type = target_to_host_flock(l_type);
6851 if (l_type < 0) {
6852 return l_type;
6853 }
6854 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006855 __get_user(fl->l_whence, &target_fl->l_whence);
6856 __get_user(fl->l_start, &target_fl->l_start);
6857 __get_user(fl->l_len, &target_fl->l_len);
6858 __get_user(fl->l_pid, &target_fl->l_pid);
6859 unlock_user_struct(target_fl, target_flock_addr, 0);
6860 return 0;
6861}
6862
6863static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006864 const struct flock *fl)
Peter Maydell213d3e92016-06-13 11:22:05 +01006865{
6866 struct target_flock *target_fl;
6867 short l_type;
6868
6869 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6870 return -TARGET_EFAULT;
6871 }
6872
Laurent Vivierae68ad92018-05-10 01:11:21 +02006873 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006874 __put_user(l_type, &target_fl->l_type);
6875 __put_user(fl->l_whence, &target_fl->l_whence);
6876 __put_user(fl->l_start, &target_fl->l_start);
6877 __put_user(fl->l_len, &target_fl->l_len);
6878 __put_user(fl->l_pid, &target_fl->l_pid);
6879 unlock_user_struct(target_fl, target_flock_addr, 1);
6880 return 0;
6881}
6882
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006883typedef abi_long from_flock64_fn(struct flock *fl, abi_ulong target_addr);
6884typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock *fl);
Peter Maydell213d3e92016-06-13 11:22:05 +01006885
6886#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
Richard Hendersonffe81d42022-01-06 20:25:59 -08006887struct target_oabi_flock64 {
6888 abi_short l_type;
6889 abi_short l_whence;
6890 abi_llong l_start;
6891 abi_llong l_len;
6892 abi_int l_pid;
6893} QEMU_PACKED;
6894
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006895static inline abi_long copy_from_user_oabi_flock64(struct flock *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006896 abi_ulong target_flock_addr)
6897{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006898 struct target_oabi_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006899 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006900
6901 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6902 return -TARGET_EFAULT;
6903 }
6904
6905 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006906 l_type = target_to_host_flock(l_type);
6907 if (l_type < 0) {
6908 return l_type;
6909 }
6910 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006911 __get_user(fl->l_whence, &target_fl->l_whence);
6912 __get_user(fl->l_start, &target_fl->l_start);
6913 __get_user(fl->l_len, &target_fl->l_len);
6914 __get_user(fl->l_pid, &target_fl->l_pid);
6915 unlock_user_struct(target_fl, target_flock_addr, 0);
6916 return 0;
6917}
6918
Laurent Vivier7f254c52018-05-02 23:57:30 +02006919static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006920 const struct flock *fl)
Peter Maydell213d3e92016-06-13 11:22:05 +01006921{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006922 struct target_oabi_flock64 *target_fl;
Peter Maydell213d3e92016-06-13 11:22:05 +01006923 short l_type;
6924
6925 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6926 return -TARGET_EFAULT;
6927 }
6928
Laurent Vivierae68ad92018-05-10 01:11:21 +02006929 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006930 __put_user(l_type, &target_fl->l_type);
6931 __put_user(fl->l_whence, &target_fl->l_whence);
6932 __put_user(fl->l_start, &target_fl->l_start);
6933 __put_user(fl->l_len, &target_fl->l_len);
6934 __put_user(fl->l_pid, &target_fl->l_pid);
6935 unlock_user_struct(target_fl, target_flock_addr, 1);
6936 return 0;
6937}
6938#endif
6939
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006940static inline abi_long copy_from_user_flock64(struct flock *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006941 abi_ulong target_flock_addr)
6942{
6943 struct target_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006944 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006945
6946 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6947 return -TARGET_EFAULT;
6948 }
6949
6950 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006951 l_type = target_to_host_flock(l_type);
6952 if (l_type < 0) {
6953 return l_type;
6954 }
6955 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006956 __get_user(fl->l_whence, &target_fl->l_whence);
6957 __get_user(fl->l_start, &target_fl->l_start);
6958 __get_user(fl->l_len, &target_fl->l_len);
6959 __get_user(fl->l_pid, &target_fl->l_pid);
6960 unlock_user_struct(target_fl, target_flock_addr, 0);
6961 return 0;
6962}
6963
6964static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006965 const struct flock *fl)
Peter Maydell213d3e92016-06-13 11:22:05 +01006966{
6967 struct target_flock64 *target_fl;
6968 short l_type;
6969
6970 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6971 return -TARGET_EFAULT;
6972 }
6973
Laurent Vivierae68ad92018-05-10 01:11:21 +02006974 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006975 __put_user(l_type, &target_fl->l_type);
6976 __put_user(fl->l_whence, &target_fl->l_whence);
6977 __put_user(fl->l_start, &target_fl->l_start);
6978 __put_user(fl->l_len, &target_fl->l_len);
6979 __put_user(fl->l_pid, &target_fl->l_pid);
6980 unlock_user_struct(target_fl, target_flock_addr, 1);
6981 return 0;
6982}
6983
blueswir1992f48a2007-10-14 16:27:31 +00006984static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006985{
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006986 struct flock fl;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006987#ifdef F_GETOWN_EX
6988 struct f_owner_ex fox;
6989 struct target_f_owner_ex *target_fox;
6990#endif
blueswir1992f48a2007-10-14 16:27:31 +00006991 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006992 int host_cmd = target_to_host_fcntl_cmd(cmd);
6993
6994 if (host_cmd == -TARGET_EINVAL)
6995 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006996
bellard7775e9e2003-05-14 22:46:48 +00006997 switch(cmd) {
6998 case TARGET_F_GETLK:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03006999 ret = copy_from_user_flock(&fl, arg);
Peter Maydell213d3e92016-06-13 11:22:05 +01007000 if (ret) {
7001 return ret;
7002 }
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007003 ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00007004 if (ret == 0) {
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007005 ret = copy_to_user_flock(arg, &fl);
bellard7775e9e2003-05-14 22:46:48 +00007006 }
7007 break;
ths3b46e622007-09-17 08:09:54 +00007008
bellard7775e9e2003-05-14 22:46:48 +00007009 case TARGET_F_SETLK:
7010 case TARGET_F_SETLKW:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007011 ret = copy_from_user_flock(&fl, arg);
Peter Maydell213d3e92016-06-13 11:22:05 +01007012 if (ret) {
7013 return ret;
7014 }
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007015 ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00007016 break;
ths3b46e622007-09-17 08:09:54 +00007017
bellard7775e9e2003-05-14 22:46:48 +00007018 case TARGET_F_GETLK64:
Andreas Schwab2d92c682020-05-25 09:59:28 +02007019 case TARGET_F_OFD_GETLK:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007020 ret = copy_from_user_flock64(&fl, arg);
Peter Maydell213d3e92016-06-13 11:22:05 +01007021 if (ret) {
7022 return ret;
7023 }
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007024 ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
ths43f238d2007-01-05 20:55:49 +00007025 if (ret == 0) {
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007026 ret = copy_to_user_flock64(arg, &fl);
ths43f238d2007-01-05 20:55:49 +00007027 }
bellard9ee1fa22007-11-11 15:11:19 +00007028 break;
bellard7775e9e2003-05-14 22:46:48 +00007029 case TARGET_F_SETLK64:
7030 case TARGET_F_SETLKW64:
Andreas Schwab2d92c682020-05-25 09:59:28 +02007031 case TARGET_F_OFD_SETLK:
7032 case TARGET_F_OFD_SETLKW:
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007033 ret = copy_from_user_flock64(&fl, arg);
Peter Maydell213d3e92016-06-13 11:22:05 +01007034 if (ret) {
7035 return ret;
7036 }
Michael Tokarevac1bbe82024-08-29 09:39:50 +03007037 ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00007038 break;
7039
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007040 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01007041 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00007042 if (ret >= 0) {
7043 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
Helge Dellere0ddf8e2023-07-08 07:00:25 +02007044 /* tell 32-bit guests it uses largefile on 64-bit hosts: */
7045 if (O_LARGEFILE == 0 && HOST_LONG_BITS == 64) {
7046 ret |= TARGET_O_LARGEFILE;
7047 }
bellard9ee1fa22007-11-11 15:11:19 +00007048 }
bellardffa65c32004-01-04 23:57:22 +00007049 break;
7050
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007051 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01007052 ret = get_errno(safe_fcntl(fd, host_cmd,
7053 target_to_host_bitmask(arg,
7054 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007055 break;
7056
Andreas Schwab8d5d3002014-03-07 15:24:08 +01007057#ifdef F_GETOWN_EX
7058 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01007059 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01007060 if (ret >= 0) {
7061 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
7062 return -TARGET_EFAULT;
7063 target_fox->type = tswap32(fox.type);
7064 target_fox->pid = tswap32(fox.pid);
7065 unlock_user_struct(target_fox, arg, 1);
7066 }
7067 break;
7068#endif
7069
7070#ifdef F_SETOWN_EX
7071 case TARGET_F_SETOWN_EX:
7072 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
7073 return -TARGET_EFAULT;
7074 fox.type = tswap32(target_fox->type);
7075 fox.pid = tswap32(target_fox->pid);
7076 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01007077 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01007078 break;
7079#endif
7080
Timothy Baldwina7b4c9b2020-07-29 21:06:44 +01007081 case TARGET_F_SETSIG:
7082 ret = get_errno(safe_fcntl(fd, host_cmd, target_to_host_signal(arg)));
7083 break;
7084
7085 case TARGET_F_GETSIG:
7086 ret = host_to_target_signal(get_errno(safe_fcntl(fd, host_cmd, arg)));
7087 break;
7088
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02007089 case TARGET_F_SETOWN:
7090 case TARGET_F_GETOWN:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02007091 case TARGET_F_SETLEASE:
7092 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01007093 case TARGET_F_SETPIPE_SZ:
7094 case TARGET_F_GETPIPE_SZ:
Shu-Chun Weng2bb963f2020-12-18 11:32:10 -08007095 case TARGET_F_ADD_SEALS:
7096 case TARGET_F_GET_SEALS:
Peter Maydell435da5e2016-06-13 11:22:05 +01007097 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00007098 break;
7099
bellard7775e9e2003-05-14 22:46:48 +00007100 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01007101 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00007102 break;
7103 }
7104 return ret;
7105}
7106
bellard67867302003-11-23 17:05:30 +00007107#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00007108
bellard67867302003-11-23 17:05:30 +00007109static inline int high2lowuid(int uid)
7110{
7111 if (uid > 65535)
7112 return 65534;
7113 else
7114 return uid;
7115}
7116
7117static inline int high2lowgid(int gid)
7118{
7119 if (gid > 65535)
7120 return 65534;
7121 else
7122 return gid;
7123}
7124
7125static inline int low2highuid(int uid)
7126{
7127 if ((int16_t)uid == -1)
7128 return -1;
7129 else
7130 return uid;
7131}
7132
7133static inline int low2highgid(int gid)
7134{
7135 if ((int16_t)gid == -1)
7136 return -1;
7137 else
7138 return gid;
7139}
Riku Voipio0c866a72011-04-18 15:23:06 +03007140static inline int tswapid(int id)
7141{
7142 return tswap16(id);
7143}
Peter Maydell76ca3102014-03-02 19:36:41 +00007144
7145#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
7146
Riku Voipio0c866a72011-04-18 15:23:06 +03007147#else /* !USE_UID16 */
7148static inline int high2lowuid(int uid)
7149{
7150 return uid;
7151}
7152static inline int high2lowgid(int gid)
7153{
7154 return gid;
7155}
7156static inline int low2highuid(int uid)
7157{
7158 return uid;
7159}
7160static inline int low2highgid(int gid)
7161{
7162 return gid;
7163}
7164static inline int tswapid(int id)
7165{
7166 return tswap32(id);
7167}
Peter Maydell76ca3102014-03-02 19:36:41 +00007168
7169#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
7170
bellard67867302003-11-23 17:05:30 +00007171#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00007172
Peter Maydellfd6f7792016-03-01 16:33:02 +00007173/* We must do direct syscalls for setting UID/GID, because we want to
7174 * implement the Linux system call semantics of "change only for this thread",
7175 * not the libc/POSIX semantics of "change for all threads in process".
7176 * (See http://ewontfix.com/17/ for more details.)
7177 * We use the 32-bit version of the syscalls if present; if it is not
7178 * then either the host architecture supports 32-bit UIDs natively with
7179 * the standard syscall, or the 16-bit UID is the best we can do.
7180 */
7181#ifdef __NR_setuid32
7182#define __NR_sys_setuid __NR_setuid32
7183#else
7184#define __NR_sys_setuid __NR_setuid
7185#endif
7186#ifdef __NR_setgid32
7187#define __NR_sys_setgid __NR_setgid32
7188#else
7189#define __NR_sys_setgid __NR_setgid
7190#endif
7191#ifdef __NR_setresuid32
7192#define __NR_sys_setresuid __NR_setresuid32
7193#else
7194#define __NR_sys_setresuid __NR_setresuid
7195#endif
7196#ifdef __NR_setresgid32
7197#define __NR_sys_setresgid __NR_setresgid32
7198#else
7199#define __NR_sys_setresgid __NR_setresgid
7200#endif
Ilya Leoshkevich54b27922024-06-14 17:46:40 +02007201#ifdef __NR_setgroups32
7202#define __NR_sys_setgroups __NR_setgroups32
7203#else
7204#define __NR_sys_setgroups __NR_setgroups
7205#endif
Peter Maydellfd6f7792016-03-01 16:33:02 +00007206
7207_syscall1(int, sys_setuid, uid_t, uid)
7208_syscall1(int, sys_setgid, gid_t, gid)
7209_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
7210_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
Ilya Leoshkevich54b27922024-06-14 17:46:40 +02007211_syscall2(int, sys_setgroups, int, size, gid_t *, grouplist)
Peter Maydellfd6f7792016-03-01 16:33:02 +00007212
bellard31e31b82003-02-18 22:55:36 +00007213void syscall_init(void)
7214{
bellard2ab83ea2003-06-15 19:56:46 +00007215 IOCTLEntry *ie;
7216 const argtype *arg_type;
7217 int size;
7218
Alexander Graf8be656b2015-05-06 23:47:32 +02007219 thunk_init(STRUCT_MAX);
7220
Blue Swirl001faf32009-05-13 17:53:17 +00007221#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00007222#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00007223#include "syscall_types.h"
7224#undef STRUCT
7225#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00007226
7227 /* we patch the ioctl size if necessary. We rely on the fact that
7228 no ioctl has all the bits at '1' in the size field */
7229 ie = ioctl_entries;
7230 while (ie->target_cmd != 0) {
7231 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
7232 TARGET_IOC_SIZEMASK) {
7233 arg_type = ie->arg_type;
7234 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00007235 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00007236 ie->target_cmd);
7237 exit(1);
7238 }
7239 arg_type++;
7240 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00007241 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00007242 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
7243 (size << TARGET_IOC_SIZESHIFT);
7244 }
thsb92c47c2007-11-01 00:07:38 +00007245
bellard2ab83ea2003-06-15 19:56:46 +00007246 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00007247#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7248 (defined(__x86_64__) && defined(TARGET_X86_64))
7249 if (unlikely(ie->target_cmd != ie->host_cmd)) {
7250 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
7251 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00007252 }
7253#endif
7254 ie++;
7255 }
bellard31e31b82003-02-18 22:55:36 +00007256}
bellardc573ff62004-01-04 15:51:36 +00007257
pbrookce4defa2006-02-09 16:49:55 +00007258#ifdef TARGET_NR_truncate64
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02007259static inline abi_long target_truncate64(CPUArchState *cpu_env, const char *arg1,
blueswir1992f48a2007-10-14 16:27:31 +00007260 abi_long arg2,
7261 abi_long arg3,
7262 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007263{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007264 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007265 arg2 = arg3;
7266 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007267 }
Michael Tokarev99174ce2024-08-29 09:59:51 +03007268 return get_errno(truncate(arg1, target_offset64(arg2, arg3)));
pbrookce4defa2006-02-09 16:49:55 +00007269}
7270#endif
7271
7272#ifdef TARGET_NR_ftruncate64
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02007273static inline abi_long target_ftruncate64(CPUArchState *cpu_env, abi_long arg1,
blueswir1992f48a2007-10-14 16:27:31 +00007274 abi_long arg2,
7275 abi_long arg3,
7276 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007277{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007278 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007279 arg2 = arg3;
7280 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007281 }
Michael Tokarev99174ce2024-08-29 09:59:51 +03007282 return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
pbrookce4defa2006-02-09 16:49:55 +00007283}
7284#endif
7285
Alistair Francis859e8a82020-03-12 15:13:49 -07007286#if defined(TARGET_NR_timer_settime) || \
7287 (defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD))
Filip Bozuta2c86c902020-07-22 17:34:20 +02007288static inline abi_long target_to_host_itimerspec(struct itimerspec *host_its,
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007289 abi_ulong target_addr)
7290{
Filip Bozuta2c86c902020-07-22 17:34:20 +02007291 if (target_to_host_timespec(&host_its->it_interval, target_addr +
7292 offsetof(struct target_itimerspec,
7293 it_interval)) ||
7294 target_to_host_timespec(&host_its->it_value, target_addr +
7295 offsetof(struct target_itimerspec,
7296 it_value))) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007297 return -TARGET_EFAULT;
7298 }
7299
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007300 return 0;
7301}
Alistair Francis859e8a82020-03-12 15:13:49 -07007302#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007303
Filip Bozuta828cb3a2020-07-22 17:34:21 +02007304#if defined(TARGET_NR_timer_settime64) || \
7305 (defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD))
7306static inline abi_long target_to_host_itimerspec64(struct itimerspec *host_its,
7307 abi_ulong target_addr)
7308{
7309 if (target_to_host_timespec64(&host_its->it_interval, target_addr +
7310 offsetof(struct target__kernel_itimerspec,
7311 it_interval)) ||
7312 target_to_host_timespec64(&host_its->it_value, target_addr +
7313 offsetof(struct target__kernel_itimerspec,
7314 it_value))) {
7315 return -TARGET_EFAULT;
7316 }
7317
7318 return 0;
7319}
7320#endif
7321
Alistair Francis859e8a82020-03-12 15:13:49 -07007322#if ((defined(TARGET_NR_timerfd_gettime) || \
7323 defined(TARGET_NR_timerfd_settime)) && defined(CONFIG_TIMERFD)) || \
Filip Bozuta2c86c902020-07-22 17:34:20 +02007324 defined(TARGET_NR_timer_gettime) || defined(TARGET_NR_timer_settime)
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007325static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
Filip Bozuta2c86c902020-07-22 17:34:20 +02007326 struct itimerspec *host_its)
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007327{
Filip Bozuta2c86c902020-07-22 17:34:20 +02007328 if (host_to_target_timespec(target_addr + offsetof(struct target_itimerspec,
7329 it_interval),
7330 &host_its->it_interval) ||
7331 host_to_target_timespec(target_addr + offsetof(struct target_itimerspec,
7332 it_value),
7333 &host_its->it_value)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007334 return -TARGET_EFAULT;
7335 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007336 return 0;
7337}
Alistair Francis859e8a82020-03-12 15:13:49 -07007338#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007339
Filip Bozuta828cb3a2020-07-22 17:34:21 +02007340#if ((defined(TARGET_NR_timerfd_gettime64) || \
7341 defined(TARGET_NR_timerfd_settime64)) && defined(CONFIG_TIMERFD)) || \
7342 defined(TARGET_NR_timer_gettime64) || defined(TARGET_NR_timer_settime64)
7343static inline abi_long host_to_target_itimerspec64(abi_ulong target_addr,
7344 struct itimerspec *host_its)
7345{
7346 if (host_to_target_timespec64(target_addr +
7347 offsetof(struct target__kernel_itimerspec,
7348 it_interval),
7349 &host_its->it_interval) ||
7350 host_to_target_timespec64(target_addr +
7351 offsetof(struct target__kernel_itimerspec,
7352 it_value),
7353 &host_its->it_value)) {
7354 return -TARGET_EFAULT;
7355 }
7356 return 0;
7357}
7358#endif
7359
Alistair Francis859e8a82020-03-12 15:13:49 -07007360#if defined(TARGET_NR_adjtimex) || \
7361 (defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME))
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007362static inline abi_long target_to_host_timex(struct timex *host_tx,
7363 abi_long target_addr)
7364{
7365 struct target_timex *target_tx;
7366
7367 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7368 return -TARGET_EFAULT;
7369 }
7370
7371 __get_user(host_tx->modes, &target_tx->modes);
7372 __get_user(host_tx->offset, &target_tx->offset);
7373 __get_user(host_tx->freq, &target_tx->freq);
7374 __get_user(host_tx->maxerror, &target_tx->maxerror);
7375 __get_user(host_tx->esterror, &target_tx->esterror);
7376 __get_user(host_tx->status, &target_tx->status);
7377 __get_user(host_tx->constant, &target_tx->constant);
7378 __get_user(host_tx->precision, &target_tx->precision);
7379 __get_user(host_tx->tolerance, &target_tx->tolerance);
7380 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7381 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7382 __get_user(host_tx->tick, &target_tx->tick);
7383 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7384 __get_user(host_tx->jitter, &target_tx->jitter);
7385 __get_user(host_tx->shift, &target_tx->shift);
7386 __get_user(host_tx->stabil, &target_tx->stabil);
7387 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7388 __get_user(host_tx->calcnt, &target_tx->calcnt);
7389 __get_user(host_tx->errcnt, &target_tx->errcnt);
7390 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7391 __get_user(host_tx->tai, &target_tx->tai);
7392
7393 unlock_user_struct(target_tx, target_addr, 0);
7394 return 0;
7395}
7396
7397static inline abi_long host_to_target_timex(abi_long target_addr,
7398 struct timex *host_tx)
7399{
7400 struct target_timex *target_tx;
7401
7402 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7403 return -TARGET_EFAULT;
7404 }
7405
7406 __put_user(host_tx->modes, &target_tx->modes);
7407 __put_user(host_tx->offset, &target_tx->offset);
7408 __put_user(host_tx->freq, &target_tx->freq);
7409 __put_user(host_tx->maxerror, &target_tx->maxerror);
7410 __put_user(host_tx->esterror, &target_tx->esterror);
7411 __put_user(host_tx->status, &target_tx->status);
7412 __put_user(host_tx->constant, &target_tx->constant);
7413 __put_user(host_tx->precision, &target_tx->precision);
7414 __put_user(host_tx->tolerance, &target_tx->tolerance);
7415 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7416 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7417 __put_user(host_tx->tick, &target_tx->tick);
7418 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7419 __put_user(host_tx->jitter, &target_tx->jitter);
7420 __put_user(host_tx->shift, &target_tx->shift);
7421 __put_user(host_tx->stabil, &target_tx->stabil);
7422 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7423 __put_user(host_tx->calcnt, &target_tx->calcnt);
7424 __put_user(host_tx->errcnt, &target_tx->errcnt);
7425 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7426 __put_user(host_tx->tai, &target_tx->tai);
7427
7428 unlock_user_struct(target_tx, target_addr, 1);
7429 return 0;
7430}
Alistair Francis859e8a82020-03-12 15:13:49 -07007431#endif
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007432
Filip Bozuta6ac03b22020-08-24 21:21:15 +02007433
7434#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
7435static inline abi_long target_to_host_timex64(struct timex *host_tx,
7436 abi_long target_addr)
7437{
7438 struct target__kernel_timex *target_tx;
7439
7440 if (copy_from_user_timeval64(&host_tx->time, target_addr +
7441 offsetof(struct target__kernel_timex,
7442 time))) {
7443 return -TARGET_EFAULT;
7444 }
7445
7446 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7447 return -TARGET_EFAULT;
7448 }
7449
7450 __get_user(host_tx->modes, &target_tx->modes);
7451 __get_user(host_tx->offset, &target_tx->offset);
7452 __get_user(host_tx->freq, &target_tx->freq);
7453 __get_user(host_tx->maxerror, &target_tx->maxerror);
7454 __get_user(host_tx->esterror, &target_tx->esterror);
7455 __get_user(host_tx->status, &target_tx->status);
7456 __get_user(host_tx->constant, &target_tx->constant);
7457 __get_user(host_tx->precision, &target_tx->precision);
7458 __get_user(host_tx->tolerance, &target_tx->tolerance);
7459 __get_user(host_tx->tick, &target_tx->tick);
7460 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7461 __get_user(host_tx->jitter, &target_tx->jitter);
7462 __get_user(host_tx->shift, &target_tx->shift);
7463 __get_user(host_tx->stabil, &target_tx->stabil);
7464 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7465 __get_user(host_tx->calcnt, &target_tx->calcnt);
7466 __get_user(host_tx->errcnt, &target_tx->errcnt);
7467 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7468 __get_user(host_tx->tai, &target_tx->tai);
7469
7470 unlock_user_struct(target_tx, target_addr, 0);
7471 return 0;
7472}
7473
7474static inline abi_long host_to_target_timex64(abi_long target_addr,
7475 struct timex *host_tx)
7476{
7477 struct target__kernel_timex *target_tx;
7478
7479 if (copy_to_user_timeval64(target_addr +
7480 offsetof(struct target__kernel_timex, time),
7481 &host_tx->time)) {
7482 return -TARGET_EFAULT;
7483 }
7484
7485 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7486 return -TARGET_EFAULT;
7487 }
7488
7489 __put_user(host_tx->modes, &target_tx->modes);
7490 __put_user(host_tx->offset, &target_tx->offset);
7491 __put_user(host_tx->freq, &target_tx->freq);
7492 __put_user(host_tx->maxerror, &target_tx->maxerror);
7493 __put_user(host_tx->esterror, &target_tx->esterror);
7494 __put_user(host_tx->status, &target_tx->status);
7495 __put_user(host_tx->constant, &target_tx->constant);
7496 __put_user(host_tx->precision, &target_tx->precision);
7497 __put_user(host_tx->tolerance, &target_tx->tolerance);
7498 __put_user(host_tx->tick, &target_tx->tick);
7499 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7500 __put_user(host_tx->jitter, &target_tx->jitter);
7501 __put_user(host_tx->shift, &target_tx->shift);
7502 __put_user(host_tx->stabil, &target_tx->stabil);
7503 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7504 __put_user(host_tx->calcnt, &target_tx->calcnt);
7505 __put_user(host_tx->errcnt, &target_tx->errcnt);
7506 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7507 __put_user(host_tx->tai, &target_tx->tai);
7508
7509 unlock_user_struct(target_tx, target_addr, 1);
7510 return 0;
7511}
7512#endif
7513
Michael Forney96ff7582021-05-25 20:55:56 -07007514#ifndef HAVE_SIGEV_NOTIFY_THREAD_ID
7515#define sigev_notify_thread_id _sigev_un._tid
7516#endif
7517
Peter Maydellc0659762014-08-09 15:42:32 +01007518static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7519 abi_ulong target_addr)
7520{
7521 struct target_sigevent *target_sevp;
7522
7523 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7524 return -TARGET_EFAULT;
7525 }
7526
7527 /* This union is awkward on 64 bit systems because it has a 32 bit
7528 * integer and a pointer in it; we follow the conversion approach
7529 * used for handling sigval types in signal.c so the guest should get
7530 * the correct value back even if we did a 64 bit byteswap and it's
7531 * using the 32 bit integer.
7532 */
7533 host_sevp->sigev_value.sival_ptr =
7534 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7535 host_sevp->sigev_signo =
7536 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7537 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
Michael Forney96ff7582021-05-25 20:55:56 -07007538 host_sevp->sigev_notify_thread_id = tswap32(target_sevp->_sigev_un._tid);
Peter Maydellc0659762014-08-09 15:42:32 +01007539
7540 unlock_user_struct(target_sevp, target_addr, 1);
7541 return 0;
7542}
7543
Tom Musta6f6a4032014-08-12 13:53:42 -05007544#if defined(TARGET_NR_mlockall)
7545static inline int target_to_host_mlockall_arg(int arg)
7546{
7547 int result = 0;
7548
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007549 if (arg & TARGET_MCL_CURRENT) {
Tom Musta6f6a4032014-08-12 13:53:42 -05007550 result |= MCL_CURRENT;
7551 }
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007552 if (arg & TARGET_MCL_FUTURE) {
Tom Musta6f6a4032014-08-12 13:53:42 -05007553 result |= MCL_FUTURE;
7554 }
Filip Bozuta02e5d7d2020-08-11 18:45:51 +02007555#ifdef MCL_ONFAULT
7556 if (arg & TARGET_MCL_ONFAULT) {
7557 result |= MCL_ONFAULT;
7558 }
7559#endif
7560
Tom Musta6f6a4032014-08-12 13:53:42 -05007561 return result;
7562}
7563#endif
7564
Helge Dellerfe080592022-12-15 08:27:46 +01007565static inline int target_to_host_msync_arg(abi_long arg)
7566{
7567 return ((arg & TARGET_MS_ASYNC) ? MS_ASYNC : 0) |
7568 ((arg & TARGET_MS_INVALIDATE) ? MS_INVALIDATE : 0) |
7569 ((arg & TARGET_MS_SYNC) ? MS_SYNC : 0) |
7570 (arg & ~(TARGET_MS_ASYNC | TARGET_MS_INVALIDATE | TARGET_MS_SYNC));
7571}
7572
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007573#if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \
7574 defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \
7575 defined(TARGET_NR_newfstatat))
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02007576static inline abi_long host_to_target_stat64(CPUArchState *cpu_env,
balrog6a24a772008-09-20 02:23:36 +00007577 abi_ulong target_addr,
7578 struct stat *host_st)
7579{
Alexander Graf09701192013-09-03 20:12:15 +01007580#if defined(TARGET_ARM) && defined(TARGET_ABI32)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02007581 if (cpu_env->eabi) {
balrog6a24a772008-09-20 02:23:36 +00007582 struct target_eabi_stat64 *target_st;
7583
7584 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7585 return -TARGET_EFAULT;
7586 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7587 __put_user(host_st->st_dev, &target_st->st_dev);
7588 __put_user(host_st->st_ino, &target_st->st_ino);
7589#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7590 __put_user(host_st->st_ino, &target_st->__st_ino);
7591#endif
7592 __put_user(host_st->st_mode, &target_st->st_mode);
7593 __put_user(host_st->st_nlink, &target_st->st_nlink);
7594 __put_user(host_st->st_uid, &target_st->st_uid);
7595 __put_user(host_st->st_gid, &target_st->st_gid);
7596 __put_user(host_st->st_rdev, &target_st->st_rdev);
7597 __put_user(host_st->st_size, &target_st->st_size);
7598 __put_user(host_st->st_blksize, &target_st->st_blksize);
7599 __put_user(host_st->st_blocks, &target_st->st_blocks);
7600 __put_user(host_st->st_atime, &target_st->target_st_atime);
7601 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7602 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Michael Forneyfebf6fa2021-05-25 20:55:31 -07007603#ifdef HAVE_STRUCT_STAT_ST_ATIM
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08007604 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
7605 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
7606 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
7607#endif
balrog6a24a772008-09-20 02:23:36 +00007608 unlock_user_struct(target_st, target_addr, 1);
7609 } else
7610#endif
7611 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007612#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007613 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007614#else
7615 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007616#endif
balrog6a24a772008-09-20 02:23:36 +00007617
7618 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7619 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007620 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007621 __put_user(host_st->st_dev, &target_st->st_dev);
7622 __put_user(host_st->st_ino, &target_st->st_ino);
7623#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7624 __put_user(host_st->st_ino, &target_st->__st_ino);
7625#endif
7626 __put_user(host_st->st_mode, &target_st->st_mode);
7627 __put_user(host_st->st_nlink, &target_st->st_nlink);
7628 __put_user(host_st->st_uid, &target_st->st_uid);
7629 __put_user(host_st->st_gid, &target_st->st_gid);
7630 __put_user(host_st->st_rdev, &target_st->st_rdev);
7631 /* XXX: better use of kernel struct */
7632 __put_user(host_st->st_size, &target_st->st_size);
7633 __put_user(host_st->st_blksize, &target_st->st_blksize);
7634 __put_user(host_st->st_blocks, &target_st->st_blocks);
7635 __put_user(host_st->st_atime, &target_st->target_st_atime);
7636 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7637 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
Michael Forneyfebf6fa2021-05-25 20:55:31 -07007638#ifdef HAVE_STRUCT_STAT_ST_ATIM
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +08007639 __put_user(host_st->st_atim.tv_nsec, &target_st->target_st_atime_nsec);
7640 __put_user(host_st->st_mtim.tv_nsec, &target_st->target_st_mtime_nsec);
7641 __put_user(host_st->st_ctim.tv_nsec, &target_st->target_st_ctime_nsec);
7642#endif
balrog6a24a772008-09-20 02:23:36 +00007643 unlock_user_struct(target_st, target_addr, 1);
7644 }
7645
7646 return 0;
7647}
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007648#endif
balrog6a24a772008-09-20 02:23:36 +00007649
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007650#if defined(TARGET_NR_statx) && defined(__NR_statx)
7651static inline abi_long host_to_target_statx(struct target_statx *host_stx,
7652 abi_ulong target_addr)
7653{
7654 struct target_statx *target_stx;
7655
7656 if (!lock_user_struct(VERIFY_WRITE, target_stx, target_addr, 0)) {
7657 return -TARGET_EFAULT;
7658 }
7659 memset(target_stx, 0, sizeof(*target_stx));
7660
7661 __put_user(host_stx->stx_mask, &target_stx->stx_mask);
7662 __put_user(host_stx->stx_blksize, &target_stx->stx_blksize);
7663 __put_user(host_stx->stx_attributes, &target_stx->stx_attributes);
7664 __put_user(host_stx->stx_nlink, &target_stx->stx_nlink);
7665 __put_user(host_stx->stx_uid, &target_stx->stx_uid);
7666 __put_user(host_stx->stx_gid, &target_stx->stx_gid);
7667 __put_user(host_stx->stx_mode, &target_stx->stx_mode);
7668 __put_user(host_stx->stx_ino, &target_stx->stx_ino);
7669 __put_user(host_stx->stx_size, &target_stx->stx_size);
7670 __put_user(host_stx->stx_blocks, &target_stx->stx_blocks);
7671 __put_user(host_stx->stx_attributes_mask, &target_stx->stx_attributes_mask);
7672 __put_user(host_stx->stx_atime.tv_sec, &target_stx->stx_atime.tv_sec);
7673 __put_user(host_stx->stx_atime.tv_nsec, &target_stx->stx_atime.tv_nsec);
Ariadne Conilld1e26702019-11-22 11:40:40 -06007674 __put_user(host_stx->stx_btime.tv_sec, &target_stx->stx_btime.tv_sec);
7675 __put_user(host_stx->stx_btime.tv_nsec, &target_stx->stx_btime.tv_nsec);
7676 __put_user(host_stx->stx_ctime.tv_sec, &target_stx->stx_ctime.tv_sec);
7677 __put_user(host_stx->stx_ctime.tv_nsec, &target_stx->stx_ctime.tv_nsec);
7678 __put_user(host_stx->stx_mtime.tv_sec, &target_stx->stx_mtime.tv_sec);
7679 __put_user(host_stx->stx_mtime.tv_nsec, &target_stx->stx_mtime.tv_nsec);
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007680 __put_user(host_stx->stx_rdev_major, &target_stx->stx_rdev_major);
7681 __put_user(host_stx->stx_rdev_minor, &target_stx->stx_rdev_minor);
7682 __put_user(host_stx->stx_dev_major, &target_stx->stx_dev_major);
7683 __put_user(host_stx->stx_dev_minor, &target_stx->stx_dev_minor);
7684
7685 unlock_user_struct(target_stx, target_addr, 1);
7686
7687 return 0;
7688}
7689#endif
7690
Alistair Francis14690292020-03-18 15:47:01 -07007691static int do_sys_futex(int *uaddr, int op, int val,
7692 const struct timespec *timeout, int *uaddr2,
7693 int val3)
7694{
7695#if HOST_LONG_BITS == 64
7696#if defined(__NR_futex)
7697 /* always a 64-bit time_t, it doesn't define _time64 version */
7698 return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
7699
7700#endif
7701#else /* HOST_LONG_BITS == 64 */
7702#if defined(__NR_futex_time64)
7703 if (sizeof(timeout->tv_sec) == 8) {
7704 /* _time64 function on 32bit arch */
7705 return sys_futex_time64(uaddr, op, val, timeout, uaddr2, val3);
7706 }
7707#endif
7708#if defined(__NR_futex)
7709 /* old function on 32bit arch */
7710 return sys_futex(uaddr, op, val, timeout, uaddr2, val3);
7711#endif
7712#endif /* HOST_LONG_BITS == 64 */
7713 g_assert_not_reached();
7714}
7715
7716static int do_safe_futex(int *uaddr, int op, int val,
7717 const struct timespec *timeout, int *uaddr2,
7718 int val3)
7719{
7720#if HOST_LONG_BITS == 64
7721#if defined(__NR_futex)
7722 /* always a 64-bit time_t, it doesn't define _time64 version */
7723 return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
7724#endif
7725#else /* HOST_LONG_BITS == 64 */
7726#if defined(__NR_futex_time64)
7727 if (sizeof(timeout->tv_sec) == 8) {
7728 /* _time64 function on 32bit arch */
7729 return get_errno(safe_futex_time64(uaddr, op, val, timeout, uaddr2,
7730 val3));
7731 }
7732#endif
7733#if defined(__NR_futex)
7734 /* old function on 32bit arch */
7735 return get_errno(safe_futex(uaddr, op, val, timeout, uaddr2, val3));
7736#endif
7737#endif /* HOST_LONG_BITS == 64 */
7738 return -TARGET_ENOSYS;
7739}
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02007740
pbrookbd0c5662008-05-29 14:34:11 +00007741/* ??? Using host futex calls even when target atomic operations
7742 are not really atomic probably breaks things. However implementing
7743 futexes locally would make futexes shared between multiple processes
7744 tricky. However they're probably useless because guest atomic
7745 operations won't work either. */
Richard Henderson0fbc0f82022-08-28 19:09:59 -07007746#if defined(TARGET_NR_futex) || defined(TARGET_NR_futex_time64)
7747static int do_futex(CPUState *cpu, bool time64, target_ulong uaddr,
7748 int op, int val, target_ulong timeout,
7749 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007750{
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007751 struct timespec ts, *pts = NULL;
7752 void *haddr2 = NULL;
Nathan Froyda16aae02009-08-03 08:43:29 -07007753 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007754
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007755 /* We assume FUTEX_* constants are the same on both host and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007756#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007757 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007758#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007759 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007760#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007761 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007762 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007763 case FUTEX_WAIT_BITSET:
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007764 val = tswap32(val);
7765 break;
Richard Hendersonc72a90d2022-08-28 19:10:03 -07007766 case FUTEX_WAIT_REQUEUE_PI:
7767 val = tswap32(val);
7768 haddr2 = g2h(cpu, uaddr2);
7769 break;
7770 case FUTEX_LOCK_PI:
7771 case FUTEX_LOCK_PI2:
7772 break;
pbrookbd0c5662008-05-29 14:34:11 +00007773 case FUTEX_WAKE:
Richard Hendersona6180f82022-08-28 19:10:01 -07007774 case FUTEX_WAKE_BITSET:
Richard Hendersonc72a90d2022-08-28 19:10:03 -07007775 case FUTEX_TRYLOCK_PI:
7776 case FUTEX_UNLOCK_PI:
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007777 timeout = 0;
7778 break;
pbrookbd0c5662008-05-29 14:34:11 +00007779 case FUTEX_FD:
Richard Henderson0f946732022-08-28 19:10:02 -07007780 val = target_to_host_signal(val);
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007781 timeout = 0;
7782 break;
pbrookbd0c5662008-05-29 14:34:11 +00007783 case FUTEX_CMP_REQUEUE:
Richard Hendersonc72a90d2022-08-28 19:10:03 -07007784 case FUTEX_CMP_REQUEUE_PI:
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007785 val3 = tswap32(val3);
7786 /* fall through */
7787 case FUTEX_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007788 case FUTEX_WAKE_OP:
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007789 /*
7790 * For these, the 4th argument is not TIMEOUT, but VAL2.
7791 * But the prototype of do_safe_futex takes a pointer, so
7792 * insert casts to satisfy the compiler. We do not need
7793 * to tswap VAL2 since it's not compared to guest memory.
7794 */
7795 pts = (struct timespec *)(uintptr_t)timeout;
7796 timeout = 0;
7797 haddr2 = g2h(cpu, uaddr2);
7798 break;
pbrookbd0c5662008-05-29 14:34:11 +00007799 default:
7800 return -TARGET_ENOSYS;
7801 }
Richard Henderson57b9ccd2022-08-28 19:10:00 -07007802 if (timeout) {
7803 pts = &ts;
7804 if (time64
7805 ? target_to_host_timespec64(pts, timeout)
7806 : target_to_host_timespec(pts, timeout)) {
7807 return -TARGET_EFAULT;
7808 }
7809 }
7810 return do_safe_futex(g2h(cpu, uaddr), op, val, pts, haddr2, val3);
pbrookbd0c5662008-05-29 14:34:11 +00007811}
Alistair Francis859e8a82020-03-12 15:13:49 -07007812#endif
Alistair Francis14690292020-03-18 15:47:01 -07007813
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007814#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7815static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7816 abi_long handle, abi_long mount_id,
7817 abi_long flags)
7818{
7819 struct file_handle *target_fh;
7820 struct file_handle *fh;
7821 int mid = 0;
7822 abi_long ret;
7823 char *name;
7824 unsigned int size, total_size;
7825
7826 if (get_user_s32(size, handle)) {
7827 return -TARGET_EFAULT;
7828 }
7829
7830 name = lock_user_string(pathname);
7831 if (!name) {
7832 return -TARGET_EFAULT;
7833 }
7834
7835 total_size = sizeof(struct file_handle) + size;
7836 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7837 if (!target_fh) {
7838 unlock_user(name, pathname, 0);
7839 return -TARGET_EFAULT;
7840 }
7841
7842 fh = g_malloc0(total_size);
7843 fh->handle_bytes = size;
7844
7845 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7846 unlock_user(name, pathname, 0);
7847
7848 /* man name_to_handle_at(2):
7849 * Other than the use of the handle_bytes field, the caller should treat
7850 * the file_handle structure as an opaque data type
7851 */
7852
7853 memcpy(target_fh, fh, total_size);
7854 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7855 target_fh->handle_type = tswap32(fh->handle_type);
7856 g_free(fh);
7857 unlock_user(target_fh, handle, total_size);
7858
7859 if (put_user_s32(mid, mount_id)) {
7860 return -TARGET_EFAULT;
7861 }
7862
7863 return ret;
7864
7865}
7866#endif
7867
7868#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7869static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7870 abi_long flags)
7871{
7872 struct file_handle *target_fh;
7873 struct file_handle *fh;
7874 unsigned int size, total_size;
7875 abi_long ret;
7876
7877 if (get_user_s32(size, handle)) {
7878 return -TARGET_EFAULT;
7879 }
7880
7881 total_size = sizeof(struct file_handle) + size;
7882 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7883 if (!target_fh) {
7884 return -TARGET_EFAULT;
7885 }
7886
Thomas Huthe9d49d52015-10-09 17:56:38 +02007887 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007888 fh->handle_bytes = size;
7889 fh->handle_type = tswap32(target_fh->handle_type);
7890
7891 ret = get_errno(open_by_handle_at(mount_fd, fh,
7892 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7893
7894 g_free(fh);
7895
7896 unlock_user(target_fh, handle, total_size);
7897
7898 return ret;
7899}
7900#endif
pbrookbd0c5662008-05-29 14:34:11 +00007901
Laurent Viviere36800c2015-10-02 14:48:09 +02007902#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7903
Laurent Viviere36800c2015-10-02 14:48:09 +02007904static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7905{
7906 int host_flags;
7907 target_sigset_t *target_mask;
7908 sigset_t host_mask;
7909 abi_long ret;
7910
Helge Deller78721302021-02-10 07:12:14 +01007911 if (flags & ~(TARGET_O_NONBLOCK_MASK | TARGET_O_CLOEXEC)) {
Laurent Viviere36800c2015-10-02 14:48:09 +02007912 return -TARGET_EINVAL;
7913 }
7914 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7915 return -TARGET_EFAULT;
7916 }
7917
7918 target_to_host_sigset(&host_mask, target_mask);
7919
7920 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7921
7922 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7923 if (ret >= 0) {
7924 fd_trans_register(ret, &target_signalfd_trans);
7925 }
7926
7927 unlock_user_struct(target_mask, mask, 0);
7928
7929 return ret;
7930}
7931#endif
7932
pbrook1d9d8b52009-04-16 15:17:02 +00007933/* Map host to target signal numbers for the wait family of syscalls.
7934 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007935int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007936{
7937 if (WIFSIGNALED(status)) {
7938 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7939 }
7940 if (WIFSTOPPED(status)) {
7941 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7942 | (status & 0xff);
7943 }
7944 return status;
7945}
7946
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02007947static int open_self_cmdline(CPUArchState *cpu_env, int fd)
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007948{
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02007949 CPUState *cpu = env_cpu(cpu_env);
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00007950 struct linux_binprm *bprm = get_task_state(cpu)->bprm;
Andreas Schwab58de8b92017-03-20 12:31:55 +01007951 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007952
Andreas Schwab58de8b92017-03-20 12:31:55 +01007953 for (i = 0; i < bprm->argc; i++) {
7954 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007955
Andreas Schwab58de8b92017-03-20 12:31:55 +01007956 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007957 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007958 }
7959 }
7960
Andreas Schwab58de8b92017-03-20 12:31:55 +01007961 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007962}
7963
Richard Henderson7b7a3362023-08-08 20:02:19 -07007964struct open_self_maps_data {
7965 TaskState *ts;
7966 IntervalTreeRoot *host_maps;
7967 int fd;
7968 bool smaps;
7969};
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01007970
Richard Henderson7b7a3362023-08-08 20:02:19 -07007971/*
7972 * Subroutine to output one line of /proc/self/maps,
7973 * or one region of /proc/self/smaps.
7974 */
7975
7976#ifdef TARGET_HPPA
7977# define test_stack(S, E, L) (E == L)
7978#else
7979# define test_stack(S, E, L) (S == L)
7980#endif
7981
7982static void open_self_maps_4(const struct open_self_maps_data *d,
7983 const MapInfo *mi, abi_ptr start,
7984 abi_ptr end, unsigned flags)
7985{
7986 const struct image_info *info = d->ts->info;
7987 const char *path = mi->path;
7988 uint64_t offset;
7989 int fd = d->fd;
7990 int count;
7991
7992 if (test_stack(start, end, info->stack_limit)) {
7993 path = "[stack]";
Richard Henderson92d2a032023-08-16 10:33:28 -07007994 } else if (start == info->brk) {
7995 path = "[heap]";
Richard Henderson5d94c2f2023-08-16 10:54:57 -07007996 } else if (start == info->vdso) {
7997 path = "[vdso]";
Richard Henderson4ef1f552024-02-24 02:29:41 +00007998#ifdef TARGET_X86_64
7999 } else if (start == TARGET_VSYSCALL_PAGE) {
8000 path = "[vsyscall]";
8001#endif
Richard Henderson7b7a3362023-08-08 20:02:19 -07008002 }
8003
8004 /* Except null device (MAP_ANON), adjust offset for this fragment. */
8005 offset = mi->offset;
8006 if (mi->dev) {
8007 uintptr_t hstart = (uintptr_t)g2h_untagged(start);
8008 offset += hstart - mi->itree.start;
8009 }
8010
8011 count = dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
8012 " %c%c%c%c %08" PRIx64 " %02x:%02x %"PRId64,
8013 start, end,
8014 (flags & PAGE_READ) ? 'r' : '-',
8015 (flags & PAGE_WRITE_ORG) ? 'w' : '-',
8016 (flags & PAGE_EXEC) ? 'x' : '-',
8017 mi->is_priv ? 'p' : 's',
8018 offset, major(mi->dev), minor(mi->dev),
8019 (uint64_t)mi->inode);
8020 if (path) {
8021 dprintf(fd, "%*s%s\n", 73 - count, "", path);
8022 } else {
8023 dprintf(fd, "\n");
8024 }
8025
8026 if (d->smaps) {
8027 unsigned long size = end - start;
8028 unsigned long page_size_kb = TARGET_PAGE_SIZE >> 10;
8029 unsigned long size_kb = size >> 10;
8030
8031 dprintf(fd, "Size: %lu kB\n"
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008032 "KernelPageSize: %lu kB\n"
8033 "MMUPageSize: %lu kB\n"
8034 "Rss: 0 kB\n"
8035 "Pss: 0 kB\n"
8036 "Pss_Dirty: 0 kB\n"
8037 "Shared_Clean: 0 kB\n"
8038 "Shared_Dirty: 0 kB\n"
8039 "Private_Clean: 0 kB\n"
8040 "Private_Dirty: 0 kB\n"
8041 "Referenced: 0 kB\n"
Ilya Leoshkevich6467d9e2023-08-23 17:55:33 -07008042 "Anonymous: %lu kB\n"
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008043 "LazyFree: 0 kB\n"
8044 "AnonHugePages: 0 kB\n"
8045 "ShmemPmdMapped: 0 kB\n"
8046 "FilePmdMapped: 0 kB\n"
8047 "Shared_Hugetlb: 0 kB\n"
8048 "Private_Hugetlb: 0 kB\n"
8049 "Swap: 0 kB\n"
8050 "SwapPss: 0 kB\n"
8051 "Locked: 0 kB\n"
Richard Henderson7b7a3362023-08-08 20:02:19 -07008052 "THPeligible: 0\n"
8053 "VmFlags:%s%s%s%s%s%s%s%s\n",
8054 size_kb, page_size_kb, page_size_kb,
Ilya Leoshkevich6467d9e2023-08-23 17:55:33 -07008055 (flags & PAGE_ANON ? size_kb : 0),
Richard Henderson7b7a3362023-08-08 20:02:19 -07008056 (flags & PAGE_READ) ? " rd" : "",
8057 (flags & PAGE_WRITE_ORG) ? " wr" : "",
8058 (flags & PAGE_EXEC) ? " ex" : "",
8059 mi->is_priv ? "" : " sh",
8060 (flags & PAGE_READ) ? " mr" : "",
8061 (flags & PAGE_WRITE_ORG) ? " mw" : "",
8062 (flags & PAGE_EXEC) ? " me" : "",
8063 mi->is_priv ? "" : " ms");
8064 }
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008065}
8066
Richard Henderson7b7a3362023-08-08 20:02:19 -07008067/*
8068 * Callback for walk_memory_regions, when read_self_maps() fails.
8069 * Proceed without the benefit of host /proc/self/maps cross-check.
8070 */
8071static int open_self_maps_3(void *opaque, target_ulong guest_start,
8072 target_ulong guest_end, unsigned long flags)
Alexander Graf36c08d42011-11-02 20:23:24 +01008073{
Richard Henderson7b7a3362023-08-08 20:02:19 -07008074 static const MapInfo mi = { .is_priv = true };
Alexander Graf36c08d42011-11-02 20:23:24 +01008075
Richard Henderson7b7a3362023-08-08 20:02:19 -07008076 open_self_maps_4(opaque, &mi, guest_start, guest_end, flags);
8077 return 0;
8078}
Alexander Graf1a49ef22012-05-01 16:30:28 +01008079
Richard Henderson7b7a3362023-08-08 20:02:19 -07008080/*
8081 * Callback for walk_memory_regions, when read_self_maps() succeeds.
8082 */
8083static int open_self_maps_2(void *opaque, target_ulong guest_start,
8084 target_ulong guest_end, unsigned long flags)
8085{
8086 const struct open_self_maps_data *d = opaque;
8087 uintptr_t host_start = (uintptr_t)g2h_untagged(guest_start);
8088 uintptr_t host_last = (uintptr_t)g2h_untagged(guest_end - 1);
Alex Bennée01ef6b92020-04-03 20:11:46 +01008089
Richard Henderson4ef1f552024-02-24 02:29:41 +00008090#ifdef TARGET_X86_64
8091 /*
8092 * Because of the extremely high position of the page within the guest
8093 * virtual address space, this is not backed by host memory at all.
8094 * Therefore the loop below would fail. This is the only instance
8095 * of not having host backing memory.
8096 */
8097 if (guest_start == TARGET_VSYSCALL_PAGE) {
8098 return open_self_maps_3(opaque, guest_start, guest_end, flags);
8099 }
8100#endif
8101
Richard Henderson7b7a3362023-08-08 20:02:19 -07008102 while (1) {
8103 IntervalTreeNode *n =
8104 interval_tree_iter_first(d->host_maps, host_start, host_start);
8105 MapInfo *mi = container_of(n, MapInfo, itree);
8106 uintptr_t this_hlast = MIN(host_last, n->last);
8107 target_ulong this_gend = h2g(this_hlast) + 1;
Alex Bennée01ef6b92020-04-03 20:11:46 +01008108
Richard Henderson7b7a3362023-08-08 20:02:19 -07008109 open_self_maps_4(d, mi, guest_start, this_gend, flags);
Alex Bennée01ef6b92020-04-03 20:11:46 +01008110
Richard Henderson7b7a3362023-08-08 20:02:19 -07008111 if (this_hlast == host_last) {
8112 return 0;
Alexander Graf1a49ef22012-05-01 16:30:28 +01008113 }
Richard Henderson7b7a3362023-08-08 20:02:19 -07008114 host_start = this_hlast + 1;
8115 guest_start = h2g(host_start);
Alexander Graf1a49ef22012-05-01 16:30:28 +01008116 }
Richard Henderson7b7a3362023-08-08 20:02:19 -07008117}
Alexander Graf1a49ef22012-05-01 16:30:28 +01008118
Richard Henderson7b7a3362023-08-08 20:02:19 -07008119static int open_self_maps_1(CPUArchState *env, int fd, bool smaps)
8120{
8121 struct open_self_maps_data d = {
Philippe Mathieu-Daudé59272462024-04-25 11:12:19 +02008122 .ts = get_task_state(env_cpu(env)),
Richard Henderson7b7a3362023-08-08 20:02:19 -07008123 .host_maps = read_self_maps(),
8124 .fd = fd,
8125 .smaps = smaps
8126 };
Alex Bennée01ef6b92020-04-03 20:11:46 +01008127
Richard Henderson7b7a3362023-08-08 20:02:19 -07008128 if (d.host_maps) {
8129 walk_memory_regions(&d, open_self_maps_2);
8130 free_self_maps(d.host_maps);
8131 } else {
8132 walk_memory_regions(&d, open_self_maps_3);
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008133 }
Alexander Graf36c08d42011-11-02 20:23:24 +01008134 return 0;
8135}
8136
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008137static int open_self_maps(CPUArchState *cpu_env, int fd)
8138{
8139 return open_self_maps_1(cpu_env, fd, false);
8140}
8141
8142static int open_self_smaps(CPUArchState *cpu_env, int fd)
8143{
8144 return open_self_maps_1(cpu_env, fd, true);
8145}
8146
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02008147static int open_self_stat(CPUArchState *cpu_env, int fd)
Alexander Graf480b8e72011-11-02 20:23:25 +01008148{
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02008149 CPUState *cpu = env_cpu(cpu_env);
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00008150 TaskState *ts = get_task_state(cpu);
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01008151 g_autoptr(GString) buf = g_string_new(NULL);
Alexander Graf480b8e72011-11-02 20:23:25 +01008152 int i;
8153
8154 for (i = 0; i < 44; i++) {
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01008155 if (i == 0) {
8156 /* pid */
8157 g_string_printf(buf, FMT_pid " ", getpid());
8158 } else if (i == 1) {
8159 /* app name */
8160 gchar *bin = g_strrstr(ts->bprm->argv[0], "/");
8161 bin = bin ? bin + 1 : ts->bprm->argv[0];
8162 g_string_printf(buf, "(%.15s) ", bin);
Andreas Schwab25bb27c2023-03-06 10:59:29 +01008163 } else if (i == 2) {
8164 /* task state */
8165 g_string_assign(buf, "R "); /* we are running right now */
Andreas Schwab7aa9fe32021-06-21 11:32:59 +02008166 } else if (i == 3) {
8167 /* ppid */
8168 g_string_printf(buf, FMT_pid " ", getppid());
Fabio D'Ursod9b019e2024-06-19 21:41:09 +02008169 } else if (i == 19) {
8170 /* num_threads */
8171 int cpus = 0;
8172 WITH_RCU_READ_LOCK_GUARD() {
8173 CPUState *cpu_iter;
8174 CPU_FOREACH(cpu_iter) {
8175 cpus++;
8176 }
8177 }
8178 g_string_printf(buf, "%d ", cpus);
Cameron Esfahanieb33cda2022-01-27 16:12:51 -08008179 } else if (i == 21) {
8180 /* starttime */
8181 g_string_printf(buf, "%" PRIu64 " ", ts->start_boottime);
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01008182 } else if (i == 27) {
8183 /* stack bottom */
8184 g_string_printf(buf, TARGET_ABI_FMT_ld " ", ts->info->start_stack);
8185 } else {
8186 /* for the rest, there is MasterCard */
8187 g_string_printf(buf, "0%c", i == 43 ? '\n' : ' ');
8188 }
Alexander Graf480b8e72011-11-02 20:23:25 +01008189
Alex Bennée7ad4d5a2020-04-14 21:06:23 +01008190 if (write(fd, buf->str, buf->len) != buf->len) {
8191 return -1;
8192 }
Alexander Graf480b8e72011-11-02 20:23:25 +01008193 }
8194
8195 return 0;
8196}
8197
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02008198static int open_self_auxv(CPUArchState *cpu_env, int fd)
Alexander Graf257450e2011-11-02 20:23:26 +01008199{
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02008200 CPUState *cpu = env_cpu(cpu_env);
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00008201 TaskState *ts = get_task_state(cpu);
Alexander Graf257450e2011-11-02 20:23:26 +01008202 abi_ulong auxv = ts->info->saved_auxv;
8203 abi_ulong len = ts->info->auxv_len;
8204 char *ptr;
8205
8206 /*
8207 * Auxiliary vector is stored in target process stack.
8208 * read in whole auxv vector and copy it to file
8209 */
8210 ptr = lock_user(VERIFY_READ, auxv, len, 0);
8211 if (ptr != NULL) {
8212 while (len > 0) {
8213 ssize_t r;
8214 r = write(fd, ptr, len);
8215 if (r <= 0) {
8216 break;
8217 }
8218 len -= r;
8219 ptr += r;
8220 }
8221 lseek(fd, 0, SEEK_SET);
8222 unlock_user(ptr, auxv, len);
8223 }
8224
8225 return 0;
8226}
8227
Andreas Schwab463d8e72013-07-02 14:04:12 +01008228static int is_proc_myself(const char *filename, const char *entry)
8229{
8230 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
8231 filename += strlen("/proc/");
8232 if (!strncmp(filename, "self/", strlen("self/"))) {
8233 filename += strlen("self/");
8234 } else if (*filename >= '1' && *filename <= '9') {
8235 char myself[80];
8236 snprintf(myself, sizeof(myself), "%d/", getpid());
8237 if (!strncmp(filename, myself, strlen(myself))) {
8238 filename += strlen(myself);
8239 } else {
8240 return 0;
8241 }
8242 } else {
8243 return 0;
8244 }
8245 if (!strcmp(filename, entry)) {
8246 return 1;
8247 }
8248 }
8249 return 0;
8250}
8251
Helge Dellerbd5ccd62022-10-24 22:18:09 +02008252static void excp_dump_file(FILE *logfile, CPUArchState *env,
8253 const char *fmt, int code)
8254{
8255 if (logfile) {
8256 CPUState *cs = env_cpu(env);
8257
8258 fprintf(logfile, fmt, code);
8259 fprintf(logfile, "Failing executable: %s\n", exec_path);
8260 cpu_dump_state(cs, logfile, 0);
8261 open_self_maps(env, fileno(logfile));
8262 }
8263}
8264
8265void target_exception_dump(CPUArchState *env, const char *fmt, int code)
8266{
8267 /* dump to console */
8268 excp_dump_file(stderr, env, fmt, code);
8269
8270 /* dump to log file */
8271 if (qemu_log_separate()) {
8272 FILE *logfile = qemu_log_trylock();
8273
8274 excp_dump_file(logfile, env, fmt, code);
8275 qemu_log_unlock(logfile);
8276 }
8277}
8278
Richard Henderson121c8dd2023-08-23 17:13:14 -07008279#include "target_proc.h"
8280
Marc-André Lureauee3eb3a2022-03-23 19:57:18 +04008281#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN || \
Richard Henderson121c8dd2023-08-23 17:13:14 -07008282 defined(HAVE_ARCH_PROC_CPUINFO) || \
8283 defined(HAVE_ARCH_PROC_HARDWARE)
Laurent Vivierde6b9932013-08-30 01:46:40 +02008284static int is_proc(const char *filename, const char *entry)
8285{
8286 return strcmp(filename, entry) == 0;
8287}
Laurent Vivierfff69382019-05-17 15:31:48 +02008288#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02008289
Marc-André Lureauee3eb3a2022-03-23 19:57:18 +04008290#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02008291static int open_net_route(CPUArchState *cpu_env, int fd)
Laurent Vivierde6b9932013-08-30 01:46:40 +02008292{
8293 FILE *fp;
8294 char *line = NULL;
8295 size_t len = 0;
8296 ssize_t read;
8297
8298 fp = fopen("/proc/net/route", "r");
8299 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01008300 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02008301 }
8302
8303 /* read header */
8304
8305 read = getline(&line, &len, fp);
8306 dprintf(fd, "%s", line);
8307
8308 /* read routes */
8309
8310 while ((read = getline(&line, &len, fp)) != -1) {
8311 char iface[16];
8312 uint32_t dest, gw, mask;
8313 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
Peter Maydell9d0bd0c2019-02-05 17:42:07 +00008314 int fields;
8315
8316 fields = sscanf(line,
8317 "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
8318 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
8319 &mask, &mtu, &window, &irtt);
8320 if (fields != 11) {
8321 continue;
8322 }
Laurent Vivierde6b9932013-08-30 01:46:40 +02008323 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
8324 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
8325 metric, tswap32(mask), mtu, window, irtt);
8326 }
8327
8328 free(line);
8329 fclose(fp);
8330
8331 return 0;
8332}
8333#endif
8334
Helge Dellerb8002052023-08-03 23:44:47 +02008335int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
Ilya Leoshkevich35be8982023-06-30 19:04:17 +01008336 int flags, mode_t mode, bool safe)
Alexander Graf3be14d02011-11-02 20:23:23 +01008337{
Helge Dellerb8002052023-08-03 23:44:47 +02008338 g_autofree char *proc_name = NULL;
8339 const char *pathname;
Alexander Graf3be14d02011-11-02 20:23:23 +01008340 struct fake_open {
8341 const char *filename;
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02008342 int (*fill)(CPUArchState *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02008343 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01008344 };
8345 const struct fake_open *fake_open;
8346 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02008347 { "maps", open_self_maps, is_proc_myself },
Ilya Leoshkevich77ae5762023-06-30 19:04:18 +01008348 { "smaps", open_self_smaps, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02008349 { "stat", open_self_stat, is_proc_myself },
8350 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02008351 { "cmdline", open_self_cmdline, is_proc_myself },
Marc-André Lureauee3eb3a2022-03-23 19:57:18 +04008352#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
Laurent Vivierde6b9932013-08-30 01:46:40 +02008353 { "/proc/net/route", open_net_route, is_proc },
8354#endif
Richard Henderson121c8dd2023-08-23 17:13:14 -07008355#if defined(HAVE_ARCH_PROC_CPUINFO)
Laurent Vivierfff69382019-05-17 15:31:48 +02008356 { "/proc/cpuinfo", open_cpuinfo, is_proc },
8357#endif
Richard Henderson121c8dd2023-08-23 17:13:14 -07008358#if defined(HAVE_ARCH_PROC_HARDWARE)
Laurent Vivier4ab67132019-05-17 15:31:49 +02008359 { "/proc/hardware", open_hardware, is_proc },
8360#endif
Laurent Vivierde6b9932013-08-30 01:46:40 +02008361 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01008362 };
8363
Helge Dellerb8002052023-08-03 23:44:47 +02008364 /* if this is a file from /proc/ filesystem, expand full name */
8365 proc_name = realpath(fname, NULL);
8366 if (proc_name && strncmp(proc_name, "/proc/", 6) == 0) {
8367 pathname = proc_name;
8368 } else {
8369 pathname = fname;
8370 }
8371
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03008372 if (is_proc_myself(pathname, "exe")) {
Ilya Leoshkevich35be8982023-06-30 19:04:17 +01008373 if (safe) {
8374 return safe_openat(dirfd, exec_path, flags, mode);
8375 } else {
8376 return openat(dirfd, exec_path, flags, mode);
8377 }
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03008378 }
8379
Alexander Graf3be14d02011-11-02 20:23:23 +01008380 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02008381 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01008382 break;
8383 }
8384 }
8385
8386 if (fake_open->filename) {
8387 const char *tmpdir;
8388 char filename[PATH_MAX];
8389 int fd, r;
8390
Rainer Müller5b63de62022-07-29 17:49:51 +02008391 fd = memfd_create("qemu-open", 0);
Alexander Graf3be14d02011-11-02 20:23:23 +01008392 if (fd < 0) {
Rainer Müller5b63de62022-07-29 17:49:51 +02008393 if (errno != ENOSYS) {
8394 return fd;
8395 }
8396 /* create temporary file to map stat to */
8397 tmpdir = getenv("TMPDIR");
8398 if (!tmpdir)
8399 tmpdir = "/tmp";
8400 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
8401 fd = mkstemp(filename);
8402 if (fd < 0) {
8403 return fd;
8404 }
8405 unlink(filename);
Alexander Graf3be14d02011-11-02 20:23:23 +01008406 }
Alexander Graf3be14d02011-11-02 20:23:23 +01008407
8408 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01008409 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01008410 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01008411 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01008412 return r;
8413 }
8414 lseek(fd, 0, SEEK_SET);
8415
8416 return fd;
8417 }
8418
Ilya Leoshkevich35be8982023-06-30 19:04:17 +01008419 if (safe) {
8420 return safe_openat(dirfd, path(pathname), flags, mode);
8421 } else {
8422 return openat(dirfd, path(pathname), flags, mode);
8423 }
Alexander Graf3be14d02011-11-02 20:23:23 +01008424}
8425
Ilya Leoshkevicha4dab0a2023-06-30 19:04:16 +01008426ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
8427{
8428 ssize_t ret;
8429
8430 if (!pathname || !buf) {
8431 errno = EFAULT;
8432 return -1;
8433 }
8434
8435 if (!bufsiz) {
8436 /* Short circuit this for the magic exe check. */
8437 errno = EINVAL;
8438 return -1;
8439 }
8440
8441 if (is_proc_myself((const char *)pathname, "exe")) {
8442 /*
8443 * Don't worry about sign mismatch as earlier mapping
8444 * logic would have thrown a bad address error.
8445 */
8446 ret = MIN(strlen(exec_path), bufsiz);
8447 /* We cannot NUL terminate the string. */
8448 memcpy(buf, exec_path, ret);
8449 } else {
8450 ret = readlink(path(pathname), buf, bufsiz);
8451 }
8452
8453 return ret;
8454}
8455
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02008456static int do_execv(CPUArchState *cpu_env, int dirfd,
8457 abi_long pathname, abi_long guest_argp,
8458 abi_long guest_envp, int flags, bool is_execveat)
Drew DeVault156e1f62022-11-04 18:36:31 +01008459{
8460 int ret;
8461 char **argp, **envp;
8462 int argc, envc;
8463 abi_ulong gp;
8464 abi_ulong addr;
8465 char **q;
8466 void *p;
8467
8468 argc = 0;
8469
8470 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
8471 if (get_user_ual(addr, gp)) {
8472 return -TARGET_EFAULT;
8473 }
8474 if (!addr) {
8475 break;
8476 }
8477 argc++;
8478 }
8479 envc = 0;
8480 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
8481 if (get_user_ual(addr, gp)) {
8482 return -TARGET_EFAULT;
8483 }
8484 if (!addr) {
8485 break;
8486 }
8487 envc++;
8488 }
8489
8490 argp = g_new0(char *, argc + 1);
8491 envp = g_new0(char *, envc + 1);
8492
8493 for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
8494 if (get_user_ual(addr, gp)) {
8495 goto execve_efault;
8496 }
8497 if (!addr) {
8498 break;
8499 }
8500 *q = lock_user_string(addr);
8501 if (!*q) {
8502 goto execve_efault;
8503 }
8504 }
8505 *q = NULL;
8506
8507 for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
8508 if (get_user_ual(addr, gp)) {
8509 goto execve_efault;
8510 }
8511 if (!addr) {
8512 break;
8513 }
8514 *q = lock_user_string(addr);
8515 if (!*q) {
8516 goto execve_efault;
8517 }
8518 }
8519 *q = NULL;
8520
8521 /*
8522 * Although execve() is not an interruptible syscall it is
8523 * a special case where we must use the safe_syscall wrapper:
8524 * if we allow a signal to happen before we make the host
8525 * syscall then we will 'lose' it, because at the point of
8526 * execve the process leaves QEMU's control. So we use the
8527 * safe syscall wrapper to ensure that we either take the
8528 * signal as a guest signal, or else it does not happen
8529 * before the execve completes and makes it the other
8530 * program's problem.
8531 */
8532 p = lock_user_string(pathname);
8533 if (!p) {
8534 goto execve_efault;
8535 }
8536
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02008537 const char *exe = p;
Drew DeVault156e1f62022-11-04 18:36:31 +01008538 if (is_proc_myself(p, "exe")) {
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02008539 exe = exec_path;
Drew DeVault156e1f62022-11-04 18:36:31 +01008540 }
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02008541 ret = is_execveat
8542 ? safe_execveat(dirfd, exe, argp, envp, flags)
8543 : safe_execve(exe, argp, envp);
8544 ret = get_errno(ret);
Drew DeVault156e1f62022-11-04 18:36:31 +01008545
8546 unlock_user(p, pathname, 0);
8547
8548 goto execve_end;
8549
8550execve_efault:
8551 ret = -TARGET_EFAULT;
8552
8553execve_end:
8554 for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
8555 if (get_user_ual(addr, gp) || !addr) {
8556 break;
8557 }
8558 unlock_user(*q, addr, 0);
8559 }
8560 for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
8561 if (get_user_ual(addr, gp) || !addr) {
8562 break;
8563 }
8564 unlock_user(*q, addr, 0);
8565 }
8566
8567 g_free(argp);
8568 g_free(envp);
8569 return ret;
8570}
8571
Alexander Grafaecc8862014-11-10 21:33:03 +01008572#define TIMER_MAGIC 0x0caf0000
8573#define TIMER_MAGIC_MASK 0xffff0000
8574
8575/* Convert QEMU provided timer ID back to internal 16bit index format */
8576static target_timer_t get_timer_id(abi_long arg)
8577{
8578 target_timer_t timerid = arg;
8579
8580 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
8581 return -TARGET_EINVAL;
8582 }
8583
8584 timerid &= 0xffff;
8585
8586 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
8587 return -TARGET_EINVAL;
8588 }
8589
8590 return timerid;
8591}
8592
Samuel Thibault2e0a8712018-01-09 21:16:43 +01008593static int target_to_host_cpu_mask(unsigned long *host_mask,
8594 size_t host_size,
8595 abi_ulong target_addr,
8596 size_t target_size)
8597{
8598 unsigned target_bits = sizeof(abi_ulong) * 8;
8599 unsigned host_bits = sizeof(*host_mask) * 8;
8600 abi_ulong *target_mask;
8601 unsigned i, j;
8602
8603 assert(host_size >= target_size);
8604
8605 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
8606 if (!target_mask) {
8607 return -TARGET_EFAULT;
8608 }
8609 memset(host_mask, 0, host_size);
8610
8611 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
8612 unsigned bit = i * target_bits;
8613 abi_ulong val;
8614
8615 __get_user(val, &target_mask[i]);
8616 for (j = 0; j < target_bits; j++, bit++) {
8617 if (val & (1UL << j)) {
8618 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
8619 }
8620 }
8621 }
8622
8623 unlock_user(target_mask, target_addr, 0);
8624 return 0;
8625}
8626
8627static int host_to_target_cpu_mask(const unsigned long *host_mask,
8628 size_t host_size,
8629 abi_ulong target_addr,
8630 size_t target_size)
8631{
8632 unsigned target_bits = sizeof(abi_ulong) * 8;
8633 unsigned host_bits = sizeof(*host_mask) * 8;
8634 abi_ulong *target_mask;
8635 unsigned i, j;
8636
8637 assert(host_size >= target_size);
8638
8639 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
8640 if (!target_mask) {
8641 return -TARGET_EFAULT;
8642 }
8643
8644 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
8645 unsigned bit = i * target_bits;
8646 abi_ulong val = 0;
8647
8648 for (j = 0; j < target_bits; j++, bit++) {
8649 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
8650 val |= 1UL << j;
8651 }
8652 }
8653 __put_user(val, &target_mask[i]);
8654 }
8655
8656 unlock_user(target_mask, target_addr, target_size);
8657 return 0;
8658}
8659
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008660#ifdef TARGET_NR_getdents
Richard Hendersonaee14c72021-11-14 11:35:39 +01008661static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008662{
Richard Hendersonaee14c72021-11-14 11:35:39 +01008663 g_autofree void *hdirp = NULL;
8664 void *tdirp;
8665 int hlen, hoff, toff;
8666 int hreclen, treclen;
Michael Tokarev99174ce2024-08-29 09:59:51 +03008667 off_t prev_diroff = 0;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008668
Richard Hendersonaee14c72021-11-14 11:35:39 +01008669 hdirp = g_try_malloc(count);
8670 if (!hdirp) {
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008671 return -TARGET_ENOMEM;
8672 }
8673
Richard Hendersonaee14c72021-11-14 11:35:39 +01008674#ifdef EMULATE_GETDENTS_WITH_GETDENTS
8675 hlen = sys_getdents(dirfd, hdirp, count);
8676#else
8677 hlen = sys_getdents64(dirfd, hdirp, count);
8678#endif
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008679
Richard Hendersonaee14c72021-11-14 11:35:39 +01008680 hlen = get_errno(hlen);
8681 if (is_error(hlen)) {
8682 return hlen;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008683 }
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008684
Richard Hendersonaee14c72021-11-14 11:35:39 +01008685 tdirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8686 if (!tdirp) {
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008687 return -TARGET_EFAULT;
8688 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008689
8690 for (hoff = toff = 0; hoff < hlen; hoff += hreclen, toff += treclen) {
8691#ifdef EMULATE_GETDENTS_WITH_GETDENTS
8692 struct linux_dirent *hde = hdirp + hoff;
8693#else
8694 struct linux_dirent64 *hde = hdirp + hoff;
8695#endif
8696 struct target_dirent *tde = tdirp + toff;
8697 int namelen;
8698 uint8_t type;
8699
8700 namelen = strlen(hde->d_name);
8701 hreclen = hde->d_reclen;
8702 treclen = offsetof(struct target_dirent, d_name) + namelen + 2;
8703 treclen = QEMU_ALIGN_UP(treclen, __alignof(struct target_dirent));
8704
8705 if (toff + treclen > count) {
8706 /*
8707 * If the host struct is smaller than the target struct, or
8708 * requires less alignment and thus packs into less space,
8709 * then the host can return more entries than we can pass
8710 * on to the guest.
8711 */
8712 if (toff == 0) {
8713 toff = -TARGET_EINVAL; /* result buffer is too small */
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008714 break;
8715 }
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008716 /*
Richard Hendersonaee14c72021-11-14 11:35:39 +01008717 * Return what we have, resetting the file pointer to the
8718 * location of the first record not returned.
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008719 */
Michael Tokarev99174ce2024-08-29 09:59:51 +03008720 lseek(dirfd, prev_diroff, SEEK_SET);
Richard Hendersonaee14c72021-11-14 11:35:39 +01008721 break;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008722 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008723
8724 prev_diroff = hde->d_off;
8725 tde->d_ino = tswapal(hde->d_ino);
8726 tde->d_off = tswapal(hde->d_off);
8727 tde->d_reclen = tswap16(treclen);
8728 memcpy(tde->d_name, hde->d_name, namelen + 1);
8729
8730 /*
8731 * The getdents type is in what was formerly a padding byte at the
8732 * end of the structure.
8733 */
8734#ifdef EMULATE_GETDENTS_WITH_GETDENTS
8735 type = *((uint8_t *)hde + hreclen - 1);
8736#else
8737 type = hde->d_type;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008738#endif
Richard Hendersonaee14c72021-11-14 11:35:39 +01008739 *((uint8_t *)tde + treclen - 1) = type;
8740 }
8741
8742 unlock_user(tdirp, arg2, toff);
8743 return toff;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008744}
8745#endif /* TARGET_NR_getdents */
8746
8747#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
Richard Hendersonaee14c72021-11-14 11:35:39 +01008748static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008749{
Richard Hendersonaee14c72021-11-14 11:35:39 +01008750 g_autofree void *hdirp = NULL;
8751 void *tdirp;
8752 int hlen, hoff, toff;
8753 int hreclen, treclen;
Michael Tokarev99174ce2024-08-29 09:59:51 +03008754 off_t prev_diroff = 0;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008755
Richard Hendersonaee14c72021-11-14 11:35:39 +01008756 hdirp = g_try_malloc(count);
8757 if (!hdirp) {
8758 return -TARGET_ENOMEM;
8759 }
8760
8761 hlen = get_errno(sys_getdents64(dirfd, hdirp, count));
8762 if (is_error(hlen)) {
8763 return hlen;
8764 }
8765
8766 tdirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8767 if (!tdirp) {
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008768 return -TARGET_EFAULT;
8769 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008770
8771 for (hoff = toff = 0; hoff < hlen; hoff += hreclen, toff += treclen) {
8772 struct linux_dirent64 *hde = hdirp + hoff;
8773 struct target_dirent64 *tde = tdirp + toff;
8774 int namelen;
8775
8776 namelen = strlen(hde->d_name) + 1;
8777 hreclen = hde->d_reclen;
8778 treclen = offsetof(struct target_dirent64, d_name) + namelen;
8779 treclen = QEMU_ALIGN_UP(treclen, __alignof(struct target_dirent64));
8780
8781 if (toff + treclen > count) {
8782 /*
8783 * If the host struct is smaller than the target struct, or
8784 * requires less alignment and thus packs into less space,
8785 * then the host can return more entries than we can pass
8786 * on to the guest.
8787 */
8788 if (toff == 0) {
8789 toff = -TARGET_EINVAL; /* result buffer is too small */
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008790 break;
8791 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008792 /*
8793 * Return what we have, resetting the file pointer to the
8794 * location of the first record not returned.
8795 */
Michael Tokarev99174ce2024-08-29 09:59:51 +03008796 lseek(dirfd, prev_diroff, SEEK_SET);
Richard Hendersonaee14c72021-11-14 11:35:39 +01008797 break;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008798 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008799
8800 prev_diroff = hde->d_off;
8801 tde->d_ino = tswap64(hde->d_ino);
8802 tde->d_off = tswap64(hde->d_off);
8803 tde->d_reclen = tswap16(treclen);
8804 tde->d_type = hde->d_type;
8805 memcpy(tde->d_name, hde->d_name, namelen);
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008806 }
Richard Hendersonaee14c72021-11-14 11:35:39 +01008807
8808 unlock_user(tdirp, arg2, toff);
8809 return toff;
Richard Hendersonfd08ddb2021-11-14 11:35:36 +01008810}
8811#endif /* TARGET_NR_getdents64 */
8812
Robbin Ehn9e1c7d92023-06-19 10:24:03 +02008813#if defined(TARGET_NR_riscv_hwprobe)
8814
8815#define RISCV_HWPROBE_KEY_MVENDORID 0
8816#define RISCV_HWPROBE_KEY_MARCHID 1
8817#define RISCV_HWPROBE_KEY_MIMPID 2
8818
8819#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
8820#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
8821
Christoph Müllnera3432cf2024-02-07 12:59:26 +01008822#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
8823#define RISCV_HWPROBE_IMA_FD (1 << 0)
8824#define RISCV_HWPROBE_IMA_C (1 << 1)
8825#define RISCV_HWPROBE_IMA_V (1 << 2)
8826#define RISCV_HWPROBE_EXT_ZBA (1 << 3)
8827#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
8828#define RISCV_HWPROBE_EXT_ZBS (1 << 5)
8829#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6)
8830#define RISCV_HWPROBE_EXT_ZBC (1 << 7)
8831#define RISCV_HWPROBE_EXT_ZBKB (1 << 8)
8832#define RISCV_HWPROBE_EXT_ZBKC (1 << 9)
8833#define RISCV_HWPROBE_EXT_ZBKX (1 << 10)
8834#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
8835#define RISCV_HWPROBE_EXT_ZKNE (1 << 12)
8836#define RISCV_HWPROBE_EXT_ZKNH (1 << 13)
8837#define RISCV_HWPROBE_EXT_ZKSED (1 << 14)
8838#define RISCV_HWPROBE_EXT_ZKSH (1 << 15)
8839#define RISCV_HWPROBE_EXT_ZKT (1 << 16)
8840#define RISCV_HWPROBE_EXT_ZVBB (1 << 17)
8841#define RISCV_HWPROBE_EXT_ZVBC (1 << 18)
8842#define RISCV_HWPROBE_EXT_ZVKB (1 << 19)
8843#define RISCV_HWPROBE_EXT_ZVKG (1 << 20)
8844#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21)
8845#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22)
8846#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23)
8847#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24)
8848#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25)
8849#define RISCV_HWPROBE_EXT_ZVKT (1 << 26)
8850#define RISCV_HWPROBE_EXT_ZFH (1 << 27)
8851#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28)
8852#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29)
8853#define RISCV_HWPROBE_EXT_ZVFH (1 << 30)
8854#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31)
8855#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
Christoph Müllner4f1a53b2024-02-07 13:22:55 +01008856#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
Christoph Müllnera3432cf2024-02-07 12:59:26 +01008857#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
8858#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
Robbin Ehn9e1c7d92023-06-19 10:24:03 +02008859
8860#define RISCV_HWPROBE_KEY_CPUPERF_0 5
8861#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
8862#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
8863#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
8864#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
8865#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
8866#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
8867
Palmer Dabbelt301c65f2023-11-10 09:37:16 -08008868#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
8869
Robbin Ehn9e1c7d92023-06-19 10:24:03 +02008870struct riscv_hwprobe {
8871 abi_llong key;
8872 abi_ullong value;
8873};
8874
8875static void risc_hwprobe_fill_pairs(CPURISCVState *env,
8876 struct riscv_hwprobe *pair,
8877 size_t pair_count)
8878{
8879 const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
8880
8881 for (; pair_count > 0; pair_count--, pair++) {
8882 abi_llong key;
8883 abi_ullong value;
8884 __put_user(0, &pair->value);
8885 __get_user(key, &pair->key);
8886 switch (key) {
8887 case RISCV_HWPROBE_KEY_MVENDORID:
8888 __put_user(cfg->mvendorid, &pair->value);
8889 break;
8890 case RISCV_HWPROBE_KEY_MARCHID:
8891 __put_user(cfg->marchid, &pair->value);
8892 break;
8893 case RISCV_HWPROBE_KEY_MIMPID:
8894 __put_user(cfg->mimpid, &pair->value);
8895 break;
8896 case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
8897 value = riscv_has_ext(env, RVI) &&
8898 riscv_has_ext(env, RVM) &&
8899 riscv_has_ext(env, RVA) ?
8900 RISCV_HWPROBE_BASE_BEHAVIOR_IMA : 0;
8901 __put_user(value, &pair->value);
8902 break;
8903 case RISCV_HWPROBE_KEY_IMA_EXT_0:
8904 value = riscv_has_ext(env, RVF) &&
8905 riscv_has_ext(env, RVD) ?
8906 RISCV_HWPROBE_IMA_FD : 0;
8907 value |= riscv_has_ext(env, RVC) ?
Robbin Ehnbb0a45e2023-08-28 16:56:59 +02008908 RISCV_HWPROBE_IMA_C : 0;
8909 value |= riscv_has_ext(env, RVV) ?
8910 RISCV_HWPROBE_IMA_V : 0;
8911 value |= cfg->ext_zba ?
8912 RISCV_HWPROBE_EXT_ZBA : 0;
8913 value |= cfg->ext_zbb ?
8914 RISCV_HWPROBE_EXT_ZBB : 0;
8915 value |= cfg->ext_zbs ?
8916 RISCV_HWPROBE_EXT_ZBS : 0;
Christoph Müllner01911312024-02-07 12:59:25 +01008917 value |= cfg->ext_zicboz ?
8918 RISCV_HWPROBE_EXT_ZICBOZ : 0;
Christoph Müllnera3432cf2024-02-07 12:59:26 +01008919 value |= cfg->ext_zbc ?
8920 RISCV_HWPROBE_EXT_ZBC : 0;
8921 value |= cfg->ext_zbkb ?
8922 RISCV_HWPROBE_EXT_ZBKB : 0;
8923 value |= cfg->ext_zbkc ?
8924 RISCV_HWPROBE_EXT_ZBKC : 0;
8925 value |= cfg->ext_zbkx ?
8926 RISCV_HWPROBE_EXT_ZBKX : 0;
8927 value |= cfg->ext_zknd ?
8928 RISCV_HWPROBE_EXT_ZKND : 0;
8929 value |= cfg->ext_zkne ?
8930 RISCV_HWPROBE_EXT_ZKNE : 0;
8931 value |= cfg->ext_zknh ?
8932 RISCV_HWPROBE_EXT_ZKNH : 0;
8933 value |= cfg->ext_zksed ?
8934 RISCV_HWPROBE_EXT_ZKSED : 0;
8935 value |= cfg->ext_zksh ?
8936 RISCV_HWPROBE_EXT_ZKSH : 0;
8937 value |= cfg->ext_zkt ?
8938 RISCV_HWPROBE_EXT_ZKT : 0;
8939 value |= cfg->ext_zvbb ?
8940 RISCV_HWPROBE_EXT_ZVBB : 0;
8941 value |= cfg->ext_zvbc ?
8942 RISCV_HWPROBE_EXT_ZVBC : 0;
8943 value |= cfg->ext_zvkb ?
8944 RISCV_HWPROBE_EXT_ZVKB : 0;
8945 value |= cfg->ext_zvkg ?
8946 RISCV_HWPROBE_EXT_ZVKG : 0;
8947 value |= cfg->ext_zvkned ?
8948 RISCV_HWPROBE_EXT_ZVKNED : 0;
8949 value |= cfg->ext_zvknha ?
8950 RISCV_HWPROBE_EXT_ZVKNHA : 0;
8951 value |= cfg->ext_zvknhb ?
8952 RISCV_HWPROBE_EXT_ZVKNHB : 0;
8953 value |= cfg->ext_zvksed ?
8954 RISCV_HWPROBE_EXT_ZVKSED : 0;
8955 value |= cfg->ext_zvksh ?
8956 RISCV_HWPROBE_EXT_ZVKSH : 0;
8957 value |= cfg->ext_zvkt ?
8958 RISCV_HWPROBE_EXT_ZVKT : 0;
8959 value |= cfg->ext_zfh ?
8960 RISCV_HWPROBE_EXT_ZFH : 0;
8961 value |= cfg->ext_zfhmin ?
8962 RISCV_HWPROBE_EXT_ZFHMIN : 0;
8963 value |= cfg->ext_zihintntl ?
8964 RISCV_HWPROBE_EXT_ZIHINTNTL : 0;
8965 value |= cfg->ext_zvfh ?
8966 RISCV_HWPROBE_EXT_ZVFH : 0;
8967 value |= cfg->ext_zvfhmin ?
8968 RISCV_HWPROBE_EXT_ZVFHMIN : 0;
8969 value |= cfg->ext_zfa ?
8970 RISCV_HWPROBE_EXT_ZFA : 0;
Christoph Müllner4f1a53b2024-02-07 13:22:55 +01008971 value |= cfg->ext_ztso ?
8972 RISCV_HWPROBE_EXT_ZTSO : 0;
Christoph Müllnera3432cf2024-02-07 12:59:26 +01008973 value |= cfg->ext_zacas ?
8974 RISCV_HWPROBE_EXT_ZACAS : 0;
8975 value |= cfg->ext_zicond ?
8976 RISCV_HWPROBE_EXT_ZICOND : 0;
Robbin Ehn9e1c7d92023-06-19 10:24:03 +02008977 __put_user(value, &pair->value);
8978 break;
8979 case RISCV_HWPROBE_KEY_CPUPERF_0:
8980 __put_user(RISCV_HWPROBE_MISALIGNED_FAST, &pair->value);
8981 break;
Palmer Dabbelt301c65f2023-11-10 09:37:16 -08008982 case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE:
8983 value = cfg->ext_zicboz ? cfg->cboz_blocksize : 0;
8984 __put_user(value, &pair->value);
8985 break;
Robbin Ehn9e1c7d92023-06-19 10:24:03 +02008986 default:
8987 __put_user(-1, &pair->key);
8988 break;
8989 }
8990 }
8991}
8992
8993static int cpu_set_valid(abi_long arg3, abi_long arg4)
8994{
8995 int ret, i, tmp;
8996 size_t host_mask_size, target_mask_size;
8997 unsigned long *host_mask;
8998
8999 /*
9000 * cpu_set_t represent CPU masks as bit masks of type unsigned long *.
9001 * arg3 contains the cpu count.
9002 */
9003 tmp = (8 * sizeof(abi_ulong));
9004 target_mask_size = ((arg3 + tmp - 1) / tmp) * sizeof(abi_ulong);
9005 host_mask_size = (target_mask_size + (sizeof(*host_mask) - 1)) &
9006 ~(sizeof(*host_mask) - 1);
9007
9008 host_mask = alloca(host_mask_size);
9009
9010 ret = target_to_host_cpu_mask(host_mask, host_mask_size,
9011 arg4, target_mask_size);
9012 if (ret != 0) {
9013 return ret;
9014 }
9015
9016 for (i = 0 ; i < host_mask_size / sizeof(*host_mask); i++) {
9017 if (host_mask[i] != 0) {
9018 return 0;
9019 }
9020 }
9021 return -TARGET_EINVAL;
9022}
9023
9024static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
9025 abi_long arg2, abi_long arg3,
9026 abi_long arg4, abi_long arg5)
9027{
9028 int ret;
9029 struct riscv_hwprobe *host_pairs;
9030
9031 /* flags must be 0 */
9032 if (arg5 != 0) {
9033 return -TARGET_EINVAL;
9034 }
9035
9036 /* check cpu_set */
9037 if (arg3 != 0) {
9038 ret = cpu_set_valid(arg3, arg4);
9039 if (ret != 0) {
9040 return ret;
9041 }
9042 } else if (arg4 != 0) {
9043 return -TARGET_EINVAL;
9044 }
9045
9046 /* no pairs */
9047 if (arg2 == 0) {
9048 return 0;
9049 }
9050
9051 host_pairs = lock_user(VERIFY_WRITE, arg1,
9052 sizeof(*host_pairs) * (size_t)arg2, 0);
9053 if (host_pairs == NULL) {
9054 return -TARGET_EFAULT;
9055 }
9056 risc_hwprobe_fill_pairs(cpu_env, host_pairs, arg2);
9057 unlock_user(host_pairs, arg1, sizeof(*host_pairs) * (size_t)arg2);
9058 return 0;
9059}
9060#endif /* TARGET_NR_riscv_hwprobe */
9061
YAMAMOTO Takashie10fbe82021-05-31 14:50:12 +09009062#if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
9063_syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
9064#endif
9065
Thomas Weißschuh7f696cdd2023-04-24 17:34:29 +02009066#if defined(TARGET_NR_open_tree) && defined(__NR_open_tree)
9067#define __NR_sys_open_tree __NR_open_tree
9068_syscall3(int, sys_open_tree, int, __dfd, const char *, __filename,
9069 unsigned int, __flags)
9070#endif
9071
Thomas Weißschuh4b2d2752023-04-24 17:34:28 +02009072#if defined(TARGET_NR_move_mount) && defined(__NR_move_mount)
9073#define __NR_sys_move_mount __NR_move_mount
9074_syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
9075 int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
9076#endif
9077
Richard Hendersondc1ce182018-08-18 12:01:04 -07009078/* This is an internal helper for do_syscall so that it is easier
9079 * to have a single return point, so that actions, such as logging
9080 * of syscall results, can be performed.
9081 * All errnos that do_syscall() returns must be -TARGET_<errcode>.
9082 */
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +02009083static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
Richard Hendersondc1ce182018-08-18 12:01:04 -07009084 abi_long arg2, abi_long arg3, abi_long arg4,
9085 abi_long arg5, abi_long arg6, abi_long arg7,
9086 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00009087{
Richard Henderson29a0af62019-03-22 16:07:18 -07009088 CPUState *cpu = env_cpu(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00009089 abi_long ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009090#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
9091 || defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
Aleksandar Rikaloefa92182019-06-28 12:43:34 +02009092 || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) \
9093 || defined(TARGET_NR_statx)
bellard31e31b82003-02-18 22:55:36 +00009094 struct stat st;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009095#endif
9096#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
9097 || defined(TARGET_NR_fstatfs)
bellard56c8f682005-11-28 22:28:41 +00009098 struct statfs stfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009099#endif
pbrook53a59602006-03-25 19:31:22 +00009100 void *p;
ths3b46e622007-09-17 08:09:54 +00009101
bellard31e31b82003-02-18 22:55:36 +00009102 switch(num) {
9103 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02009104 /* In old applications this may be used to implement _exit(2).
zhaolichang6f9ff552020-09-17 15:50:25 +08009105 However in threaded applications it is used for thread termination,
Andreas Färber9b056fc2013-06-24 23:53:10 +02009106 and _exit_group is used for application termination.
9107 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01009108
9109 if (block_signals()) {
Richard Hendersonaf254a22021-11-22 19:47:33 +01009110 return -QEMU_ERESTARTSYS;
Timothy E Baldwina0995882016-05-27 15:51:56 +01009111 }
9112
Alex Bennée1f81ce92020-05-20 15:05:39 +01009113 pthread_mutex_lock(&clone_lock);
Alex Bennéedd1f6342016-09-30 22:31:01 +01009114
Andreas Färberbdc44642013-06-24 23:50:24 +02009115 if (CPU_NEXT(first_cpu)) {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00009116 TaskState *ts = get_task_state(cpu);
pbrookc2764712009-03-07 15:24:59 +00009117
Richard Henderson6490d9a2023-01-24 10:10:19 -10009118 if (ts->child_tidptr) {
9119 put_user_u32(0, ts->child_tidptr);
9120 do_sys_futex(g2h(cpu, ts->child_tidptr),
9121 FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
9122 }
9123
9124 object_unparent(OBJECT(cpu));
Alex Bennée1f81ce92020-05-20 15:05:39 +01009125 object_unref(OBJECT(cpu));
9126 /*
9127 * At this point the CPU should be unrealized and removed
9128 * from cpu lists. We can clean-up the rest of the thread
9129 * data without the lock held.
9130 */
Alex Bennéedd1f6342016-09-30 22:31:01 +01009131
Alex Bennée1f81ce92020-05-20 15:05:39 +01009132 pthread_mutex_unlock(&clone_lock);
Alex Bennéedd1f6342016-09-30 22:31:01 +01009133
Andreas Färbera2247f82013-06-09 19:47:04 +02009134 thread_cpu = NULL;
Andreas Färber9b056fc2013-06-24 23:53:10 +02009135 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04009136 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02009137 pthread_exit(NULL);
9138 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01009139
Alex Bennée1f81ce92020-05-20 15:05:39 +01009140 pthread_mutex_unlock(&clone_lock);
Alex Bennée708b6a62018-06-22 17:09:10 +01009141 preexit_cleanup(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00009142 _exit(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009143 return 0; /* avoid warning */
bellard31e31b82003-02-18 22:55:36 +00009144 case TARGET_NR_read:
Andreas Schwabba584f12019-03-05 17:45:05 +01009145 if (arg2 == 0 && arg3 == 0) {
9146 return get_errno(safe_read(arg1, 0, 0));
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009147 } else {
aurel3238d840e2009-01-30 19:48:17 +00009148 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009149 return -TARGET_EFAULT;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01009150 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02009151 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01009152 fd_trans_host_to_target_data(arg1)) {
9153 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02009154 }
aurel3238d840e2009-01-30 19:48:17 +00009155 unlock_user(p, arg2, ret);
9156 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009157 return ret;
bellard31e31b82003-02-18 22:55:36 +00009158 case TARGET_NR_write:
Tony Garnock-Jones58cfa6c2018-09-08 19:22:05 +01009159 if (arg2 == 0 && arg3 == 0) {
9160 return get_errno(safe_write(arg1, 0, 0));
9161 }
bellard579a97f2007-11-11 14:26:47 +00009162 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009163 return -TARGET_EFAULT;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01009164 if (fd_trans_target_to_host_data(arg1)) {
9165 void *copy = g_malloc(arg3);
9166 memcpy(copy, p, arg3);
9167 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
9168 if (ret >= 0) {
9169 ret = get_errno(safe_write(arg1, copy, ret));
9170 }
9171 g_free(copy);
9172 } else {
9173 ret = get_errno(safe_write(arg1, p, arg3));
9174 }
pbrook53a59602006-03-25 19:31:22 +00009175 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009176 return ret;
9177
Chen Gang704eff62015-08-21 05:37:33 +08009178#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00009179 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00009180 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009181 return -TARGET_EFAULT;
Ilya Leoshkevicha4dab0a2023-06-30 19:04:16 +01009182 ret = get_errno(do_guest_openat(cpu_env, AT_FDCWD, p,
Riku Voipio0b2effd2014-08-06 10:36:37 +03009183 target_to_host_bitmask(arg2, fcntl_flags_tbl),
Ilya Leoshkevich35be8982023-06-30 19:04:17 +01009184 arg3, true));
Laurent Viviere36800c2015-10-02 14:48:09 +02009185 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00009186 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009187 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009188#endif
ths82424832007-09-24 09:21:55 +00009189 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00009190 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009191 return -TARGET_EFAULT;
Ilya Leoshkevicha4dab0a2023-06-30 19:04:16 +01009192 ret = get_errno(do_guest_openat(cpu_env, arg1, p,
Riku Voipio0b2effd2014-08-06 10:36:37 +03009193 target_to_host_bitmask(arg3, fcntl_flags_tbl),
Ilya Leoshkevich35be8982023-06-30 19:04:17 +01009194 arg4, true));
Laurent Viviere36800c2015-10-02 14:48:09 +02009195 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00009196 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009197 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02009198#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
9199 case TARGET_NR_name_to_handle_at:
9200 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009201 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02009202#endif
9203#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
9204 case TARGET_NR_open_by_handle_at:
9205 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02009206 fd_trans_unregister(ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009207 return ret;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02009208#endif
Helge Dellercc054c62022-09-18 21:45:46 +02009209#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
9210 case TARGET_NR_pidfd_open:
9211 return get_errno(pidfd_open(arg1, arg2));
9212#endif
9213#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal)
9214 case TARGET_NR_pidfd_send_signal:
9215 {
Laurent Vivier46187d72022-10-05 18:38:26 +02009216 siginfo_t uinfo, *puinfo;
Helge Dellercc054c62022-09-18 21:45:46 +02009217
Laurent Vivier46187d72022-10-05 18:38:26 +02009218 if (arg3) {
9219 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9220 if (!p) {
9221 return -TARGET_EFAULT;
9222 }
9223 target_to_host_siginfo(&uinfo, p);
9224 unlock_user(p, arg3, 0);
9225 puinfo = &uinfo;
9226 } else {
9227 puinfo = NULL;
Helge Dellercc054c62022-09-18 21:45:46 +02009228 }
Helge Dellercc054c62022-09-18 21:45:46 +02009229 ret = get_errno(pidfd_send_signal(arg1, target_to_host_signal(arg2),
Laurent Vivier46187d72022-10-05 18:38:26 +02009230 puinfo, arg4));
Helge Dellercc054c62022-09-18 21:45:46 +02009231 }
9232 return ret;
9233#endif
9234#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd)
9235 case TARGET_NR_pidfd_getfd:
9236 return get_errno(pidfd_getfd(arg1, arg2, arg3));
9237#endif
bellard31e31b82003-02-18 22:55:36 +00009238 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02009239 fd_trans_unregister(arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009240 return get_errno(close(arg1));
Helge Delleraf804f32022-10-25 04:34:14 +02009241#if defined(__NR_close_range) && defined(TARGET_NR_close_range)
9242 case TARGET_NR_close_range:
9243 ret = get_errno(sys_close_range(arg1, arg2, arg3));
9244 if (ret == 0 && !(arg3 & CLOSE_RANGE_CLOEXEC)) {
9245 abi_long fd, maxfd;
9246 maxfd = MIN(arg2, target_fd_max);
9247 for (fd = arg1; fd < maxfd; fd++) {
9248 fd_trans_unregister(fd);
9249 }
9250 }
9251 return ret;
9252#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009253
bellard31e31b82003-02-18 22:55:36 +00009254 case TARGET_NR_brk:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009255 return do_brk(arg1);
Chen Gang704eff62015-08-21 05:37:33 +08009256#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00009257 case TARGET_NR_fork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009258 return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
Chen Gang704eff62015-08-21 05:37:33 +08009259#endif
thse5febef2007-04-01 18:31:35 +00009260#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00009261 case TARGET_NR_waitpid:
9262 {
pbrook53a59602006-03-25 19:31:22 +00009263 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009264 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01009265 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00009266 && put_user_s32(host_to_target_waitstatus(status), arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009267 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00009268 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009269 return ret;
thse5febef2007-04-01 18:31:35 +00009270#endif
pbrookf0cbb612008-05-30 18:20:05 +00009271#ifdef TARGET_NR_waitid
9272 case TARGET_NR_waitid:
9273 {
Richard Hendersonf0907ff2024-04-05 11:58:14 -10009274 struct rusage ru;
pbrookf0cbb612008-05-30 18:20:05 +00009275 siginfo_t info;
Richard Hendersonf0907ff2024-04-05 11:58:14 -10009276
9277 ret = get_errno(safe_waitid(arg1, arg2, (arg3 ? &info : NULL),
9278 arg4, (arg5 ? &ru : NULL)));
9279 if (!is_error(ret)) {
9280 if (arg3) {
9281 p = lock_user(VERIFY_WRITE, arg3,
9282 sizeof(target_siginfo_t), 0);
9283 if (!p) {
9284 return -TARGET_EFAULT;
9285 }
9286 host_to_target_siginfo(p, &info);
9287 unlock_user(p, arg3, sizeof(target_siginfo_t));
9288 }
9289 if (arg5 && host_to_target_rusage(arg5, &ru)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009290 return -TARGET_EFAULT;
Richard Hendersonf0907ff2024-04-05 11:58:14 -10009291 }
pbrookf0cbb612008-05-30 18:20:05 +00009292 }
9293 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009294 return ret;
pbrookf0cbb612008-05-30 18:20:05 +00009295#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009296#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009297 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00009298 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009299 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009300 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02009301 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00009302 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009303 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009304#endif
Chen Gang704eff62015-08-21 05:37:33 +08009305#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00009306 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00009307 {
9308 void * p2;
9309 p = lock_user_string(arg1);
9310 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009311 if (!p || !p2)
9312 ret = -TARGET_EFAULT;
9313 else
9314 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009315 unlock_user(p2, arg2, 0);
9316 unlock_user(p, arg1, 0);
9317 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009318 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009319#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009320#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00009321 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00009322 {
9323 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00009324 if (!arg2 || !arg4)
Richard Henderson2852aaf2018-08-18 12:01:06 -07009325 return -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00009326 p = lock_user_string(arg2);
9327 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00009328 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009329 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00009330 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009331 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00009332 unlock_user(p, arg2, 0);
9333 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00009334 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009335 return ret;
ths64f0ce42007-09-24 09:25:06 +00009336#endif
Chen Gang704eff62015-08-21 05:37:33 +08009337#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00009338 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00009339 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009340 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009341 ret = get_errno(unlink(p));
9342 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009343 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009344#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009345#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00009346 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00009347 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009348 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009349 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00009350 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009351 return ret;
balrogb7d35e62007-12-12 00:40:24 +00009352#endif
Drew DeVault55bbe4d2022-11-04 18:36:32 +01009353 case TARGET_NR_execveat:
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02009354 return do_execv(cpu_env, arg1, arg2, arg3, arg4, arg5, true);
bellard31e31b82003-02-18 22:55:36 +00009355 case TARGET_NR_execve:
Pierrick Bouvier7a8d9f32023-07-05 14:10:23 +02009356 return do_execv(cpu_env, AT_FDCWD, arg1, arg2, arg3, 0, false);
bellard31e31b82003-02-18 22:55:36 +00009357 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00009358 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009359 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009360 ret = get_errno(chdir(p));
9361 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009362 return ret;
bellarda315a142005-01-30 22:59:18 +00009363#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00009364 case TARGET_NR_time:
9365 {
pbrook53a59602006-03-25 19:31:22 +00009366 time_t host_time;
9367 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00009368 if (!is_error(ret)
9369 && arg1
9370 && put_user_sal(host_time, arg1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009371 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00009372 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009373 return ret;
bellarda315a142005-01-30 22:59:18 +00009374#endif
Chen Gang704eff62015-08-21 05:37:33 +08009375#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00009376 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00009377 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009378 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009379 ret = get_errno(mknod(p, arg2, arg3));
9380 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009381 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009382#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009383#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00009384 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00009385 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009386 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009387 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00009388 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009389 return ret;
ths75ac37a2007-09-24 09:23:05 +00009390#endif
Chen Gang704eff62015-08-21 05:37:33 +08009391#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00009392 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00009393 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009394 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009395 ret = get_errno(chmod(p, arg2));
9396 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009397 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009398#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009399#ifdef TARGET_NR_lseek
bellard31e31b82003-02-18 22:55:36 +00009400 case TARGET_NR_lseek:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009401 return get_errno(lseek(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009402#endif
Richard Henderson92317332010-05-03 10:07:53 -07009403#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
9404 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00009405 case TARGET_NR_getxpid:
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02009406 cpu_env->ir[IR_A4] = getppid();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009407 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07009408#endif
9409#ifdef TARGET_NR_getpid
9410 case TARGET_NR_getpid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009411 return get_errno(getpid());
Richard Henderson92317332010-05-03 10:07:53 -07009412#endif
bellard31e31b82003-02-18 22:55:36 +00009413 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01009414 {
9415 /* need to look at the data field */
9416 void *p2, *p3;
9417
9418 if (arg1) {
9419 p = lock_user_string(arg1);
9420 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009421 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01009422 }
9423 } else {
9424 p = NULL;
9425 }
9426
9427 p2 = lock_user_string(arg2);
9428 if (!p2) {
9429 if (arg1) {
9430 unlock_user(p, arg1, 0);
9431 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07009432 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01009433 }
9434
9435 if (arg3) {
9436 p3 = lock_user_string(arg3);
9437 if (!p3) {
9438 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00009439 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01009440 }
9441 unlock_user(p2, arg2, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -07009442 return -TARGET_EFAULT;
Paul Burton356d7712014-06-22 11:25:37 +01009443 }
9444 } else {
9445 p3 = NULL;
9446 }
9447
9448 /* FIXME - arg5 should be locked, but it isn't clear how to
9449 * do that since it's not guaranteed to be a NULL-terminated
9450 * string.
9451 */
9452 if (!arg5) {
9453 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
9454 } else {
Richard Henderson3e8f1622021-02-12 10:48:43 -08009455 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(cpu, arg5));
Paul Burton356d7712014-06-22 11:25:37 +01009456 }
9457 ret = get_errno(ret);
9458
9459 if (arg1) {
9460 unlock_user(p, arg1, 0);
9461 }
9462 unlock_user(p2, arg2, 0);
9463 if (arg3) {
9464 unlock_user(p3, arg3, 0);
9465 }
9466 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009467 return ret;
Laurent Vivier6eb9dbf2020-05-02 21:46:42 +02009468#if defined(TARGET_NR_umount) || defined(TARGET_NR_oldumount)
9469#if defined(TARGET_NR_umount)
bellard31e31b82003-02-18 22:55:36 +00009470 case TARGET_NR_umount:
Laurent Vivier6eb9dbf2020-05-02 21:46:42 +02009471#endif
9472#if defined(TARGET_NR_oldumount)
9473 case TARGET_NR_oldumount:
9474#endif
bellard579a97f2007-11-11 14:26:47 +00009475 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009476 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009477 ret = get_errno(umount(p));
9478 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009479 return ret;
thse5febef2007-04-01 18:31:35 +00009480#endif
Thomas Weißschuh4b2d2752023-04-24 17:34:28 +02009481#if defined(TARGET_NR_move_mount) && defined(__NR_move_mount)
9482 case TARGET_NR_move_mount:
9483 {
9484 void *p2, *p4;
9485
9486 if (!arg2 || !arg4) {
9487 return -TARGET_EFAULT;
9488 }
9489
9490 p2 = lock_user_string(arg2);
9491 if (!p2) {
9492 return -TARGET_EFAULT;
9493 }
9494
9495 p4 = lock_user_string(arg4);
9496 if (!p4) {
9497 unlock_user(p2, arg2, 0);
9498 return -TARGET_EFAULT;
9499 }
9500 ret = get_errno(sys_move_mount(arg1, p2, arg3, p4, arg5));
9501
9502 unlock_user(p2, arg2, 0);
9503 unlock_user(p4, arg4, 0);
9504
9505 return ret;
9506 }
9507#endif
Thomas Weißschuh7f696cdd2023-04-24 17:34:29 +02009508#if defined(TARGET_NR_open_tree) && defined(__NR_open_tree)
9509 case TARGET_NR_open_tree:
9510 {
9511 void *p2;
9512 int host_flags;
9513
9514 if (!arg2) {
9515 return -TARGET_EFAULT;
9516 }
9517
9518 p2 = lock_user_string(arg2);
9519 if (!p2) {
9520 return -TARGET_EFAULT;
9521 }
9522
9523 host_flags = arg3 & ~TARGET_O_CLOEXEC;
9524 if (arg3 & TARGET_O_CLOEXEC) {
9525 host_flags |= O_CLOEXEC;
9526 }
9527
9528 ret = get_errno(sys_open_tree(arg1, p2, host_flags));
9529
9530 unlock_user(p2, arg2, 0);
9531
9532 return ret;
9533 }
9534#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009535#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009536 case TARGET_NR_stime:
9537 {
Laurent Vivier0f1f2d42019-11-12 15:25:56 +01009538 struct timespec ts;
9539 ts.tv_nsec = 0;
9540 if (get_user_sal(ts.tv_sec, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009541 return -TARGET_EFAULT;
Laurent Vivier0f1f2d42019-11-12 15:25:56 +01009542 }
9543 return get_errno(clock_settime(CLOCK_REALTIME, &ts));
bellard31e31b82003-02-18 22:55:36 +00009544 }
j_mayer7a3148a2007-04-05 07:13:51 +00009545#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009546#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009547 case TARGET_NR_alarm:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009548 return alarm(arg1);
j_mayer7a3148a2007-04-05 07:13:51 +00009549#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009550#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009551 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01009552 if (!block_signals()) {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +00009553 sigsuspend(&get_task_state(cpu)->signal_mask);
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01009554 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009555 return -TARGET_EINTR;
j_mayer7a3148a2007-04-05 07:13:51 +00009556#endif
thse5febef2007-04-01 18:31:35 +00009557#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00009558 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00009559 {
pbrook53a59602006-03-25 19:31:22 +00009560 struct utimbuf tbuf, *host_tbuf;
9561 struct target_utimbuf *target_tbuf;
9562 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00009563 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009564 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009565 tbuf.actime = tswapal(target_tbuf->actime);
9566 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00009567 unlock_user_struct(target_tbuf, arg2, 0);
9568 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00009569 } else {
pbrook53a59602006-03-25 19:31:22 +00009570 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00009571 }
bellard579a97f2007-11-11 14:26:47 +00009572 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009573 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009574 ret = get_errno(utime(p, host_tbuf));
9575 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00009576 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009577 return ret;
thse5febef2007-04-01 18:31:35 +00009578#endif
Chen Gang704eff62015-08-21 05:37:33 +08009579#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00009580 case TARGET_NR_utimes:
9581 {
bellard978a66f2004-12-06 22:58:05 +00009582 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00009583 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00009584 if (copy_from_user_timeval(&tv[0], arg2)
9585 || copy_from_user_timeval(&tv[1],
9586 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009587 return -TARGET_EFAULT;
bellard978a66f2004-12-06 22:58:05 +00009588 tvp = tv;
9589 } else {
9590 tvp = NULL;
9591 }
bellard579a97f2007-11-11 14:26:47 +00009592 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009593 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009594 ret = get_errno(utimes(p, tvp));
9595 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00009596 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009597 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009598#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009599#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00009600 case TARGET_NR_futimesat:
9601 {
9602 struct timeval *tvp, tv[2];
9603 if (arg3) {
9604 if (copy_from_user_timeval(&tv[0], arg3)
9605 || copy_from_user_timeval(&tv[1],
9606 arg3 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009607 return -TARGET_EFAULT;
balrogac8a6552008-09-20 02:25:39 +00009608 tvp = tv;
9609 } else {
9610 tvp = NULL;
9611 }
Richard Henderson2852aaf2018-08-18 12:01:06 -07009612 if (!(p = lock_user_string(arg2))) {
9613 return -TARGET_EFAULT;
9614 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01009615 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00009616 unlock_user(p, arg2, 0);
9617 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009618 return ret;
balrogac8a6552008-09-20 02:25:39 +00009619#endif
Chen Gang704eff62015-08-21 05:37:33 +08009620#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00009621 case TARGET_NR_access:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009622 if (!(p = lock_user_string(arg1))) {
9623 return -TARGET_EFAULT;
9624 }
Ulrich Hecht719f9082009-07-03 17:09:29 +02009625 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00009626 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009627 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009628#endif
ths92a34c12007-09-24 09:27:49 +00009629#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
9630 case TARGET_NR_faccessat:
Richard Henderson2852aaf2018-08-18 12:01:06 -07009631 if (!(p = lock_user_string(arg2))) {
9632 return -TARGET_EFAULT;
9633 }
Peter Maydellc0d472b2013-06-12 16:20:21 +01009634 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009635 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009636 return ret;
ths92a34c12007-09-24 09:27:49 +00009637#endif
WANG Xuerui35a2c852022-10-09 14:08:13 +08009638#if defined(TARGET_NR_faccessat2)
9639 case TARGET_NR_faccessat2:
9640 if (!(p = lock_user_string(arg2))) {
9641 return -TARGET_EFAULT;
9642 }
9643 ret = get_errno(faccessat(arg1, p, arg3, arg4));
9644 unlock_user(p, arg2, 0);
9645 return ret;
9646#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009647#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009648 case TARGET_NR_nice:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009649 return get_errno(nice(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +00009650#endif
bellard31e31b82003-02-18 22:55:36 +00009651 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00009652 sync();
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009653 return 0;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02009654#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
9655 case TARGET_NR_syncfs:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009656 return get_errno(syncfs(arg1));
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02009657#endif
bellard31e31b82003-02-18 22:55:36 +00009658 case TARGET_NR_kill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009659 return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
Chen Gang704eff62015-08-21 05:37:33 +08009660#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00009661 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00009662 {
9663 void *p2;
9664 p = lock_user_string(arg1);
9665 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009666 if (!p || !p2)
9667 ret = -TARGET_EFAULT;
9668 else
9669 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009670 unlock_user(p2, arg2, 0);
9671 unlock_user(p, arg1, 0);
9672 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009673 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009674#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009675#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00009676 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00009677 {
bellard579a97f2007-11-11 14:26:47 +00009678 void *p2;
ths722183f2007-09-24 09:24:37 +00009679 p = lock_user_string(arg2);
9680 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00009681 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009682 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00009683 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009684 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00009685 unlock_user(p2, arg4, 0);
9686 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00009687 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009688 return ret;
ths722183f2007-09-24 09:24:37 +00009689#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01009690#if defined(TARGET_NR_renameat2)
9691 case TARGET_NR_renameat2:
9692 {
9693 void *p2;
9694 p = lock_user_string(arg2);
9695 p2 = lock_user_string(arg4);
9696 if (!p || !p2) {
9697 ret = -TARGET_EFAULT;
9698 } else {
9699 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
9700 }
9701 unlock_user(p2, arg4, 0);
9702 unlock_user(p, arg2, 0);
9703 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009704 return ret;
Andreas Schwab95d03072018-01-23 11:53:31 +01009705#endif
Chen Gang704eff62015-08-21 05:37:33 +08009706#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00009707 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00009708 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009709 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009710 ret = get_errno(mkdir(p, arg2));
9711 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009712 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009713#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009714#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00009715 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00009716 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009717 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009718 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00009719 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009720 return ret;
ths4472ad02007-09-24 09:22:32 +00009721#endif
Chen Gang704eff62015-08-21 05:37:33 +08009722#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00009723 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00009724 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009725 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009726 ret = get_errno(rmdir(p));
9727 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009728 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009729#endif
bellard31e31b82003-02-18 22:55:36 +00009730 case TARGET_NR_dup:
9731 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02009732 if (ret >= 0) {
9733 fd_trans_dup(arg1, ret);
9734 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009735 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009736#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00009737 case TARGET_NR_pipe:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009738 return do_pipe(cpu_env, arg1, 0, 0);
Chen Gang704eff62015-08-21 05:37:33 +08009739#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03009740#ifdef TARGET_NR_pipe2
9741 case TARGET_NR_pipe2:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009742 return do_pipe(cpu_env, arg1,
9743 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03009744#endif
bellard31e31b82003-02-18 22:55:36 +00009745 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00009746 {
pbrook53a59602006-03-25 19:31:22 +00009747 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00009748 struct tms tms;
9749 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00009750 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00009751 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
9752 if (!tmsp)
Richard Henderson2852aaf2018-08-18 12:01:06 -07009753 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009754 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
9755 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
9756 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
9757 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00009758 }
bellardc596ed12003-07-13 17:32:31 +00009759 if (!is_error(ret))
9760 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00009761 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009762 return ret;
bellard31e31b82003-02-18 22:55:36 +00009763 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00009764 if (arg1 == 0) {
9765 ret = get_errno(acct(NULL));
9766 } else {
Richard Henderson2852aaf2018-08-18 12:01:06 -07009767 if (!(p = lock_user_string(arg1))) {
9768 return -TARGET_EFAULT;
9769 }
aurel3238d840e2009-01-30 19:48:17 +00009770 ret = get_errno(acct(path(p)));
9771 unlock_user(p, arg1, 0);
9772 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009773 return ret;
Richard Henderson8070e7b2013-07-24 09:50:00 -10009774#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00009775 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00009776 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009777 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009778 ret = get_errno(umount2(p, arg2));
9779 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009780 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009781#endif
bellard31e31b82003-02-18 22:55:36 +00009782 case TARGET_NR_ioctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009783 return do_ioctl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13009784#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00009785 case TARGET_NR_fcntl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009786 return do_fcntl(arg1, arg2, arg3);
Michael Clark47ae93c2018-03-03 01:31:11 +13009787#endif
bellard31e31b82003-02-18 22:55:36 +00009788 case TARGET_NR_setpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009789 return get_errno(setpgid(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009790 case TARGET_NR_umask:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009791 return get_errno(umask(arg1));
bellard31e31b82003-02-18 22:55:36 +00009792 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00009793 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009794 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00009795 ret = get_errno(chroot(p));
9796 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009797 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009798#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00009799 case TARGET_NR_dup2:
9800 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02009801 if (ret >= 0) {
9802 fd_trans_dup(arg1, arg2);
9803 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009804 return ret;
Chen Gang704eff62015-08-21 05:37:33 +08009805#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009806#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
9807 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00009808 {
9809 int host_flags;
9810
9811 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
9812 return -EINVAL;
9813 }
9814 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
9815 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02009816 if (ret >= 0) {
9817 fd_trans_dup(arg1, arg2);
9818 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009819 return ret;
Peter Maydell10fa9932017-12-15 15:18:00 +00009820 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03009821#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009822#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009823 case TARGET_NR_getppid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009824 return get_errno(getppid());
j_mayer7a3148a2007-04-05 07:13:51 +00009825#endif
Chen Gang704eff62015-08-21 05:37:33 +08009826#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00009827 case TARGET_NR_getpgrp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009828 return get_errno(getpgrp());
Chen Gang704eff62015-08-21 05:37:33 +08009829#endif
bellard31e31b82003-02-18 22:55:36 +00009830 case TARGET_NR_setsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009831 return get_errno(setsid());
thse5febef2007-04-01 18:31:35 +00009832#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00009833 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00009834 {
Richard Henderson02d0de12021-04-22 16:02:26 -07009835#if defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00009836 struct target_sigaction act, oact, *pact, *old_act;
9837
9838 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00009839 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009840 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00009841 act._sa_handler = old_act->_sa_handler;
9842 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
9843 act.sa_flags = old_act->sa_flags;
9844 unlock_user_struct(old_act, arg2, 0);
9845 pact = &act;
9846 } else {
9847 pact = NULL;
9848 }
9849
Richard Henderson02fb28e2021-04-22 16:02:23 -07009850 ret = get_errno(do_sigaction(arg1, pact, &oact, 0));
bellard106ec872006-06-27 21:08:10 +00009851
9852 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00009853 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009854 return -TARGET_EFAULT;
bellard106ec872006-06-27 21:08:10 +00009855 old_act->_sa_handler = oact._sa_handler;
9856 old_act->sa_flags = oact.sa_flags;
9857 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
9858 old_act->sa_mask.sig[1] = 0;
9859 old_act->sa_mask.sig[2] = 0;
9860 old_act->sa_mask.sig[3] = 0;
9861 unlock_user_struct(old_act, arg3, 1);
9862 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08009863#else
9864 struct target_old_sigaction *old_act;
9865 struct target_sigaction act, oact, *pact;
9866 if (arg2) {
9867 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009868 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08009869 act._sa_handler = old_act->_sa_handler;
9870 target_siginitset(&act.sa_mask, old_act->sa_mask);
9871 act.sa_flags = old_act->sa_flags;
Richard Hendersonca192272021-04-22 16:02:24 -07009872#ifdef TARGET_ARCH_HAS_SA_RESTORER
Richard Henderson6049f4f2009-12-27 18:30:03 -08009873 act.sa_restorer = old_act->sa_restorer;
Richard Hendersonca192272021-04-22 16:02:24 -07009874#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08009875 unlock_user_struct(old_act, arg2, 0);
9876 pact = &act;
9877 } else {
9878 pact = NULL;
9879 }
Richard Henderson02fb28e2021-04-22 16:02:23 -07009880 ret = get_errno(do_sigaction(arg1, pact, &oact, 0));
Richard Henderson6049f4f2009-12-27 18:30:03 -08009881 if (!is_error(ret) && arg3) {
9882 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -07009883 return -TARGET_EFAULT;
Richard Henderson6049f4f2009-12-27 18:30:03 -08009884 old_act->_sa_handler = oact._sa_handler;
9885 old_act->sa_mask = oact.sa_mask.sig[0];
9886 old_act->sa_flags = oact.sa_flags;
Richard Hendersonca192272021-04-22 16:02:24 -07009887#ifdef TARGET_ARCH_HAS_SA_RESTORER
Richard Henderson6049f4f2009-12-27 18:30:03 -08009888 old_act->sa_restorer = oact.sa_restorer;
Richard Hendersonca192272021-04-22 16:02:24 -07009889#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08009890 unlock_user_struct(old_act, arg3, 1);
9891 }
ths388bb212007-05-13 13:58:00 +00009892#endif
bellard31e31b82003-02-18 22:55:36 +00009893 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009894 return ret;
thse5febef2007-04-01 18:31:35 +00009895#endif
bellard66fb9762003-03-23 01:06:05 +00009896 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00009897 {
Richard Henderson0f6f9902021-04-22 16:02:25 -07009898 /*
9899 * For Alpha and SPARC this is a 5 argument syscall, with
Peter Maydell78bfef72017-11-06 18:33:26 +00009900 * a 'restorer' parameter which must be copied into the
9901 * sa_restorer field of the sigaction struct.
9902 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
9903 * and arg5 is the sigsetsize.
Peter Maydell78bfef72017-11-06 18:33:26 +00009904 */
Richard Henderson0f6f9902021-04-22 16:02:25 -07009905#if defined(TARGET_ALPHA)
9906 target_ulong sigsetsize = arg4;
9907 target_ulong restorer = arg5;
9908#elif defined(TARGET_SPARC)
Peter Maydell78bfef72017-11-06 18:33:26 +00009909 target_ulong restorer = arg4;
9910 target_ulong sigsetsize = arg5;
9911#else
9912 target_ulong sigsetsize = arg4;
Richard Henderson02fb28e2021-04-22 16:02:23 -07009913 target_ulong restorer = 0;
Peter Maydell78bfef72017-11-06 18:33:26 +00009914#endif
Richard Hendersonfb804392021-04-22 16:02:27 -07009915 struct target_sigaction *act = NULL;
9916 struct target_sigaction *oact = NULL;
pbrook53a59602006-03-25 19:31:22 +00009917
Peter Maydell78bfef72017-11-06 18:33:26 +00009918 if (sigsetsize != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009919 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +01009920 }
Richard Hendersonfb804392021-04-22 16:02:27 -07009921 if (arg2 && !lock_user_struct(VERIFY_READ, act, arg2, 1)) {
9922 return -TARGET_EFAULT;
Peter Maydell78bfef72017-11-06 18:33:26 +00009923 }
Richard Hendersonfb804392021-04-22 16:02:27 -07009924 if (arg3 && !lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
9925 ret = -TARGET_EFAULT;
9926 } else {
9927 ret = get_errno(do_sigaction(arg1, act, oact, restorer));
9928 if (oact) {
9929 unlock_user_struct(oact, arg3, 1);
bellard579a97f2007-11-11 14:26:47 +00009930 }
Richard Hendersonfb804392021-04-22 16:02:27 -07009931 }
9932 if (act) {
pbrook53a59602006-03-25 19:31:22 +00009933 unlock_user_struct(act, arg2, 0);
Richard Hendersonfb804392021-04-22 16:02:27 -07009934 }
pbrook53a59602006-03-25 19:31:22 +00009935 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009936 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009937#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009938 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00009939 {
9940 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00009941 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009942 ret = do_sigprocmask(0, NULL, &cur_set);
9943 if (!ret) {
9944 host_to_target_old_sigset(&target_set, &cur_set);
9945 ret = target_set;
9946 }
bellard66fb9762003-03-23 01:06:05 +00009947 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009948 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009949#endif
9950#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009951 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00009952 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02009953 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00009954 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00009955 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009956 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
9957 if (!ret) {
9958 host_to_target_old_sigset(&target_set, &oset);
9959 ret = target_set;
9960 }
bellard66fb9762003-03-23 01:06:05 +00009961 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -07009962 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +00009963#endif
thse5febef2007-04-01 18:31:35 +00009964#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00009965 case TARGET_NR_sigprocmask:
9966 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07009967#if defined(TARGET_ALPHA)
9968 sigset_t set, oldset;
9969 abi_ulong mask;
9970 int how;
9971
9972 switch (arg1) {
9973 case TARGET_SIG_BLOCK:
9974 how = SIG_BLOCK;
9975 break;
9976 case TARGET_SIG_UNBLOCK:
9977 how = SIG_UNBLOCK;
9978 break;
9979 case TARGET_SIG_SETMASK:
9980 how = SIG_SETMASK;
9981 break;
9982 default:
Richard Henderson259841c2018-08-18 12:01:09 -07009983 return -TARGET_EINVAL;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009984 }
9985 mask = arg2;
9986 target_to_host_old_sigset(&set, &mask);
9987
Peter Maydell3d3efba2016-05-27 15:51:49 +01009988 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07009989 if (!is_error(ret)) {
9990 host_to_target_old_sigset(&mask, &oldset);
9991 ret = mask;
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +02009992 cpu_env->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07009993 }
9994#else
bellard66fb9762003-03-23 01:06:05 +00009995 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009996 int how;
ths3b46e622007-09-17 08:09:54 +00009997
pbrook53a59602006-03-25 19:31:22 +00009998 if (arg2) {
Patrick Ventureebce1712022-01-26 13:25:59 -08009999 p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
10000 if (!p) {
10001 return -TARGET_EFAULT;
10002 }
10003 target_to_host_old_sigset(&set, p);
10004 unlock_user(p, arg2, 0);
10005 set_ptr = &set;
Richard Hendersona5b3b132010-05-03 10:07:55 -070010006 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +000010007 case TARGET_SIG_BLOCK:
10008 how = SIG_BLOCK;
10009 break;
10010 case TARGET_SIG_UNBLOCK:
10011 how = SIG_UNBLOCK;
10012 break;
10013 case TARGET_SIG_SETMASK:
10014 how = SIG_SETMASK;
10015 break;
10016 default:
Richard Henderson259841c2018-08-18 12:01:09 -070010017 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +000010018 }
bellard66fb9762003-03-23 01:06:05 +000010019 } else {
10020 how = 0;
10021 set_ptr = NULL;
10022 }
Peter Maydell3d3efba2016-05-27 15:51:49 +010010023 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +000010024 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -050010025 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010026 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010027 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -050010028 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +000010029 }
Richard Hendersona5b3b132010-05-03 10:07:55 -070010030#endif
bellard66fb9762003-03-23 01:06:05 +000010031 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010032 return ret;
thse5febef2007-04-01 18:31:35 +000010033#endif
bellard66fb9762003-03-23 01:06:05 +000010034 case TARGET_NR_rt_sigprocmask:
10035 {
10036 int how = arg1;
10037 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +000010038
Peter Maydellc8157012016-06-30 14:23:24 +010010039 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010040 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +010010041 }
10042
pbrook53a59602006-03-25 19:31:22 +000010043 if (arg2) {
Shu-Chun Wengd3ced2a2022-01-26 13:25:58 -080010044 p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
10045 if (!p) {
10046 return -TARGET_EFAULT;
10047 }
10048 target_to_host_sigset(&set, p);
10049 unlock_user(p, arg2, 0);
10050 set_ptr = &set;
bellard66fb9762003-03-23 01:06:05 +000010051 switch(how) {
10052 case TARGET_SIG_BLOCK:
10053 how = SIG_BLOCK;
10054 break;
10055 case TARGET_SIG_UNBLOCK:
10056 how = SIG_UNBLOCK;
10057 break;
10058 case TARGET_SIG_SETMASK:
10059 how = SIG_SETMASK;
10060 break;
10061 default:
Richard Henderson259841c2018-08-18 12:01:09 -070010062 return -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +000010063 }
bellard66fb9762003-03-23 01:06:05 +000010064 } else {
10065 how = 0;
10066 set_ptr = NULL;
10067 }
Peter Maydell3d3efba2016-05-27 15:51:49 +010010068 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +000010069 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -050010070 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010071 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010072 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -050010073 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +000010074 }
10075 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010076 return ret;
thse5febef2007-04-01 18:31:35 +000010077#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +000010078 case TARGET_NR_sigpending:
10079 {
10080 sigset_t set;
10081 ret = get_errno(sigpending(&set));
10082 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -050010083 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010084 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010085 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -050010086 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +000010087 }
10088 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010089 return ret;
thse5febef2007-04-01 18:31:35 +000010090#endif
bellard66fb9762003-03-23 01:06:05 +000010091 case TARGET_NR_rt_sigpending:
10092 {
10093 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +010010094
10095 /* Yes, this check is >, not != like most. We follow the kernel's
10096 * logic and it does it like this because it implements
10097 * NR_sigpending through the same code path, and in that case
10098 * the old_sigset_t is smaller in size.
10099 */
10100 if (arg2 > sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010101 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +010010102 }
10103
bellard66fb9762003-03-23 01:06:05 +000010104 ret = get_errno(sigpending(&set));
10105 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -050010106 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010107 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010108 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -050010109 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +000010110 }
10111 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010112 return ret;
thse5febef2007-04-01 18:31:35 +000010113#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +000010114 case TARGET_NR_sigsuspend:
10115 {
Richard Henderson0a99f092022-03-15 01:43:05 -070010116 sigset_t *set;
10117
Richard Hendersonf43ce122010-05-03 10:07:54 -070010118#if defined(TARGET_ALPHA)
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +000010119 TaskState *ts = get_task_state(cpu);
Richard Henderson7fb5ef32022-03-15 01:43:04 -070010120 /* target_to_host_old_sigset will bswap back */
10121 abi_ulong mask = tswapal(arg1);
Richard Henderson0a99f092022-03-15 01:43:05 -070010122 set = &ts->sigsuspend_mask;
10123 target_to_host_old_sigset(set, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -070010124#else
Richard Henderson0a99f092022-03-15 01:43:05 -070010125 ret = process_sigsuspend_mask(&set, arg1, sizeof(target_sigset_t));
10126 if (ret != 0) {
10127 return ret;
Peter Maydell3d3efba2016-05-27 15:51:49 +010010128 }
Richard Henderson0a99f092022-03-15 01:43:05 -070010129#endif
10130 ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
10131 finish_sigsuspend_mask(ret);
bellard66fb9762003-03-23 01:06:05 +000010132 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010133 return ret;
thse5febef2007-04-01 18:31:35 +000010134#endif
bellard66fb9762003-03-23 01:06:05 +000010135 case TARGET_NR_rt_sigsuspend:
10136 {
Richard Henderson0a99f092022-03-15 01:43:05 -070010137 sigset_t *set;
Peter Maydellc8157012016-06-30 14:23:24 +010010138
Richard Henderson0a99f092022-03-15 01:43:05 -070010139 ret = process_sigsuspend_mask(&set, arg1, arg2);
10140 if (ret != 0) {
10141 return ret;
Peter Maydellc8157012016-06-30 14:23:24 +010010142 }
Richard Henderson0a99f092022-03-15 01:43:05 -070010143 ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
10144 finish_sigsuspend_mask(ret);
bellard66fb9762003-03-23 01:06:05 +000010145 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010146 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010147#ifdef TARGET_NR_rt_sigtimedwait
bellard66fb9762003-03-23 01:06:05 +000010148 case TARGET_NR_rt_sigtimedwait:
10149 {
bellard66fb9762003-03-23 01:06:05 +000010150 sigset_t set;
10151 struct timespec uts, *puts;
10152 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +000010153
Peter Maydellc8157012016-06-30 14:23:24 +010010154 if (arg4 != sizeof(target_sigset_t)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010155 return -TARGET_EINVAL;
Peter Maydellc8157012016-06-30 14:23:24 +010010156 }
10157
Anthony Liguoric227f092009-10-01 16:12:16 -050010158 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010159 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010160 target_to_host_sigset(&set, p);
10161 unlock_user(p, arg1, 0);
10162 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +000010163 puts = &uts;
Filip Bozuta4d213002020-07-24 20:16:51 +020010164 if (target_to_host_timespec(puts, arg3)) {
10165 return -TARGET_EFAULT;
10166 }
bellard66fb9762003-03-23 01:06:05 +000010167 } else {
10168 puts = NULL;
10169 }
Peter Maydellb3f82332016-06-06 19:58:08 +010010170 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
10171 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +010010172 if (!is_error(ret)) {
10173 if (arg2) {
10174 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
10175 0);
10176 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010177 return -TARGET_EFAULT;
Petar Jovanovic974a1962014-03-03 15:07:41 +010010178 }
10179 host_to_target_siginfo(p, &uinfo);
10180 unlock_user(p, arg2, sizeof(target_siginfo_t));
10181 }
10182 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +000010183 }
10184 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010185 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010186#endif
Filip Bozutaddcbde12020-08-24 21:21:16 +020010187#ifdef TARGET_NR_rt_sigtimedwait_time64
10188 case TARGET_NR_rt_sigtimedwait_time64:
10189 {
10190 sigset_t set;
10191 struct timespec uts, *puts;
10192 siginfo_t uinfo;
10193
10194 if (arg4 != sizeof(target_sigset_t)) {
10195 return -TARGET_EINVAL;
10196 }
10197
10198 p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
10199 if (!p) {
10200 return -TARGET_EFAULT;
10201 }
10202 target_to_host_sigset(&set, p);
10203 unlock_user(p, arg1, 0);
10204 if (arg3) {
10205 puts = &uts;
10206 if (target_to_host_timespec64(puts, arg3)) {
10207 return -TARGET_EFAULT;
10208 }
10209 } else {
10210 puts = NULL;
10211 }
10212 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
10213 SIGSET_T_SIZE));
10214 if (!is_error(ret)) {
10215 if (arg2) {
10216 p = lock_user(VERIFY_WRITE, arg2,
10217 sizeof(target_siginfo_t), 0);
10218 if (!p) {
10219 return -TARGET_EFAULT;
10220 }
10221 host_to_target_siginfo(p, &uinfo);
10222 unlock_user(p, arg2, sizeof(target_siginfo_t));
10223 }
10224 ret = host_to_target_signal(ret);
10225 }
10226 }
10227 return ret;
10228#endif
bellard66fb9762003-03-23 01:06:05 +000010229 case TARGET_NR_rt_sigqueueinfo:
10230 {
10231 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +010010232
10233 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
10234 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010235 return -TARGET_EFAULT;
Peter Maydell4debae62016-06-20 15:50:36 +010010236 }
pbrook53a59602006-03-25 19:31:22 +000010237 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +020010238 unlock_user(p, arg3, 0);
fanwenjie9b9145f2022-08-31 11:55:25 +080010239 ret = get_errno(sys_rt_sigqueueinfo(arg1, target_to_host_signal(arg2), &uinfo));
bellard66fb9762003-03-23 01:06:05 +000010240 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010241 return ret;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +020010242 case TARGET_NR_rt_tgsigqueueinfo:
10243 {
10244 siginfo_t uinfo;
10245
10246 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
10247 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010248 return -TARGET_EFAULT;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +020010249 }
10250 target_to_host_siginfo(&uinfo, p);
10251 unlock_user(p, arg4, 0);
fanwenjie9b9145f2022-08-31 11:55:25 +080010252 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, target_to_host_signal(arg3), &uinfo));
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +020010253 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010254 return ret;
thse5febef2007-04-01 18:31:35 +000010255#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +000010256 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +010010257 if (block_signals()) {
Richard Hendersonaf254a22021-11-22 19:47:33 +010010258 return -QEMU_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +010010259 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010260 return do_sigreturn(cpu_env);
thse5febef2007-04-01 18:31:35 +000010261#endif
bellard66fb9762003-03-23 01:06:05 +000010262 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +010010263 if (block_signals()) {
Richard Hendersonaf254a22021-11-22 19:47:33 +010010264 return -QEMU_ERESTARTSYS;
Peter Maydell3d3efba2016-05-27 15:51:49 +010010265 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010266 return do_rt_sigreturn(cpu_env);
bellard31e31b82003-02-18 22:55:36 +000010267 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +000010268 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010269 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010270 ret = get_errno(sethostname(p, arg2));
10271 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010272 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010273#ifdef TARGET_NR_setrlimit
bellard31e31b82003-02-18 22:55:36 +000010274 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +000010275 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010276 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +000010277 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +000010278 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +000010279 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010280 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010281 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
10282 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010283 unlock_user_struct(target_rlim, arg2, 0);
Max Filippov5dfa88f2018-09-17 11:13:14 -070010284 /*
10285 * If we just passed through resource limit settings for memory then
10286 * they would also apply to QEMU's own allocations, and QEMU will
10287 * crash or hang or die if its allocations fail. Ideally we would
10288 * track the guest allocations in QEMU and apply the limits ourselves.
10289 * For now, just tell the guest the call succeeded but don't actually
10290 * limit anything.
10291 */
10292 if (resource != RLIMIT_AS &&
10293 resource != RLIMIT_DATA &&
10294 resource != RLIMIT_STACK) {
10295 return get_errno(setrlimit(resource, &rlim));
10296 } else {
10297 return 0;
10298 }
bellard9de5e442003-03-23 16:49:39 +000010299 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010300#endif
10301#ifdef TARGET_NR_getrlimit
bellard31e31b82003-02-18 22:55:36 +000010302 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +000010303 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010304 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +000010305 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +000010306 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +000010307
bellard9de5e442003-03-23 16:49:39 +000010308 ret = get_errno(getrlimit(resource, &rlim));
10309 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010310 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010311 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010312 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10313 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010314 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +000010315 }
10316 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010317 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010318#endif
bellard31e31b82003-02-18 22:55:36 +000010319 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +000010320 {
10321 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +000010322 ret = get_errno(getrusage(arg1, &rusage));
10323 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +020010324 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +000010325 }
10326 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010327 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010328#if defined(TARGET_NR_gettimeofday)
bellard31e31b82003-02-18 22:55:36 +000010329 case TARGET_NR_gettimeofday:
10330 {
bellard31e31b82003-02-18 22:55:36 +000010331 struct timeval tv;
Richard Hendersona52f5f82020-02-12 19:22:23 -080010332 struct timezone tz;
10333
10334 ret = get_errno(gettimeofday(&tv, &tz));
bellard31e31b82003-02-18 22:55:36 +000010335 if (!is_error(ret)) {
Richard Hendersona52f5f82020-02-12 19:22:23 -080010336 if (arg1 && copy_to_user_timeval(arg1, &tv)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010337 return -TARGET_EFAULT;
Richard Hendersona52f5f82020-02-12 19:22:23 -080010338 }
10339 if (arg2 && copy_to_user_timezone(arg2, &tz)) {
10340 return -TARGET_EFAULT;
10341 }
bellard31e31b82003-02-18 22:55:36 +000010342 }
10343 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010344 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010345#endif
10346#if defined(TARGET_NR_settimeofday)
bellard31e31b82003-02-18 22:55:36 +000010347 case TARGET_NR_settimeofday:
10348 {
Paul Burtonb67d8032014-06-22 11:25:41 +010010349 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +010010350 struct timezone tz, *ptz = NULL;
10351
Paul Burtonb67d8032014-06-22 11:25:41 +010010352 if (arg1) {
10353 if (copy_from_user_timeval(&tv, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010354 return -TARGET_EFAULT;
Paul Burtonb67d8032014-06-22 11:25:41 +010010355 }
10356 ptv = &tv;
10357 }
Paul Burtonef4467e2014-06-22 11:25:40 +010010358
10359 if (arg2) {
10360 if (copy_from_user_timezone(&tz, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010361 return -TARGET_EFAULT;
Paul Burtonef4467e2014-06-22 11:25:40 +010010362 }
10363 ptz = &tz;
10364 }
10365
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010366 return get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +000010367 }
Alistair Francis859e8a82020-03-12 15:13:49 -070010368#endif
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010369#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +000010370 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +020010371#if defined(TARGET_WANT_NI_OLD_SELECT)
10372 /* some architectures used to have old_select here
10373 * but now ENOSYS it.
10374 */
10375 ret = -TARGET_ENOSYS;
10376#elif defined(TARGET_WANT_OLD_SYS_SELECT)
10377 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010378#else
Laurent Vivier5457dc92016-07-08 01:17:27 +020010379 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010380#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010381 return ret;
bellard048f6b42005-11-26 18:47:20 +000010382#endif
Riku Voipio9e423822010-05-07 12:28:05 +000010383#ifdef TARGET_NR_pselect6
10384 case TARGET_NR_pselect6:
Filip Bozutae5ce9682020-08-25 00:30:49 +020010385 return do_pselect6(arg1, arg2, arg3, arg4, arg5, arg6, false);
10386#endif
10387#ifdef TARGET_NR_pselect6_time64
10388 case TARGET_NR_pselect6_time64:
10389 return do_pselect6(arg1, arg2, arg3, arg4, arg5, arg6, true);
Riku Voipio9e423822010-05-07 12:28:05 +000010390#endif
Chen Gang704eff62015-08-21 05:37:33 +080010391#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +000010392 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +000010393 {
10394 void *p2;
10395 p = lock_user_string(arg1);
10396 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +000010397 if (!p || !p2)
10398 ret = -TARGET_EFAULT;
10399 else
10400 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +000010401 unlock_user(p2, arg2, 0);
10402 unlock_user(p, arg1, 0);
10403 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010404 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010405#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010406#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +000010407 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +000010408 {
bellard579a97f2007-11-11 14:26:47 +000010409 void *p2;
thsf0b62432007-09-24 09:25:40 +000010410 p = lock_user_string(arg1);
10411 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +000010412 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +000010413 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +000010414 else
Peter Maydellc0d472b2013-06-12 16:20:21 +010010415 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +000010416 unlock_user(p2, arg3, 0);
10417 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +000010418 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010419 return ret;
thsf0b62432007-09-24 09:25:40 +000010420#endif
Chen Gang704eff62015-08-21 05:37:33 +080010421#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +000010422 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +000010423 {
Andreas Schwab463d8e72013-07-02 14:04:12 +010010424 void *p2;
pbrook53a59602006-03-25 19:31:22 +000010425 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +000010426 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Ilya Leoshkevicha4dab0a2023-06-30 19:04:16 +010010427 ret = get_errno(do_guest_readlink(p, p2, arg3));
pbrook53a59602006-03-25 19:31:22 +000010428 unlock_user(p2, arg2, ret);
10429 unlock_user(p, arg1, 0);
10430 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010431 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010432#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010433#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +000010434 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +000010435 {
bellard579a97f2007-11-11 14:26:47 +000010436 void *p2;
ths5e0ccb12007-09-24 09:26:10 +000010437 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +000010438 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +010010439 if (!p || !p2) {
10440 ret = -TARGET_EFAULT;
Jameson Nash65d48302022-08-08 15:07:27 -040010441 } else if (!arg4) {
10442 /* Short circuit this for the magic exe check. */
10443 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +010010444 } else if (is_proc_myself((const char *)p, "exe")) {
Helge Deller258bec32022-12-05 12:38:25 +010010445 /*
10446 * Don't worry about sign mismatch as earlier mapping
10447 * logic would have thrown a bad address error.
10448 */
10449 ret = MIN(strlen(exec_path), arg4);
10450 /* We cannot NUL terminate the string. */
10451 memcpy(p2, exec_path, ret);
Andreas Schwab463d8e72013-07-02 14:04:12 +010010452 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +010010453 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +010010454 }
bellard579a97f2007-11-11 14:26:47 +000010455 unlock_user(p2, arg3, ret);
10456 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +000010457 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010458 return ret;
ths5e0ccb12007-09-24 09:26:10 +000010459#endif
thse5febef2007-04-01 18:31:35 +000010460#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +000010461 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +000010462 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010463 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010464 ret = get_errno(swapon(p, arg2));
10465 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010466 return ret;
thse5febef2007-04-01 18:31:35 +000010467#endif
bellard31e31b82003-02-18 22:55:36 +000010468 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +000010469 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
10470 /* arg4 must be ignored in all other cases */
10471 p = lock_user_string(arg4);
10472 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010473 return -TARGET_EFAULT;
Laurent Vivierc07ecc62013-01-07 11:40:06 +000010474 }
10475 ret = get_errno(reboot(arg1, arg2, arg3, p));
10476 unlock_user(p, arg4, 0);
10477 } else {
10478 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
10479 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010480 return ret;
thse5febef2007-04-01 18:31:35 +000010481#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +000010482 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +010010483#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
10484 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Philippe Mathieu-Daudébff4b022024-07-24 13:47:57 +020010485 defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) \
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010486 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +000010487 {
blueswir1992f48a2007-10-14 16:27:31 +000010488 abi_ulong *v;
10489 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +000010490 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010491 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010492 v1 = tswapal(v[0]);
10493 v2 = tswapal(v[1]);
10494 v3 = tswapal(v[2]);
10495 v4 = tswapal(v[3]);
10496 v5 = tswapal(v[4]);
10497 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +000010498 unlock_user(v, arg1, 0);
Richard Henderson9ab8d0712023-08-07 18:22:35 -070010499 return do_mmap(v1, v2, v3, v4, v5, v6);
bellard31e31b82003-02-18 22:55:36 +000010500 }
bellard31e31b82003-02-18 22:55:36 +000010501#else
Richard Hendersonee1bf832021-02-12 10:48:44 -080010502 /* mmap pointers are always untagged */
Richard Henderson9ab8d0712023-08-07 18:22:35 -070010503 return do_mmap(arg1, arg2, arg3, arg4, arg5, arg6);
bellard31e31b82003-02-18 22:55:36 +000010504#endif
thse5febef2007-04-01 18:31:35 +000010505#endif
bellarda315a142005-01-30 22:59:18 +000010506#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +000010507 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +000010508#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +000010509#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +000010510#endif
Richard Henderson9ab8d0712023-08-07 18:22:35 -070010511 return do_mmap(arg1, arg2, arg3, arg4, arg5,
10512 (off_t)(abi_ulong)arg6 << MMAP_SHIFT);
bellarda315a142005-01-30 22:59:18 +000010513#endif
bellard31e31b82003-02-18 22:55:36 +000010514 case TARGET_NR_munmap:
Richard Hendersonee1bf832021-02-12 10:48:44 -080010515 arg1 = cpu_untagged_addr(cpu, arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010516 return get_errno(target_munmap(arg1, arg2));
bellard9de5e442003-03-23 16:49:39 +000010517 case TARGET_NR_mprotect:
Richard Hendersonee1bf832021-02-12 10:48:44 -080010518 arg1 = cpu_untagged_addr(cpu, arg1);
Paul Brook97374d32010-06-16 13:03:51 +010010519 {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +000010520 TaskState *ts = get_task_state(cpu);
Paul Brook97374d32010-06-16 13:03:51 +010010521 /* Special hack to detect libc making the stack executable. */
10522 if ((arg3 & PROT_GROWSDOWN)
10523 && arg1 >= ts->info->stack_limit
10524 && arg1 <= ts->info->start_stack) {
10525 arg3 &= ~PROT_GROWSDOWN;
10526 arg2 = arg2 + arg1 - ts->info->stack_limit;
10527 arg1 = ts->info->stack_limit;
10528 }
10529 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010530 return get_errno(target_mprotect(arg1, arg2, arg3));
thse5febef2007-04-01 18:31:35 +000010531#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +000010532 case TARGET_NR_mremap:
Richard Hendersonee1bf832021-02-12 10:48:44 -080010533 arg1 = cpu_untagged_addr(cpu, arg1);
10534 /* mremap new_addr (arg5) is always untagged */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010535 return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
thse5febef2007-04-01 18:31:35 +000010536#endif
pbrook53a59602006-03-25 19:31:22 +000010537 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +000010538#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +000010539 case TARGET_NR_msync:
Helge Dellerfe080592022-12-15 08:27:46 +010010540 return get_errno(msync(g2h(cpu, arg1), arg2,
10541 target_to_host_msync_arg(arg3)));
thse5febef2007-04-01 18:31:35 +000010542#endif
10543#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +000010544 case TARGET_NR_mlock:
Richard Henderson3e8f1622021-02-12 10:48:43 -080010545 return get_errno(mlock(g2h(cpu, arg1), arg2));
thse5febef2007-04-01 18:31:35 +000010546#endif
10547#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +000010548 case TARGET_NR_munlock:
Richard Henderson3e8f1622021-02-12 10:48:43 -080010549 return get_errno(munlock(g2h(cpu, arg1), arg2));
thse5febef2007-04-01 18:31:35 +000010550#endif
10551#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +000010552 case TARGET_NR_mlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010553 return get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
thse5febef2007-04-01 18:31:35 +000010554#endif
10555#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +000010556 case TARGET_NR_munlockall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010557 return get_errno(munlockall());
thse5febef2007-04-01 18:31:35 +000010558#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010559#ifdef TARGET_NR_truncate
bellard31e31b82003-02-18 22:55:36 +000010560 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +000010561 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010562 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010563 ret = get_errno(truncate(p, arg2));
10564 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010565 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010566#endif
10567#ifdef TARGET_NR_ftruncate
bellard31e31b82003-02-18 22:55:36 +000010568 case TARGET_NR_ftruncate:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010569 return get_errno(ftruncate(arg1, arg2));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010570#endif
bellard31e31b82003-02-18 22:55:36 +000010571 case TARGET_NR_fchmod:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010572 return get_errno(fchmod(arg1, arg2));
Peter Maydellc0d472b2013-06-12 16:20:21 +010010573#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +000010574 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +000010575 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010576 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010577 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +000010578 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010579 return ret;
ths814d7972007-09-24 09:26:51 +000010580#endif
bellard31e31b82003-02-18 22:55:36 +000010581 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -070010582 /* Note that negative values are valid for getpriority, so we must
10583 differentiate based on errno settings. */
10584 errno = 0;
10585 ret = getpriority(arg1, arg2);
10586 if (ret == -1 && errno != 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010587 return -host_to_target_errno(errno);
Richard Henderson95c09822012-06-07 15:14:50 -070010588 }
10589#ifdef TARGET_ALPHA
10590 /* Return value is the unbiased priority. Signal no error. */
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020010591 cpu_env->ir[IR_V0] = 0;
Richard Henderson95c09822012-06-07 15:14:50 -070010592#else
10593 /* Return value is a biased priority to avoid negative numbers. */
10594 ret = 20 - ret;
10595#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010596 return ret;
bellard31e31b82003-02-18 22:55:36 +000010597 case TARGET_NR_setpriority:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010598 return get_errno(setpriority(arg1, arg2, arg3));
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010599#ifdef TARGET_NR_statfs
bellard31e31b82003-02-18 22:55:36 +000010600 case TARGET_NR_statfs:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010601 if (!(p = lock_user_string(arg1))) {
10602 return -TARGET_EFAULT;
10603 }
pbrook53a59602006-03-25 19:31:22 +000010604 ret = get_errno(statfs(path(p), &stfs));
10605 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010606 convert_statfs:
10607 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010608 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +000010609
bellard579a97f2007-11-11 14:26:47 +000010610 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010611 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010612 __put_user(stfs.f_type, &target_stfs->f_type);
10613 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
10614 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
10615 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
10616 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
10617 __put_user(stfs.f_files, &target_stfs->f_files);
10618 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
10619 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
10620 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
10621 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +020010622 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -050010623#ifdef _STATFS_F_FLAGS
10624 __put_user(stfs.f_flags, &target_stfs->f_flags);
10625#else
10626 __put_user(0, &target_stfs->f_flags);
10627#endif
Alexander Graf229d3372012-09-19 04:39:53 +020010628 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +000010629 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +000010630 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010631 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010632#endif
10633#ifdef TARGET_NR_fstatfs
bellard31e31b82003-02-18 22:55:36 +000010634 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +000010635 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +000010636 goto convert_statfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010637#endif
bellard56c8f682005-11-28 22:28:41 +000010638#ifdef TARGET_NR_statfs64
10639 case TARGET_NR_statfs64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010640 if (!(p = lock_user_string(arg1))) {
10641 return -TARGET_EFAULT;
10642 }
pbrook53a59602006-03-25 19:31:22 +000010643 ret = get_errno(statfs(path(p), &stfs));
10644 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +000010645 convert_statfs64:
10646 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010647 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +000010648
bellard579a97f2007-11-11 14:26:47 +000010649 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010650 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010651 __put_user(stfs.f_type, &target_stfs->f_type);
10652 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
10653 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
10654 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
10655 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
10656 __put_user(stfs.f_files, &target_stfs->f_files);
10657 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
10658 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
10659 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
10660 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +020010661 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Frajob94e2b42020-01-30 15:00:30 +020010662#ifdef _STATFS_F_FLAGS
10663 __put_user(stfs.f_flags, &target_stfs->f_flags);
10664#else
10665 __put_user(0, &target_stfs->f_flags);
10666#endif
Alexander Graf229d3372012-09-19 04:39:53 +020010667 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +000010668 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +000010669 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010670 return ret;
bellard56c8f682005-11-28 22:28:41 +000010671 case TARGET_NR_fstatfs64:
10672 ret = get_errno(fstatfs(arg1, &stfs));
10673 goto convert_statfs64;
10674#endif
thse5febef2007-04-01 18:31:35 +000010675#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +000010676 case TARGET_NR_socketcall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010677 return do_socketcall(arg1, arg2);
thse5febef2007-04-01 18:31:35 +000010678#endif
bellard3532fa72006-06-24 15:06:03 +000010679#ifdef TARGET_NR_accept
10680 case TARGET_NR_accept:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010681 return do_accept4(arg1, arg2, arg3, 0);
Peter Maydella94b4982013-02-08 04:35:04 +000010682#endif
10683#ifdef TARGET_NR_accept4
10684 case TARGET_NR_accept4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010685 return do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +000010686#endif
10687#ifdef TARGET_NR_bind
10688 case TARGET_NR_bind:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010689 return do_bind(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +000010690#endif
10691#ifdef TARGET_NR_connect
10692 case TARGET_NR_connect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010693 return do_connect(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +000010694#endif
10695#ifdef TARGET_NR_getpeername
10696 case TARGET_NR_getpeername:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010697 return do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +000010698#endif
10699#ifdef TARGET_NR_getsockname
10700 case TARGET_NR_getsockname:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010701 return do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +000010702#endif
10703#ifdef TARGET_NR_getsockopt
10704 case TARGET_NR_getsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010705 return do_getsockopt(arg1, arg2, arg3, arg4, arg5);
bellard3532fa72006-06-24 15:06:03 +000010706#endif
10707#ifdef TARGET_NR_listen
10708 case TARGET_NR_listen:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010709 return get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +000010710#endif
10711#ifdef TARGET_NR_recv
10712 case TARGET_NR_recv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010713 return do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +000010714#endif
10715#ifdef TARGET_NR_recvfrom
10716 case TARGET_NR_recvfrom:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010717 return do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +000010718#endif
10719#ifdef TARGET_NR_recvmsg
10720 case TARGET_NR_recvmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010721 return do_sendrecvmsg(arg1, arg2, arg3, 0);
bellard3532fa72006-06-24 15:06:03 +000010722#endif
10723#ifdef TARGET_NR_send
10724 case TARGET_NR_send:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010725 return do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +000010726#endif
10727#ifdef TARGET_NR_sendmsg
10728 case TARGET_NR_sendmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010729 return do_sendrecvmsg(arg1, arg2, arg3, 1);
bellard3532fa72006-06-24 15:06:03 +000010730#endif
Alexander Graff19e00d2014-03-02 19:36:42 +000010731#ifdef TARGET_NR_sendmmsg
10732 case TARGET_NR_sendmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010733 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
Alistair Francis859e8a82020-03-12 15:13:49 -070010734#endif
10735#ifdef TARGET_NR_recvmmsg
Alexander Graff19e00d2014-03-02 19:36:42 +000010736 case TARGET_NR_recvmmsg:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010737 return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
Alexander Graff19e00d2014-03-02 19:36:42 +000010738#endif
bellard3532fa72006-06-24 15:06:03 +000010739#ifdef TARGET_NR_sendto
10740 case TARGET_NR_sendto:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010741 return do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +000010742#endif
10743#ifdef TARGET_NR_shutdown
10744 case TARGET_NR_shutdown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010745 return get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +000010746#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +010010747#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
10748 case TARGET_NR_getrandom:
10749 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10750 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070010751 return -TARGET_EFAULT;
Laurent Vivierf894efd2016-02-21 10:56:23 +010010752 }
10753 ret = get_errno(getrandom(p, arg2, arg3));
10754 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010755 return ret;
Laurent Vivierf894efd2016-02-21 10:56:23 +010010756#endif
bellard3532fa72006-06-24 15:06:03 +000010757#ifdef TARGET_NR_socket
10758 case TARGET_NR_socket:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010759 return do_socket(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +000010760#endif
10761#ifdef TARGET_NR_socketpair
10762 case TARGET_NR_socketpair:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010763 return do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +000010764#endif
10765#ifdef TARGET_NR_setsockopt
10766 case TARGET_NR_setsockopt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010767 return do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
bellard3532fa72006-06-24 15:06:03 +000010768#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010769#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +000010770 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010771 {
10772 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +000010773
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010774 switch (arg1) {
10775 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
10776 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
10777 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
10778 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
10779 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
10780 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
10781 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
10782 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010783 return get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010784 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
10785 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
10786 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
10787 {
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010788 if (len < 0) {
Richard Henderson259841c2018-08-18 12:01:09 -070010789 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010790 }
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010791 if (len == 0) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010792 return 0;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010793 }
10794 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10795 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -070010796 return -TARGET_EFAULT;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010797 }
10798 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
10799 unlock_user(p, arg2, arg3);
10800 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010801 return ret;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010802 default:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010803 return -TARGET_EINVAL;
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +020010804 }
10805 }
10806 break;
10807#endif
bellard31e31b82003-02-18 22:55:36 +000010808 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +000010809 {
bellard66fb9762003-03-23 01:06:05 +000010810 struct itimerval value, ovalue, *pvalue;
10811
pbrook53a59602006-03-25 19:31:22 +000010812 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +000010813 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +000010814 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
10815 || copy_from_user_timeval(&pvalue->it_value,
10816 arg2 + sizeof(struct target_timeval)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010817 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +000010818 } else {
10819 pvalue = NULL;
10820 }
10821 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +000010822 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +000010823 if (copy_to_user_timeval(arg3,
10824 &ovalue.it_interval)
10825 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
10826 &ovalue.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010827 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +000010828 }
10829 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010830 return ret;
bellard31e31b82003-02-18 22:55:36 +000010831 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +000010832 {
bellard66fb9762003-03-23 01:06:05 +000010833 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +000010834
bellard66fb9762003-03-23 01:06:05 +000010835 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +000010836 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +000010837 if (copy_to_user_timeval(arg2,
10838 &value.it_interval)
10839 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
10840 &value.it_value))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010841 return -TARGET_EFAULT;
bellard66fb9762003-03-23 01:06:05 +000010842 }
10843 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010844 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080010845#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +000010846 case TARGET_NR_stat:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010847 if (!(p = lock_user_string(arg1))) {
10848 return -TARGET_EFAULT;
10849 }
pbrook53a59602006-03-25 19:31:22 +000010850 ret = get_errno(stat(path(p), &st));
10851 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010852 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +080010853#endif
10854#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +000010855 case TARGET_NR_lstat:
Richard Henderson2852aaf2018-08-18 12:01:06 -070010856 if (!(p = lock_user_string(arg1))) {
10857 return -TARGET_EFAULT;
10858 }
pbrook53a59602006-03-25 19:31:22 +000010859 ret = get_errno(lstat(path(p), &st));
10860 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010861 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +080010862#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010863#ifdef TARGET_NR_fstat
bellard31e31b82003-02-18 22:55:36 +000010864 case TARGET_NR_fstat:
10865 {
10866 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +080010867#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +000010868 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +080010869#endif
bellard31e31b82003-02-18 22:55:36 +000010870 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010871 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +000010872
bellard579a97f2007-11-11 14:26:47 +000010873 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010874 return -TARGET_EFAULT;
Ulrich Hecht12727912009-07-24 19:10:32 +020010875 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +000010876 __put_user(st.st_dev, &target_st->st_dev);
10877 __put_user(st.st_ino, &target_st->st_ino);
10878 __put_user(st.st_mode, &target_st->st_mode);
10879 __put_user(st.st_uid, &target_st->st_uid);
10880 __put_user(st.st_gid, &target_st->st_gid);
10881 __put_user(st.st_nlink, &target_st->st_nlink);
10882 __put_user(st.st_rdev, &target_st->st_rdev);
10883 __put_user(st.st_size, &target_st->st_size);
10884 __put_user(st.st_blksize, &target_st->st_blksize);
10885 __put_user(st.st_blocks, &target_st->st_blocks);
10886 __put_user(st.st_atime, &target_st->target_st_atime);
10887 __put_user(st.st_mtime, &target_st->target_st_mtime);
10888 __put_user(st.st_ctime, &target_st->target_st_ctime);
Michael Forneyfebf6fa2021-05-25 20:55:31 -070010889#if defined(HAVE_STRUCT_STAT_ST_ATIM) && defined(TARGET_STAT_HAVE_NSEC)
Chen-Yu Tsai5f992db2019-05-23 00:21:47 +080010890 __put_user(st.st_atim.tv_nsec,
10891 &target_st->target_st_atime_nsec);
10892 __put_user(st.st_mtim.tv_nsec,
10893 &target_st->target_st_mtime_nsec);
10894 __put_user(st.st_ctim.tv_nsec,
10895 &target_st->target_st_ctime_nsec);
10896#endif
pbrook53a59602006-03-25 19:31:22 +000010897 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +000010898 }
10899 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010900 return ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010901#endif
bellard31e31b82003-02-18 22:55:36 +000010902 case TARGET_NR_vhangup:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010903 return get_errno(vhangup());
bellard42ad6ae2005-01-03 22:48:11 +000010904#ifdef TARGET_NR_syscall
10905 case TARGET_NR_syscall:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010906 return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
10907 arg6, arg7, arg8, 0);
bellard42ad6ae2005-01-03 22:48:11 +000010908#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070010909#if defined(TARGET_NR_wait4)
bellard31e31b82003-02-18 22:55:36 +000010910 case TARGET_NR_wait4:
10911 {
10912 int status;
blueswir1992f48a2007-10-14 16:27:31 +000010913 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +000010914 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +000010915 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +020010916 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +000010917 if (target_rusage)
10918 rusage_ptr = &rusage;
10919 else
10920 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +010010921 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +000010922 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +010010923 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +000010924 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +000010925 if (put_user_s32(status, status_ptr))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010926 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +000010927 }
Petar Jovanovica39fb272014-04-08 19:24:30 +020010928 if (target_rusage) {
10929 rusage_err = host_to_target_rusage(target_rusage, &rusage);
10930 if (rusage_err) {
10931 ret = rusage_err;
10932 }
10933 }
bellard31e31b82003-02-18 22:55:36 +000010934 }
10935 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010936 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070010937#endif
thse5febef2007-04-01 18:31:35 +000010938#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +000010939 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +000010940 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010941 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000010942 ret = get_errno(swapoff(p));
10943 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010944 return ret;
thse5febef2007-04-01 18:31:35 +000010945#endif
bellard31e31b82003-02-18 22:55:36 +000010946 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +000010947 {
pbrook53a59602006-03-25 19:31:22 +000010948 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +000010949 struct sysinfo value;
10950 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +000010951 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +000010952 {
bellard579a97f2007-11-11 14:26:47 +000010953 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070010954 return -TARGET_EFAULT;
bellarda5448a72004-06-19 16:59:03 +000010955 __put_user(value.uptime, &target_value->uptime);
10956 __put_user(value.loads[0], &target_value->loads[0]);
10957 __put_user(value.loads[1], &target_value->loads[1]);
10958 __put_user(value.loads[2], &target_value->loads[2]);
10959 __put_user(value.totalram, &target_value->totalram);
10960 __put_user(value.freeram, &target_value->freeram);
10961 __put_user(value.sharedram, &target_value->sharedram);
10962 __put_user(value.bufferram, &target_value->bufferram);
10963 __put_user(value.totalswap, &target_value->totalswap);
10964 __put_user(value.freeswap, &target_value->freeswap);
10965 __put_user(value.procs, &target_value->procs);
10966 __put_user(value.totalhigh, &target_value->totalhigh);
10967 __put_user(value.freehigh, &target_value->freehigh);
10968 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +000010969 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +000010970 }
10971 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010972 return ret;
thse5febef2007-04-01 18:31:35 +000010973#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +000010974 case TARGET_NR_ipc:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010975 return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
thse5febef2007-04-01 18:31:35 +000010976#endif
aurel32e5289082009-04-18 16:16:12 +000010977#ifdef TARGET_NR_semget
10978 case TARGET_NR_semget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010979 return get_errno(semget(arg1, arg2, arg3));
aurel32e5289082009-04-18 16:16:12 +000010980#endif
10981#ifdef TARGET_NR_semop
10982 case TARGET_NR_semop:
Filip Bozutacac46eb2020-08-25 00:30:50 +020010983 return do_semtimedop(arg1, arg2, arg3, 0, false);
Matus Kyseld8c08b12020-06-26 14:46:11 +020010984#endif
10985#ifdef TARGET_NR_semtimedop
10986 case TARGET_NR_semtimedop:
Filip Bozutacac46eb2020-08-25 00:30:50 +020010987 return do_semtimedop(arg1, arg2, arg3, arg4, false);
10988#endif
10989#ifdef TARGET_NR_semtimedop_time64
10990 case TARGET_NR_semtimedop_time64:
10991 return do_semtimedop(arg1, arg2, arg3, arg4, true);
aurel32e5289082009-04-18 16:16:12 +000010992#endif
10993#ifdef TARGET_NR_semctl
10994 case TARGET_NR_semctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010995 return do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +000010996#endif
aurel32eeb438c2008-10-13 21:08:55 +000010997#ifdef TARGET_NR_msgctl
10998 case TARGET_NR_msgctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070010999 return do_msgctl(arg1, arg2, arg3);
aurel32eeb438c2008-10-13 21:08:55 +000011000#endif
11001#ifdef TARGET_NR_msgget
11002 case TARGET_NR_msgget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011003 return get_errno(msgget(arg1, arg2));
aurel32eeb438c2008-10-13 21:08:55 +000011004#endif
11005#ifdef TARGET_NR_msgrcv
11006 case TARGET_NR_msgrcv:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011007 return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
aurel32eeb438c2008-10-13 21:08:55 +000011008#endif
11009#ifdef TARGET_NR_msgsnd
11010 case TARGET_NR_msgsnd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011011 return do_msgsnd(arg1, arg2, arg3, arg4);
aurel32eeb438c2008-10-13 21:08:55 +000011012#endif
Riku Voipio88a8c982009-04-03 10:42:00 +030011013#ifdef TARGET_NR_shmget
11014 case TARGET_NR_shmget:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011015 return get_errno(shmget(arg1, arg2, arg3));
Riku Voipio88a8c982009-04-03 10:42:00 +030011016#endif
11017#ifdef TARGET_NR_shmctl
11018 case TARGET_NR_shmctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011019 return do_shmctl(arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030011020#endif
11021#ifdef TARGET_NR_shmat
11022 case TARGET_NR_shmat:
Richard Henderson225a2062023-08-20 09:24:14 -070011023 return target_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030011024#endif
11025#ifdef TARGET_NR_shmdt
11026 case TARGET_NR_shmdt:
Richard Henderson225a2062023-08-20 09:24:14 -070011027 return target_shmdt(arg1);
Riku Voipio88a8c982009-04-03 10:42:00 +030011028#endif
bellard31e31b82003-02-18 22:55:36 +000011029 case TARGET_NR_fsync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011030 return get_errno(fsync(arg1));
bellard31e31b82003-02-18 22:55:36 +000011031 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +010011032 /* Linux manages to have three different orderings for its
11033 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
11034 * match the kernel's CONFIG_CLONE_* settings.
11035 * Microblaze is further special in that it uses a sixth
11036 * implicit argument to clone for the TLS pointer.
11037 */
11038#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020011039 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010011040#elif defined(TARGET_CLONE_BACKWARDS)
11041 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
11042#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020011043 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000011044#else
Peter Maydell4ce62432013-07-16 18:44:57 +010011045 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000011046#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011047 return ret;
bellardec86b0f2003-04-11 00:15:04 +000011048#ifdef __NR_exit_group
11049 /* new thread calls */
11050 case TARGET_NR_exit_group:
Alex Bennée708b6a62018-06-22 17:09:10 +010011051 preexit_cleanup(cpu_env, arg1);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011052 return get_errno(exit_group(arg1));
bellardec86b0f2003-04-11 00:15:04 +000011053#endif
bellard31e31b82003-02-18 22:55:36 +000011054 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000011055 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011056 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011057 ret = get_errno(setdomainname(p, arg2));
11058 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011059 return ret;
bellard31e31b82003-02-18 22:55:36 +000011060 case TARGET_NR_uname:
11061 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000011062 {
11063 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000011064
bellard579a97f2007-11-11 14:26:47 +000011065 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011066 return -TARGET_EFAULT;
bellard29e619b2004-09-13 21:41:04 +000011067 ret = get_errno(sys_uname(buf));
11068 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010011069 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000011070 emulated. */
Philippe Mathieu-Daudé871f95c2017-07-24 15:27:47 -030011071 g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
11072 sizeof(buf->machine));
pbrookc5937222006-05-14 11:30:38 +000011073 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010011074 if (qemu_uname_release && *qemu_uname_release) {
11075 g_strlcpy(buf->release, qemu_uname_release,
11076 sizeof(buf->release));
11077 }
bellard29e619b2004-09-13 21:41:04 +000011078 }
pbrook53a59602006-03-25 19:31:22 +000011079 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000011080 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011081 return ret;
bellard6dbad632003-03-16 18:05:05 +000011082#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000011083 case TARGET_NR_modify_ldt:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011084 return do_modify_ldt(cpu_env, arg1, arg2, arg3);
j_mayer84409dd2007-04-06 08:56:50 +000011085#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000011086 case TARGET_NR_vm86:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011087 return do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000011088#endif
j_mayer84409dd2007-04-06 08:56:50 +000011089#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070011090#if defined(TARGET_NR_adjtimex)
bellard31e31b82003-02-18 22:55:36 +000011091 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020011092 {
11093 struct timex host_buf;
11094
11095 if (target_to_host_timex(&host_buf, arg1) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011096 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020011097 }
11098 ret = get_errno(adjtimex(&host_buf));
11099 if (!is_error(ret)) {
11100 if (host_to_target_timex(arg1, &host_buf) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011101 return -TARGET_EFAULT;
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020011102 }
11103 }
11104 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011105 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070011106#endif
Aleksandar Markovic38860a02016-10-10 13:23:29 +020011107#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
11108 case TARGET_NR_clock_adjtime:
11109 {
Peter Maydellaab74612023-07-17 11:05:07 +010011110 struct timex htx;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020011111
Peter Maydellaab74612023-07-17 11:05:07 +010011112 if (target_to_host_timex(&htx, arg2) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011113 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020011114 }
Peter Maydellaab74612023-07-17 11:05:07 +010011115 ret = get_errno(clock_adjtime(arg1, &htx));
11116 if (!is_error(ret) && host_to_target_timex(arg2, &htx)) {
11117 return -TARGET_EFAULT;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020011118 }
11119 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011120 return ret;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020011121#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +020011122#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
11123 case TARGET_NR_clock_adjtime64:
11124 {
11125 struct timex htx;
11126
11127 if (target_to_host_timex64(&htx, arg2) != 0) {
11128 return -TARGET_EFAULT;
11129 }
11130 ret = get_errno(clock_adjtime(arg1, &htx));
11131 if (!is_error(ret) && host_to_target_timex64(arg2, &htx)) {
11132 return -TARGET_EFAULT;
11133 }
11134 }
11135 return ret;
11136#endif
bellard31e31b82003-02-18 22:55:36 +000011137 case TARGET_NR_getpgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011138 return get_errno(getpgid(arg1));
bellard31e31b82003-02-18 22:55:36 +000011139 case TARGET_NR_fchdir:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011140 return get_errno(fchdir(arg1));
bellard31e31b82003-02-18 22:55:36 +000011141 case TARGET_NR_personality:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011142 return get_errno(personality(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000011143#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000011144 case TARGET_NR__llseek:
11145 {
11146 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000011147#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010011148 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000011149 if (res == -1) {
11150 ret = get_errno(res);
11151 } else {
11152 ret = 0;
11153 }
11154#else
bellard31e31b82003-02-18 22:55:36 +000011155 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000011156#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000011157 if ((ret == 0) && put_user_s64(res, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011158 return -TARGET_EFAULT;
Peter Maydell0c1592d2011-02-22 13:02:26 +000011159 }
bellard31e31b82003-02-18 22:55:36 +000011160 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011161 return ret;
j_mayer7a3148a2007-04-05 07:13:51 +000011162#endif
Chen Gang704eff62015-08-21 05:37:33 +080011163#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000011164 case TARGET_NR_getdents:
Richard Hendersonfd08ddb2021-11-14 11:35:36 +010011165 return do_getdents(arg1, arg2, arg3);
Chen Gang704eff62015-08-21 05:37:33 +080011166#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000011167#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000011168 case TARGET_NR_getdents64:
Richard Hendersonfd08ddb2021-11-14 11:35:36 +010011169 return do_getdents64(arg1, arg2, arg3);
bellarda541f292004-04-12 20:39:29 +000011170#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010011171#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000011172 case TARGET_NR__newselect:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011173 return do_select(arg1, arg2, arg3, arg4, arg5);
thse5febef2007-04-01 18:31:35 +000011174#endif
Filip Bozutae5ce9682020-08-25 00:30:49 +020011175#ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000011176 case TARGET_NR_poll:
Filip Bozutae5ce9682020-08-25 00:30:49 +020011177 return do_ppoll(arg1, arg2, arg3, arg4, arg5, false, false);
11178#endif
11179#ifdef TARGET_NR_ppoll
Mike Frysingerd8035d42011-02-07 01:05:51 -050011180 case TARGET_NR_ppoll:
Filip Bozutae5ce9682020-08-25 00:30:49 +020011181 return do_ppoll(arg1, arg2, arg3, arg4, arg5, true, false);
11182#endif
11183#ifdef TARGET_NR_ppoll_time64
11184 case TARGET_NR_ppoll_time64:
11185 return do_ppoll(arg1, arg2, arg3, arg4, arg5, true, true);
thse5febef2007-04-01 18:31:35 +000011186#endif
bellard31e31b82003-02-18 22:55:36 +000011187 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000011188 /* NOTE: the flock constant seems to be the same for every
11189 Linux platform */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011190 return get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000011191 case TARGET_NR_readv:
11192 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011193 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
11194 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010011195 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011196 unlock_iovec(vec, arg2, arg3, 1);
11197 } else {
11198 ret = -host_to_target_errno(errno);
11199 }
bellard31e31b82003-02-18 22:55:36 +000011200 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011201 return ret;
bellard31e31b82003-02-18 22:55:36 +000011202 case TARGET_NR_writev:
11203 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011204 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11205 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010011206 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011207 unlock_iovec(vec, arg2, arg3, 0);
11208 } else {
11209 ret = -host_to_target_errno(errno);
11210 }
bellard31e31b82003-02-18 22:55:36 +000011211 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011212 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020011213#if defined(TARGET_NR_preadv)
11214 case TARGET_NR_preadv:
11215 {
11216 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
11217 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070011218 unsigned long low, high;
11219
11220 target_to_host_low_high(arg4, arg5, &low, &high);
11221 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +020011222 unlock_iovec(vec, arg2, arg3, 1);
11223 } else {
11224 ret = -host_to_target_errno(errno);
11225 }
11226 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011227 return ret;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020011228#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020011229#if defined(TARGET_NR_pwritev)
11230 case TARGET_NR_pwritev:
11231 {
11232 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11233 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070011234 unsigned long low, high;
11235
11236 target_to_host_low_high(arg4, arg5, &low, &high);
11237 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020011238 unlock_iovec(vec, arg2, arg3, 0);
11239 } else {
11240 ret = -host_to_target_errno(errno);
11241 }
11242 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011243 return ret;
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020011244#endif
bellard31e31b82003-02-18 22:55:36 +000011245 case TARGET_NR_getsid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011246 return get_errno(getsid(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000011247#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000011248 case TARGET_NR_fdatasync:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011249 return get_errno(fdatasync(arg1));
j_mayer7a3148a2007-04-05 07:13:51 +000011250#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050011251 case TARGET_NR_sched_getaffinity:
11252 {
11253 unsigned int mask_size;
11254 unsigned long *mask;
11255
11256 /*
11257 * sched_getaffinity needs multiples of ulong, so need to take
11258 * care of mismatches between target ulong and host ulong sizes.
11259 */
11260 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011261 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -050011262 }
11263 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
11264
11265 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010011266 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050011267 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
11268
11269 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010011270 if (ret > arg2) {
11271 /* More data returned than the caller's buffer will fit.
11272 * This only happens if sizeof(abi_long) < sizeof(long)
11273 * and the caller passed us a buffer holding an odd number
11274 * of abi_longs. If the host kernel is actually using the
11275 * extra 4 bytes then fail EINVAL; otherwise we can just
11276 * ignore them and only copy the interesting part.
11277 */
11278 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
11279 if (numcpus > arg2 * 8) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011280 return -TARGET_EINVAL;
Peter Maydellbe3bd282014-05-15 14:40:23 +010011281 }
11282 ret = arg2;
11283 }
11284
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010011285 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011286 return -TARGET_EFAULT;
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010011287 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050011288 }
11289 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011290 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -050011291 case TARGET_NR_sched_setaffinity:
11292 {
11293 unsigned int mask_size;
11294 unsigned long *mask;
11295
11296 /*
11297 * sched_setaffinity needs multiples of ulong, so need to take
11298 * care of mismatches between target ulong and host ulong sizes.
11299 */
11300 if (arg2 & (sizeof(abi_ulong) - 1)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011301 return -TARGET_EINVAL;
Mike Frysinger737de1d2011-02-07 01:05:55 -050011302 }
11303 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050011304 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010011305
11306 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
11307 if (ret) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011308 return ret;
Mike Frysinger737de1d2011-02-07 01:05:55 -050011309 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050011310
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011311 return get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
Mike Frysinger737de1d2011-02-07 01:05:55 -050011312 }
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010011313 case TARGET_NR_getcpu:
11314 {
Laurent Vivier9962b7c2023-09-25 17:10:28 +020011315 unsigned cpuid, node;
11316 ret = get_errno(sys_getcpu(arg1 ? &cpuid : NULL,
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010011317 arg2 ? &node : NULL,
11318 NULL));
11319 if (is_error(ret)) {
Richard Henderson259841c2018-08-18 12:01:09 -070011320 return ret;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010011321 }
Laurent Vivier9962b7c2023-09-25 17:10:28 +020011322 if (arg1 && put_user_u32(cpuid, arg1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011323 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010011324 }
11325 if (arg2 && put_user_u32(node, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011326 return -TARGET_EFAULT;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010011327 }
11328 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011329 return ret;
bellard31e31b82003-02-18 22:55:36 +000011330 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000011331 {
Tonis Tiigi407a1192022-01-04 20:18:19 -080011332 struct target_sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000011333 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000011334
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050011335 if (arg2 == 0) {
11336 return -TARGET_EINVAL;
11337 }
Tonis Tiigi407a1192022-01-04 20:18:19 -080011338 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011339 return -TARGET_EFAULT;
Tonis Tiigi407a1192022-01-04 20:18:19 -080011340 }
bellard5cd43932003-03-29 16:54:36 +000011341 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000011342 unlock_user_struct(target_schp, arg2, 0);
Tonis Tiigi407a1192022-01-04 20:18:19 -080011343 return get_errno(sys_sched_setparam(arg1, &schp));
bellard5cd43932003-03-29 16:54:36 +000011344 }
bellard31e31b82003-02-18 22:55:36 +000011345 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000011346 {
Tonis Tiigi407a1192022-01-04 20:18:19 -080011347 struct target_sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000011348 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050011349
11350 if (arg2 == 0) {
11351 return -TARGET_EINVAL;
11352 }
Tonis Tiigi407a1192022-01-04 20:18:19 -080011353 ret = get_errno(sys_sched_getparam(arg1, &schp));
bellard5cd43932003-03-29 16:54:36 +000011354 if (!is_error(ret)) {
Tonis Tiigi407a1192022-01-04 20:18:19 -080011355 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011356 return -TARGET_EFAULT;
Tonis Tiigi407a1192022-01-04 20:18:19 -080011357 }
bellard5cd43932003-03-29 16:54:36 +000011358 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000011359 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000011360 }
11361 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011362 return ret;
bellard31e31b82003-02-18 22:55:36 +000011363 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000011364 {
Tonis Tiigi407a1192022-01-04 20:18:19 -080011365 struct target_sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000011366 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050011367 if (arg3 == 0) {
11368 return -TARGET_EINVAL;
11369 }
Tonis Tiigi407a1192022-01-04 20:18:19 -080011370 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011371 return -TARGET_EFAULT;
Tonis Tiigi407a1192022-01-04 20:18:19 -080011372 }
bellard5cd43932003-03-29 16:54:36 +000011373 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000011374 unlock_user_struct(target_schp, arg3, 0);
Tonis Tiigi407a1192022-01-04 20:18:19 -080011375 return get_errno(sys_sched_setscheduler(arg1, arg2, &schp));
bellard5cd43932003-03-29 16:54:36 +000011376 }
bellard31e31b82003-02-18 22:55:36 +000011377 case TARGET_NR_sched_getscheduler:
Tonis Tiigi407a1192022-01-04 20:18:19 -080011378 return get_errno(sys_sched_getscheduler(arg1));
Tonis Tiigi45ad7612022-01-04 20:18:18 -080011379 case TARGET_NR_sched_getattr:
11380 {
11381 struct target_sched_attr *target_scha;
11382 struct sched_attr scha;
11383 if (arg2 == 0) {
11384 return -TARGET_EINVAL;
11385 }
11386 if (arg3 > sizeof(scha)) {
11387 arg3 = sizeof(scha);
11388 }
11389 ret = get_errno(sys_sched_getattr(arg1, &scha, arg3, arg4));
11390 if (!is_error(ret)) {
11391 target_scha = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11392 if (!target_scha) {
11393 return -TARGET_EFAULT;
11394 }
11395 target_scha->size = tswap32(scha.size);
11396 target_scha->sched_policy = tswap32(scha.sched_policy);
11397 target_scha->sched_flags = tswap64(scha.sched_flags);
11398 target_scha->sched_nice = tswap32(scha.sched_nice);
11399 target_scha->sched_priority = tswap32(scha.sched_priority);
11400 target_scha->sched_runtime = tswap64(scha.sched_runtime);
11401 target_scha->sched_deadline = tswap64(scha.sched_deadline);
11402 target_scha->sched_period = tswap64(scha.sched_period);
11403 if (scha.size > offsetof(struct sched_attr, sched_util_min)) {
11404 target_scha->sched_util_min = tswap32(scha.sched_util_min);
11405 target_scha->sched_util_max = tswap32(scha.sched_util_max);
11406 }
11407 unlock_user(target_scha, arg2, arg3);
11408 }
11409 return ret;
11410 }
11411 case TARGET_NR_sched_setattr:
11412 {
11413 struct target_sched_attr *target_scha;
11414 struct sched_attr scha;
11415 uint32_t size;
11416 int zeroed;
11417 if (arg2 == 0) {
11418 return -TARGET_EINVAL;
11419 }
11420 if (get_user_u32(size, arg2)) {
11421 return -TARGET_EFAULT;
11422 }
11423 if (!size) {
11424 size = offsetof(struct target_sched_attr, sched_util_min);
11425 }
11426 if (size < offsetof(struct target_sched_attr, sched_util_min)) {
11427 if (put_user_u32(sizeof(struct target_sched_attr), arg2)) {
11428 return -TARGET_EFAULT;
11429 }
11430 return -TARGET_E2BIG;
11431 }
11432
11433 zeroed = check_zeroed_user(arg2, sizeof(struct target_sched_attr), size);
11434 if (zeroed < 0) {
11435 return zeroed;
11436 } else if (zeroed == 0) {
11437 if (put_user_u32(sizeof(struct target_sched_attr), arg2)) {
11438 return -TARGET_EFAULT;
11439 }
11440 return -TARGET_E2BIG;
11441 }
11442 if (size > sizeof(struct target_sched_attr)) {
11443 size = sizeof(struct target_sched_attr);
11444 }
11445
11446 target_scha = lock_user(VERIFY_READ, arg2, size, 1);
11447 if (!target_scha) {
11448 return -TARGET_EFAULT;
11449 }
11450 scha.size = size;
11451 scha.sched_policy = tswap32(target_scha->sched_policy);
11452 scha.sched_flags = tswap64(target_scha->sched_flags);
11453 scha.sched_nice = tswap32(target_scha->sched_nice);
11454 scha.sched_priority = tswap32(target_scha->sched_priority);
11455 scha.sched_runtime = tswap64(target_scha->sched_runtime);
11456 scha.sched_deadline = tswap64(target_scha->sched_deadline);
11457 scha.sched_period = tswap64(target_scha->sched_period);
11458 if (size > offsetof(struct target_sched_attr, sched_util_min)) {
11459 scha.sched_util_min = tswap32(target_scha->sched_util_min);
11460 scha.sched_util_max = tswap32(target_scha->sched_util_max);
11461 }
11462 unlock_user(target_scha, arg2, 0);
11463 return get_errno(sys_sched_setattr(arg1, &scha, arg3));
11464 }
bellard31e31b82003-02-18 22:55:36 +000011465 case TARGET_NR_sched_yield:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011466 return get_errno(sched_yield());
bellard31e31b82003-02-18 22:55:36 +000011467 case TARGET_NR_sched_get_priority_max:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011468 return get_errno(sched_get_priority_max(arg1));
bellard31e31b82003-02-18 22:55:36 +000011469 case TARGET_NR_sched_get_priority_min:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011470 return get_errno(sched_get_priority_min(arg1));
Alistair Francis859e8a82020-03-12 15:13:49 -070011471#ifdef TARGET_NR_sched_rr_get_interval
bellard31e31b82003-02-18 22:55:36 +000011472 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000011473 {
bellard5cd43932003-03-29 16:54:36 +000011474 struct timespec ts;
11475 ret = get_errno(sched_rr_get_interval(arg1, &ts));
11476 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050011477 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000011478 }
11479 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011480 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070011481#endif
Filip Bozutaddcbde12020-08-24 21:21:16 +020011482#ifdef TARGET_NR_sched_rr_get_interval_time64
11483 case TARGET_NR_sched_rr_get_interval_time64:
11484 {
11485 struct timespec ts;
11486 ret = get_errno(sched_rr_get_interval(arg1, &ts));
11487 if (!is_error(ret)) {
11488 ret = host_to_target_timespec64(arg2, &ts);
11489 }
11490 }
11491 return ret;
11492#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070011493#if defined(TARGET_NR_nanosleep)
bellard31e31b82003-02-18 22:55:36 +000011494 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000011495 {
bellard1b6b0292003-03-22 17:31:38 +000011496 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000011497 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010011498 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000011499 if (is_error(ret) && arg2) {
11500 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000011501 }
11502 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011503 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070011504#endif
bellard31e31b82003-02-18 22:55:36 +000011505 case TARGET_NR_prctl:
Richard Henderson87e9bf22021-12-27 07:01:22 -080011506 return do_prctl(cpu_env, arg1, arg2, arg3, arg4, arg5);
ths39b9aae2007-02-11 18:36:44 +000011507 break;
bellardd2fd1af2007-11-14 18:08:56 +000011508#ifdef TARGET_NR_arch_prctl
11509 case TARGET_NR_arch_prctl:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011510 return do_arch_prctl(cpu_env, arg1, arg2);
bellardd2fd1af2007-11-14 18:08:56 +000011511#endif
aurel32f2c7ba12008-03-28 22:32:06 +000011512#ifdef TARGET_NR_pread64
11513 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010011514 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000011515 arg4 = arg5;
11516 arg5 = arg6;
11517 }
Peter Maydell2bd3f892019-01-08 18:49:00 +000011518 if (arg2 == 0 && arg3 == 0) {
11519 /* Special-case NULL buffer and zero length, which should succeed */
11520 p = 0;
11521 } else {
11522 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11523 if (!p) {
11524 return -TARGET_EFAULT;
11525 }
11526 }
Michael Tokarev99174ce2024-08-29 09:59:51 +030011527 ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
aurel32f2c7ba12008-03-28 22:32:06 +000011528 unlock_user(p, arg2, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011529 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +000011530 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010011531 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000011532 arg4 = arg5;
11533 arg5 = arg6;
11534 }
Peter Maydell2bd3f892019-01-08 18:49:00 +000011535 if (arg2 == 0 && arg3 == 0) {
11536 /* Special-case NULL buffer and zero length, which should succeed */
11537 p = 0;
11538 } else {
11539 p = lock_user(VERIFY_READ, arg2, arg3, 1);
11540 if (!p) {
11541 return -TARGET_EFAULT;
11542 }
11543 }
Michael Tokarev99174ce2024-08-29 09:59:51 +030011544 ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
aurel32f2c7ba12008-03-28 22:32:06 +000011545 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011546 return ret;
aurel32f2c7ba12008-03-28 22:32:06 +000011547#endif
bellard31e31b82003-02-18 22:55:36 +000011548 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000011549 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011550 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011551 ret = get_errno(sys_getcwd1(p, arg2));
11552 unlock_user(p, arg1, ret);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011553 return ret;
bellard31e31b82003-02-18 22:55:36 +000011554 case TARGET_NR_capget:
11555 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000011556 {
11557 struct target_user_cap_header *target_header;
11558 struct target_user_cap_data *target_data = NULL;
11559 struct __user_cap_header_struct header;
11560 struct __user_cap_data_struct data[2];
11561 struct __user_cap_data_struct *dataptr = NULL;
11562 int i, target_datalen;
11563 int data_items = 1;
11564
11565 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070011566 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +000011567 }
11568 header.version = tswap32(target_header->version);
11569 header.pid = tswap32(target_header->pid);
11570
Peter Maydellec864872014-03-19 16:07:30 +000011571 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000011572 /* Version 2 and up takes pointer to two user_data structs */
11573 data_items = 2;
11574 }
11575
11576 target_datalen = sizeof(*target_data) * data_items;
11577
11578 if (arg2) {
11579 if (num == TARGET_NR_capget) {
11580 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
11581 } else {
11582 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
11583 }
11584 if (!target_data) {
11585 unlock_user_struct(target_header, arg1, 0);
Richard Henderson2852aaf2018-08-18 12:01:06 -070011586 return -TARGET_EFAULT;
Peter Maydelle0eb2102014-03-17 12:15:35 +000011587 }
11588
11589 if (num == TARGET_NR_capset) {
11590 for (i = 0; i < data_items; i++) {
11591 data[i].effective = tswap32(target_data[i].effective);
11592 data[i].permitted = tswap32(target_data[i].permitted);
11593 data[i].inheritable = tswap32(target_data[i].inheritable);
11594 }
11595 }
11596
11597 dataptr = data;
11598 }
11599
11600 if (num == TARGET_NR_capget) {
11601 ret = get_errno(capget(&header, dataptr));
11602 } else {
11603 ret = get_errno(capset(&header, dataptr));
11604 }
11605
11606 /* The kernel always updates version for both capget and capset */
11607 target_header->version = tswap32(header.version);
11608 unlock_user_struct(target_header, arg1, 1);
11609
11610 if (arg2) {
11611 if (num == TARGET_NR_capget) {
11612 for (i = 0; i < data_items; i++) {
11613 target_data[i].effective = tswap32(data[i].effective);
11614 target_data[i].permitted = tswap32(data[i].permitted);
11615 target_data[i].inheritable = tswap32(data[i].inheritable);
11616 }
11617 unlock_user(target_data, arg2, target_datalen);
11618 } else {
11619 unlock_user(target_data, arg2, 0);
11620 }
11621 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011622 return ret;
Peter Maydelle0eb2102014-03-17 12:15:35 +000011623 }
bellard31e31b82003-02-18 22:55:36 +000011624 case TARGET_NR_sigaltstack:
Richard Henderson6b208752021-04-25 19:53:12 -070011625 return do_sigaltstack(arg1, arg2, cpu_env);
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011626
11627#ifdef CONFIG_SENDFILE
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011628#ifdef TARGET_NR_sendfile
bellard31e31b82003-02-18 22:55:36 +000011629 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011630 {
11631 off_t *offp = NULL;
11632 off_t off;
11633 if (arg3) {
11634 ret = get_user_sal(off, arg3);
11635 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011636 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011637 }
11638 offp = &off;
11639 }
11640 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11641 if (!is_error(ret) && arg3) {
11642 abi_long ret2 = put_user_sal(off, arg3);
11643 if (is_error(ret2)) {
11644 ret = ret2;
11645 }
11646 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011647 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011648 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011649#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011650#ifdef TARGET_NR_sendfile64
11651 case TARGET_NR_sendfile64:
11652 {
11653 off_t *offp = NULL;
11654 off_t off;
11655 if (arg3) {
11656 ret = get_user_s64(off, arg3);
11657 if (is_error(ret)) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011658 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011659 }
11660 offp = &off;
11661 }
11662 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11663 if (!is_error(ret) && arg3) {
11664 abi_long ret2 = put_user_s64(off, arg3);
11665 if (is_error(ret2)) {
11666 ret = ret2;
11667 }
11668 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011669 return ret;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011670 }
11671#endif
bellardebc05482003-09-30 21:08:41 +000011672#endif
bellard048f6b42005-11-26 18:47:20 +000011673#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000011674 case TARGET_NR_vfork:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011675 return get_errno(do_fork(cpu_env,
11676 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
11677 0, 0, 0, 0));
bellard048f6b42005-11-26 18:47:20 +000011678#endif
bellardebc05482003-09-30 21:08:41 +000011679#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000011680 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000011681 {
11682 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030011683 int resource = target_to_host_resource(arg1);
11684 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000011685 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000011686 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000011687 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011688 return -TARGET_EFAULT;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090011689 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
11690 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000011691 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000011692 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011693 return ret;
bellard728584b2003-04-29 20:43:36 +000011694 }
bellardebc05482003-09-30 21:08:41 +000011695#endif
bellarda315a142005-01-30 22:59:18 +000011696#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000011697 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000011698 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011699 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011700 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
11701 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011702 return ret;
bellarda315a142005-01-30 22:59:18 +000011703#endif
11704#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000011705 case TARGET_NR_ftruncate64:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011706 return target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellarda315a142005-01-30 22:59:18 +000011707#endif
11708#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000011709 case TARGET_NR_stat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070011710 if (!(p = lock_user_string(arg1))) {
11711 return -TARGET_EFAULT;
11712 }
pbrook53a59602006-03-25 19:31:22 +000011713 ret = get_errno(stat(path(p), &st));
11714 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011715 if (!is_error(ret))
11716 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011717 return ret;
bellarda315a142005-01-30 22:59:18 +000011718#endif
11719#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000011720 case TARGET_NR_lstat64:
Richard Henderson2852aaf2018-08-18 12:01:06 -070011721 if (!(p = lock_user_string(arg1))) {
11722 return -TARGET_EFAULT;
11723 }
pbrook53a59602006-03-25 19:31:22 +000011724 ret = get_errno(lstat(path(p), &st));
11725 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011726 if (!is_error(ret))
11727 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011728 return ret;
bellarda315a142005-01-30 22:59:18 +000011729#endif
11730#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000011731 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000011732 ret = get_errno(fstat(arg1, &st));
11733 if (!is_error(ret))
11734 ret = host_to_target_stat64(cpu_env, arg2, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011735 return ret;
bellardec86b0f2003-04-11 00:15:04 +000011736#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010011737#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000011738#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000011739 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000011740#endif
11741#ifdef TARGET_NR_newfstatat
11742 case TARGET_NR_newfstatat:
11743#endif
Richard Henderson2852aaf2018-08-18 12:01:06 -070011744 if (!(p = lock_user_string(arg2))) {
11745 return -TARGET_EFAULT;
11746 }
Peter Maydellc0d472b2013-06-12 16:20:21 +010011747 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
Richard Henderson2852aaf2018-08-18 12:01:06 -070011748 unlock_user(p, arg2, 0);
balrog6a24a772008-09-20 02:23:36 +000011749 if (!is_error(ret))
11750 ret = host_to_target_stat64(cpu_env, arg3, &st);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011751 return ret;
bellarda315a142005-01-30 22:59:18 +000011752#endif
Aleksandar Rikaloefa92182019-06-28 12:43:34 +020011753#if defined(TARGET_NR_statx)
11754 case TARGET_NR_statx:
11755 {
11756 struct target_statx *target_stx;
11757 int dirfd = arg1;
11758 int flags = arg3;
11759
11760 p = lock_user_string(arg2);
11761 if (p == NULL) {
11762 return -TARGET_EFAULT;
11763 }
11764#if defined(__NR_statx)
11765 {
11766 /*
11767 * It is assumed that struct statx is architecture independent.
11768 */
11769 struct target_statx host_stx;
11770 int mask = arg4;
11771
11772 ret = get_errno(sys_statx(dirfd, p, flags, mask, &host_stx));
11773 if (!is_error(ret)) {
11774 if (host_to_target_statx(&host_stx, arg5) != 0) {
11775 unlock_user(p, arg2, 0);
11776 return -TARGET_EFAULT;
11777 }
11778 }
11779
11780 if (ret != -TARGET_ENOSYS) {
11781 unlock_user(p, arg2, 0);
11782 return ret;
11783 }
11784 }
11785#endif
11786 ret = get_errno(fstatat(dirfd, path(p), &st, flags));
11787 unlock_user(p, arg2, 0);
11788
11789 if (!is_error(ret)) {
11790 if (!lock_user_struct(VERIFY_WRITE, target_stx, arg5, 0)) {
11791 return -TARGET_EFAULT;
11792 }
11793 memset(target_stx, 0, sizeof(*target_stx));
11794 __put_user(major(st.st_dev), &target_stx->stx_dev_major);
11795 __put_user(minor(st.st_dev), &target_stx->stx_dev_minor);
11796 __put_user(st.st_ino, &target_stx->stx_ino);
11797 __put_user(st.st_mode, &target_stx->stx_mode);
11798 __put_user(st.st_uid, &target_stx->stx_uid);
11799 __put_user(st.st_gid, &target_stx->stx_gid);
11800 __put_user(st.st_nlink, &target_stx->stx_nlink);
11801 __put_user(major(st.st_rdev), &target_stx->stx_rdev_major);
11802 __put_user(minor(st.st_rdev), &target_stx->stx_rdev_minor);
11803 __put_user(st.st_size, &target_stx->stx_size);
11804 __put_user(st.st_blksize, &target_stx->stx_blksize);
11805 __put_user(st.st_blocks, &target_stx->stx_blocks);
11806 __put_user(st.st_atime, &target_stx->stx_atime.tv_sec);
11807 __put_user(st.st_mtime, &target_stx->stx_mtime.tv_sec);
11808 __put_user(st.st_ctime, &target_stx->stx_ctime.tv_sec);
11809 unlock_user_struct(target_stx, arg5, 1);
11810 }
11811 }
11812 return ret;
11813#endif
Chen Gang704eff62015-08-21 05:37:33 +080011814#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000011815 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000011816 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011817 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011818 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
11819 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011820 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080011821#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030011822#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000011823 case TARGET_NR_getuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011824 return get_errno(high2lowuid(getuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011825#endif
11826#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000011827 case TARGET_NR_getgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011828 return get_errno(high2lowgid(getgid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011829#endif
11830#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000011831 case TARGET_NR_geteuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011832 return get_errno(high2lowuid(geteuid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011833#endif
11834#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011835 case TARGET_NR_getegid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011836 return get_errno(high2lowgid(getegid()));
Riku Voipio0c866a72011-04-18 15:23:06 +030011837#endif
bellard67867302003-11-23 17:05:30 +000011838 case TARGET_NR_setreuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011839 return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
bellard67867302003-11-23 17:05:30 +000011840 case TARGET_NR_setregid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011841 return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
bellard67867302003-11-23 17:05:30 +000011842 case TARGET_NR_getgroups:
Michael Tokarev725160f2023-06-03 20:23:38 +030011843 { /* the same code as for TARGET_NR_getgroups32 */
bellard67867302003-11-23 17:05:30 +000011844 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011845 target_id *target_grouplist;
Michael Tokarev1e35d322023-04-09 13:53:27 +030011846 g_autofree gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011847 int i;
11848
Peter Maydell8fbf89a2023-06-09 17:29:15 +010011849 if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
Michael Tokarev1e35d322023-04-09 13:53:27 +030011850 return -TARGET_EINVAL;
bellard67867302003-11-23 17:05:30 +000011851 }
Michael Tokarev1e35d322023-04-09 13:53:27 +030011852 if (gidsetsize > 0) {
11853 grouplist = g_try_new(gid_t, gidsetsize);
11854 if (!grouplist) {
11855 return -TARGET_ENOMEM;
11856 }
11857 }
11858 ret = get_errno(getgroups(gidsetsize, grouplist));
11859 if (!is_error(ret) && gidsetsize > 0) {
11860 target_grouplist = lock_user(VERIFY_WRITE, arg2,
11861 gidsetsize * sizeof(target_id), 0);
11862 if (!target_grouplist) {
11863 return -TARGET_EFAULT;
11864 }
11865 for (i = 0; i < ret; i++) {
11866 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
11867 }
11868 unlock_user(target_grouplist, arg2,
11869 gidsetsize * sizeof(target_id));
11870 }
11871 return ret;
bellard67867302003-11-23 17:05:30 +000011872 }
bellard67867302003-11-23 17:05:30 +000011873 case TARGET_NR_setgroups:
Michael Tokarev725160f2023-06-03 20:23:38 +030011874 { /* the same code as for TARGET_NR_setgroups32 */
bellard67867302003-11-23 17:05:30 +000011875 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011876 target_id *target_grouplist;
Michael Tokarev1e35d322023-04-09 13:53:27 +030011877 g_autofree gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011878 int i;
Michael Tokarev1e35d322023-04-09 13:53:27 +030011879
11880 if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
11881 return -TARGET_EINVAL;
11882 }
11883 if (gidsetsize > 0) {
11884 grouplist = g_try_new(gid_t, gidsetsize);
11885 if (!grouplist) {
11886 return -TARGET_ENOMEM;
11887 }
11888 target_grouplist = lock_user(VERIFY_READ, arg2,
11889 gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011890 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070011891 return -TARGET_EFAULT;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011892 }
11893 for (i = 0; i < gidsetsize; i++) {
11894 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11895 }
Michael Tokarev1e35d322023-04-09 13:53:27 +030011896 unlock_user(target_grouplist, arg2,
11897 gidsetsize * sizeof(target_id));
bellard579a97f2007-11-11 14:26:47 +000011898 }
Ilya Leoshkevich54b27922024-06-14 17:46:40 +020011899 return get_errno(sys_setgroups(gidsetsize, grouplist));
bellard67867302003-11-23 17:05:30 +000011900 }
bellard67867302003-11-23 17:05:30 +000011901 case TARGET_NR_fchown:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011902 return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
Peter Maydellc0d472b2013-06-12 16:20:21 +010011903#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011904 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011905 if (!(p = lock_user_string(arg2)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011906 return -TARGET_EFAULT;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011907 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11908 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011909 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011910 return ret;
thsccfa72b2007-09-24 09:23:34 +000011911#endif
bellard67867302003-11-23 17:05:30 +000011912#ifdef TARGET_NR_setresuid
11913 case TARGET_NR_setresuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011914 return get_errno(sys_setresuid(low2highuid(arg1),
11915 low2highuid(arg2),
11916 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011917#endif
11918#ifdef TARGET_NR_getresuid
11919 case TARGET_NR_getresuid:
11920 {
pbrook53a59602006-03-25 19:31:22 +000011921 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011922 ret = get_errno(getresuid(&ruid, &euid, &suid));
11923 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011924 if (put_user_id(high2lowuid(ruid), arg1)
11925 || put_user_id(high2lowuid(euid), arg2)
11926 || put_user_id(high2lowuid(suid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011927 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000011928 }
11929 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011930 return ret;
bellard67867302003-11-23 17:05:30 +000011931#endif
11932#ifdef TARGET_NR_getresgid
11933 case TARGET_NR_setresgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011934 return get_errno(sys_setresgid(low2highgid(arg1),
11935 low2highgid(arg2),
11936 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011937#endif
11938#ifdef TARGET_NR_getresgid
11939 case TARGET_NR_getresgid:
11940 {
pbrook53a59602006-03-25 19:31:22 +000011941 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011942 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11943 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011944 if (put_user_id(high2lowgid(rgid), arg1)
11945 || put_user_id(high2lowgid(egid), arg2)
11946 || put_user_id(high2lowgid(sgid), arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011947 return -TARGET_EFAULT;
bellard67867302003-11-23 17:05:30 +000011948 }
11949 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011950 return ret;
bellard67867302003-11-23 17:05:30 +000011951#endif
Chen Gang704eff62015-08-21 05:37:33 +080011952#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011953 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011954 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011955 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011956 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11957 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011958 return ret;
Chen Gang704eff62015-08-21 05:37:33 +080011959#endif
bellard67867302003-11-23 17:05:30 +000011960 case TARGET_NR_setuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011961 return get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011962 case TARGET_NR_setgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011963 return get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011964 case TARGET_NR_setfsuid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011965 return get_errno(setfsuid(arg1));
bellard67867302003-11-23 17:05:30 +000011966 case TARGET_NR_setfsgid:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011967 return get_errno(setfsgid(arg1));
bellard67867302003-11-23 17:05:30 +000011968
bellarda315a142005-01-30 22:59:18 +000011969#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011970 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011971 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070011972 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000011973 ret = get_errno(lchown(p, arg2, arg3));
11974 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011975 return ret;
bellarda315a142005-01-30 22:59:18 +000011976#endif
11977#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011978 case TARGET_NR_getuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011979 return get_errno(getuid());
bellarda315a142005-01-30 22:59:18 +000011980#endif
aurel3264b4d282008-11-14 17:20:15 +000011981
11982#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11983 /* Alpha specific */
11984 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011985 {
11986 uid_t euid;
11987 euid=geteuid();
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020011988 cpu_env->ir[IR_A4]=euid;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011989 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070011990 return get_errno(getuid());
aurel3264b4d282008-11-14 17:20:15 +000011991#endif
11992#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11993 /* Alpha specific */
11994 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011995 {
11996 uid_t egid;
11997 egid=getegid();
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020011998 cpu_env->ir[IR_A4]=egid;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011999 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012000 return get_errno(getgid());
aurel3264b4d282008-11-14 17:20:15 +000012001#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080012002#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
12003 /* Alpha specific */
12004 case TARGET_NR_osf_getsysinfo:
12005 ret = -TARGET_EOPNOTSUPP;
12006 switch (arg1) {
12007 case TARGET_GSI_IEEE_FP_CONTROL:
12008 {
Richard Henderson21ba8562019-04-26 15:20:51 -070012009 uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env);
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012010 uint64_t swcr = cpu_env->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012011
Richard Henderson21ba8562019-04-26 15:20:51 -070012012 swcr &= ~SWCR_STATUS_MASK;
12013 swcr |= (fpcr >> 35) & SWCR_STATUS_MASK;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012014
12015 if (put_user_u64 (swcr, arg2))
Richard Henderson2852aaf2018-08-18 12:01:06 -070012016 return -TARGET_EFAULT;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012017 ret = 0;
12018 }
12019 break;
12020
12021 /* case GSI_IEEE_STATE_AT_SIGNAL:
12022 -- Not implemented in linux kernel.
12023 case GSI_UACPROC:
12024 -- Retrieves current unaligned access state; not much used.
12025 case GSI_PROC_TYPE:
12026 -- Retrieves implver information; surely not used.
12027 case GSI_GET_HWRPB:
12028 -- Grabs a copy of the HWRPB; surely not used.
12029 */
12030 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012031 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012032#endif
12033#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
12034 /* Alpha specific */
12035 case TARGET_NR_osf_setsysinfo:
12036 ret = -TARGET_EOPNOTSUPP;
12037 switch (arg1) {
12038 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080012039 {
Richard Henderson21ba8562019-04-26 15:20:51 -070012040 uint64_t swcr, fpcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012041
Richard Henderson6e06d512012-06-01 09:08:21 -070012042 if (get_user_u64 (swcr, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012043 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070012044 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080012045
Richard Henderson21ba8562019-04-26 15:20:51 -070012046 /*
12047 * The kernel calls swcr_update_status to update the
12048 * status bits from the fpcr at every point that it
12049 * could be queried. Therefore, we store the status
12050 * bits only in FPCR.
12051 */
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012052 cpu_env->swcr = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080012053
Richard Henderson21ba8562019-04-26 15:20:51 -070012054 fpcr = cpu_alpha_load_fpcr(cpu_env);
12055 fpcr &= ((uint64_t)FPCR_DYN_MASK << 32);
12056 fpcr |= alpha_ieee_swcr_to_fpcr(swcr);
Richard Henderson6e06d512012-06-01 09:08:21 -070012057 cpu_alpha_store_fpcr(cpu_env, fpcr);
12058 ret = 0;
12059 }
12060 break;
12061
12062 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
12063 {
Richard Henderson21ba8562019-04-26 15:20:51 -070012064 uint64_t exc, fpcr, fex;
Richard Henderson6e06d512012-06-01 09:08:21 -070012065
12066 if (get_user_u64(exc, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012067 return -TARGET_EFAULT;
Richard Henderson6e06d512012-06-01 09:08:21 -070012068 }
Richard Henderson21ba8562019-04-26 15:20:51 -070012069 exc &= SWCR_STATUS_MASK;
12070 fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080012071
Richard Henderson6e06d512012-06-01 09:08:21 -070012072 /* Old exceptions are not signaled. */
Richard Henderson21ba8562019-04-26 15:20:51 -070012073 fex = alpha_ieee_fpcr_to_swcr(fpcr);
12074 fex = exc & ~fex;
12075 fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT;
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012076 fex &= (cpu_env)->swcr;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012077
Richard Henderson21ba8562019-04-26 15:20:51 -070012078 /* Update the hardware fpcr. */
12079 fpcr |= alpha_ieee_swcr_to_fpcr(exc);
12080 cpu_alpha_store_fpcr(cpu_env, fpcr);
12081
12082 if (fex) {
12083 int si_code = TARGET_FPE_FLTUNK;
Richard Henderson6e06d512012-06-01 09:08:21 -070012084 target_siginfo_t info;
Richard Henderson21ba8562019-04-26 15:20:51 -070012085
12086 if (fex & SWCR_TRAP_ENABLE_DNO) {
12087 si_code = TARGET_FPE_FLTUND;
12088 }
12089 if (fex & SWCR_TRAP_ENABLE_INE) {
12090 si_code = TARGET_FPE_FLTRES;
12091 }
12092 if (fex & SWCR_TRAP_ENABLE_UNF) {
12093 si_code = TARGET_FPE_FLTUND;
12094 }
12095 if (fex & SWCR_TRAP_ENABLE_OVF) {
12096 si_code = TARGET_FPE_FLTOVF;
12097 }
12098 if (fex & SWCR_TRAP_ENABLE_DZE) {
12099 si_code = TARGET_FPE_FLTDIV;
12100 }
12101 if (fex & SWCR_TRAP_ENABLE_INV) {
12102 si_code = TARGET_FPE_FLTINV;
12103 }
12104
Richard Henderson6e06d512012-06-01 09:08:21 -070012105 info.si_signo = SIGFPE;
12106 info.si_errno = 0;
12107 info.si_code = si_code;
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012108 info._sifields._sigfault._addr = (cpu_env)->pc;
12109 queue_signal(cpu_env, info.si_signo,
Peter Maydell9d2803f2016-07-28 16:44:46 +010012110 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080012111 }
Richard Henderson21ba8562019-04-26 15:20:51 -070012112 ret = 0;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012113 }
12114 break;
12115
12116 /* case SSI_NVPAIRS:
12117 -- Used with SSIN_UACPROC to enable unaligned accesses.
12118 case SSI_IEEE_STATE_AT_SIGNAL:
12119 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
12120 -- Not implemented in linux kernel
12121 */
12122 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012123 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012124#endif
12125#ifdef TARGET_NR_osf_sigprocmask
12126 /* Alpha specific. */
12127 case TARGET_NR_osf_sigprocmask:
12128 {
12129 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010012130 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012131 sigset_t set, oldset;
12132
12133 switch(arg1) {
12134 case TARGET_SIG_BLOCK:
12135 how = SIG_BLOCK;
12136 break;
12137 case TARGET_SIG_UNBLOCK:
12138 how = SIG_UNBLOCK;
12139 break;
12140 case TARGET_SIG_SETMASK:
12141 how = SIG_SETMASK;
12142 break;
12143 default:
Richard Henderson259841c2018-08-18 12:01:09 -070012144 return -TARGET_EINVAL;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012145 }
12146 mask = arg2;
12147 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010012148 ret = do_sigprocmask(how, &set, &oldset);
12149 if (!ret) {
12150 host_to_target_old_sigset(&mask, &oldset);
12151 ret = mask;
12152 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080012153 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012154 return ret;
Richard Hendersonba0e2762009-12-09 15:56:29 -080012155#endif
aurel3264b4d282008-11-14 17:20:15 +000012156
bellarda315a142005-01-30 22:59:18 +000012157#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000012158 case TARGET_NR_getgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012159 return get_errno(getgid());
bellarda315a142005-01-30 22:59:18 +000012160#endif
12161#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000012162 case TARGET_NR_geteuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012163 return get_errno(geteuid());
bellarda315a142005-01-30 22:59:18 +000012164#endif
12165#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000012166 case TARGET_NR_getegid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012167 return get_errno(getegid());
bellarda315a142005-01-30 22:59:18 +000012168#endif
12169#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000012170 case TARGET_NR_setreuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012171 return get_errno(setreuid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000012172#endif
12173#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000012174 case TARGET_NR_setregid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012175 return get_errno(setregid(arg1, arg2));
bellarda315a142005-01-30 22:59:18 +000012176#endif
12177#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000012178 case TARGET_NR_getgroups32:
Michael Tokarev725160f2023-06-03 20:23:38 +030012179 { /* the same code as for TARGET_NR_getgroups */
bellard99c475a2005-01-31 20:45:13 +000012180 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000012181 uint32_t *target_grouplist;
Michael Tokarev1e35d322023-04-09 13:53:27 +030012182 g_autofree gid_t *grouplist = NULL;
bellard99c475a2005-01-31 20:45:13 +000012183 int i;
12184
Peter Maydell8fbf89a2023-06-09 17:29:15 +010012185 if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
Michael Tokarev1e35d322023-04-09 13:53:27 +030012186 return -TARGET_EINVAL;
12187 }
12188 if (gidsetsize > 0) {
12189 grouplist = g_try_new(gid_t, gidsetsize);
12190 if (!grouplist) {
12191 return -TARGET_ENOMEM;
12192 }
12193 }
bellard99c475a2005-01-31 20:45:13 +000012194 ret = get_errno(getgroups(gidsetsize, grouplist));
Michael Tokarev1e35d322023-04-09 13:53:27 +030012195 if (!is_error(ret) && gidsetsize > 0) {
12196 target_grouplist = lock_user(VERIFY_WRITE, arg2,
12197 gidsetsize * 4, 0);
bellard579a97f2007-11-11 14:26:47 +000012198 if (!target_grouplist) {
Richard Henderson259841c2018-08-18 12:01:09 -070012199 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012200 }
Michael Tokarev1e35d322023-04-09 13:53:27 +030012201 for (i = 0; i < ret; i++) {
pbrook53a59602006-03-25 19:31:22 +000012202 target_grouplist[i] = tswap32(grouplist[i]);
Michael Tokarev1e35d322023-04-09 13:53:27 +030012203 }
pbrook53a59602006-03-25 19:31:22 +000012204 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000012205 }
Michael Tokarev1e35d322023-04-09 13:53:27 +030012206 return ret;
bellard99c475a2005-01-31 20:45:13 +000012207 }
bellarda315a142005-01-30 22:59:18 +000012208#endif
12209#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000012210 case TARGET_NR_setgroups32:
Michael Tokarev725160f2023-06-03 20:23:38 +030012211 { /* the same code as for TARGET_NR_setgroups */
bellard99c475a2005-01-31 20:45:13 +000012212 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000012213 uint32_t *target_grouplist;
Michael Tokarev1e35d322023-04-09 13:53:27 +030012214 g_autofree gid_t *grouplist = NULL;
bellard99c475a2005-01-31 20:45:13 +000012215 int i;
ths3b46e622007-09-17 08:09:54 +000012216
Michael Tokarev1e35d322023-04-09 13:53:27 +030012217 if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
12218 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +000012219 }
Michael Tokarev1e35d322023-04-09 13:53:27 +030012220 if (gidsetsize > 0) {
12221 grouplist = g_try_new(gid_t, gidsetsize);
12222 if (!grouplist) {
12223 return -TARGET_ENOMEM;
12224 }
12225 target_grouplist = lock_user(VERIFY_READ, arg2,
12226 gidsetsize * 4, 1);
12227 if (!target_grouplist) {
12228 return -TARGET_EFAULT;
12229 }
12230 for (i = 0; i < gidsetsize; i++) {
12231 grouplist[i] = tswap32(target_grouplist[i]);
12232 }
12233 unlock_user(target_grouplist, arg2, 0);
12234 }
Ilya Leoshkevich54b27922024-06-14 17:46:40 +020012235 return get_errno(sys_setgroups(gidsetsize, grouplist));
bellard99c475a2005-01-31 20:45:13 +000012236 }
bellarda315a142005-01-30 22:59:18 +000012237#endif
12238#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000012239 case TARGET_NR_fchown32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012240 return get_errno(fchown(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000012241#endif
12242#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000012243 case TARGET_NR_setresuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012244 return get_errno(sys_setresuid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000012245#endif
12246#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000012247 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000012248 {
pbrook53a59602006-03-25 19:31:22 +000012249 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000012250 ret = get_errno(getresuid(&ruid, &euid, &suid));
12251 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000012252 if (put_user_u32(ruid, arg1)
12253 || put_user_u32(euid, arg2)
12254 || put_user_u32(suid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070012255 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000012256 }
12257 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012258 return ret;
bellarda315a142005-01-30 22:59:18 +000012259#endif
12260#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000012261 case TARGET_NR_setresgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012262 return get_errno(sys_setresgid(arg1, arg2, arg3));
bellarda315a142005-01-30 22:59:18 +000012263#endif
12264#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000012265 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000012266 {
pbrook53a59602006-03-25 19:31:22 +000012267 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000012268 ret = get_errno(getresgid(&rgid, &egid, &sgid));
12269 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000012270 if (put_user_u32(rgid, arg1)
12271 || put_user_u32(egid, arg2)
12272 || put_user_u32(sgid, arg3))
Richard Henderson2852aaf2018-08-18 12:01:06 -070012273 return -TARGET_EFAULT;
bellardb03c60f2003-03-23 17:19:56 +000012274 }
12275 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012276 return ret;
bellarda315a142005-01-30 22:59:18 +000012277#endif
12278#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000012279 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000012280 if (!(p = lock_user_string(arg1)))
Richard Henderson2852aaf2018-08-18 12:01:06 -070012281 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +000012282 ret = get_errno(chown(p, arg2, arg3));
12283 unlock_user(p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012284 return ret;
bellarda315a142005-01-30 22:59:18 +000012285#endif
12286#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000012287 case TARGET_NR_setuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012288 return get_errno(sys_setuid(arg1));
bellarda315a142005-01-30 22:59:18 +000012289#endif
12290#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000012291 case TARGET_NR_setgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012292 return get_errno(sys_setgid(arg1));
bellarda315a142005-01-30 22:59:18 +000012293#endif
12294#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000012295 case TARGET_NR_setfsuid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012296 return get_errno(setfsuid(arg1));
bellarda315a142005-01-30 22:59:18 +000012297#endif
12298#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000012299 case TARGET_NR_setfsgid32:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012300 return get_errno(setfsgid(arg1));
bellarda315a142005-01-30 22:59:18 +000012301#endif
bellardffa65c32004-01-04 23:57:22 +000012302#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000012303 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000012304 {
Thomas Weißschuhf443a262023-04-22 12:03:14 +020012305 void *a = lock_user(VERIFY_NONE, arg1, arg2, 0);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000012306 if (!a) {
Richard Henderson259841c2018-08-18 12:01:09 -070012307 return -TARGET_ENOMEM;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000012308 }
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000012309 p = lock_user_string(arg3);
12310 if (!p) {
Richard Henderson259841c2018-08-18 12:01:09 -070012311 ret = -TARGET_EFAULT;
12312 } else {
12313 ret = get_errno(mincore(a, arg2, p));
12314 unlock_user(p, arg3, ret);
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000012315 }
aurel3204bb9ac2008-10-01 21:46:41 +000012316 unlock_user(a, arg1, 0);
12317 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012318 return ret;
bellardffa65c32004-01-04 23:57:22 +000012319#endif
aurel32408321b2008-10-01 21:46:32 +000012320#ifdef TARGET_NR_arm_fadvise64_64
12321 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010012322 /* arm_fadvise64_64 looks like fadvise64_64 but
12323 * with different argument order: fd, advice, offset, len
12324 * rather than the usual fd, offset, len, advice.
12325 * Note that offset and len are both 64-bit so appear as
12326 * pairs of 32-bit registers.
12327 */
12328 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
12329 target_offset64(arg5, arg6), arg2);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012330 return -host_to_target_errno(ret);
aurel32408321b2008-10-01 21:46:32 +000012331#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012332
WANG Xueruieeed2292022-10-06 16:55:00 +080012333#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32)
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012334
12335#ifdef TARGET_NR_fadvise64_64
12336 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070012337#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010012338 /* 6 args: fd, advice, offset (high, low), len (high, low) */
12339 ret = arg2;
12340 arg2 = arg3;
12341 arg3 = arg4;
12342 arg4 = arg5;
12343 arg5 = arg6;
12344 arg6 = ret;
12345#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012346 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010012347 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012348 /* offset is in (3,4), len in (5,6) and advice in 7 */
12349 arg2 = arg3;
12350 arg3 = arg4;
12351 arg4 = arg5;
12352 arg5 = arg6;
12353 arg6 = arg7;
12354 }
Laurent Vivier43046b52017-03-02 01:11:45 +010012355#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012356 ret = posix_fadvise(arg1, target_offset64(arg2, arg3),
12357 target_offset64(arg4, arg5), arg6);
12358 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012359#endif
12360
12361#ifdef TARGET_NR_fadvise64
12362 case TARGET_NR_fadvise64:
12363 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010012364 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012365 /* offset is in (3,4), len in 5 and advice in 6 */
12366 arg2 = arg3;
12367 arg3 = arg4;
12368 arg4 = arg5;
12369 arg5 = arg6;
12370 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012371 ret = posix_fadvise(arg1, target_offset64(arg2, arg3), arg4, arg5);
12372 return -host_to_target_errno(ret);
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012373#endif
12374
12375#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010012376#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000012377#ifdef TARGET_NR_fadvise64_64
12378 case TARGET_NR_fadvise64_64:
12379#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020012380#ifdef TARGET_NR_fadvise64
12381 case TARGET_NR_fadvise64:
12382#endif
12383#ifdef TARGET_S390X
12384 switch (arg4) {
12385 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
12386 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
12387 case 6: arg4 = POSIX_FADV_DONTNEED; break;
12388 case 7: arg4 = POSIX_FADV_NOREUSE; break;
12389 default: break;
12390 }
12391#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012392 return -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
aurel32408321b2008-10-01 21:46:32 +000012393#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010012394#endif /* end of 64-bit ABI fadvise handling */
12395
bellardffa65c32004-01-04 23:57:22 +000012396#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000012397 case TARGET_NR_madvise:
Ilya Leoshkevich892a4f62022-06-21 16:42:05 +020012398 return target_madvise(arg1, arg2, arg3);
bellardffa65c32004-01-04 23:57:22 +000012399#endif
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010012400#ifdef TARGET_NR_fcntl64
bellard31e31b82003-02-18 22:55:36 +000012401 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000012402 {
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010012403 int cmd;
Michael Tokarevac1bbe82024-08-29 09:39:50 +030012404 struct flock fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010012405 from_flock64_fn *copyfrom = copy_from_user_flock64;
12406 to_flock64_fn *copyto = copy_to_user_flock64;
12407
pbrookce4defa2006-02-09 16:49:55 +000012408#ifdef TARGET_ARM
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012409 if (!cpu_env->eabi) {
Laurent Vivier7f254c52018-05-02 23:57:30 +020012410 copyfrom = copy_from_user_oabi_flock64;
12411 copyto = copy_to_user_oabi_flock64;
Peter Maydell213d3e92016-06-13 11:22:05 +010012412 }
pbrookce4defa2006-02-09 16:49:55 +000012413#endif
bellard77e46722003-04-29 20:39:06 +000012414
Alex Bennéebbf5f2a2020-04-03 20:11:40 +010012415 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000012416 if (cmd == -TARGET_EINVAL) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012417 return cmd;
Peter Maydell31b63192011-12-05 23:11:50 +000012418 }
thsb1e341e2007-03-20 21:50:52 +000012419
bellard60cd49d2003-03-16 22:53:56 +000012420 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000012421 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010012422 ret = copyfrom(&fl, arg3);
12423 if (ret) {
12424 break;
ths58134272007-03-31 18:59:32 +000012425 }
Laurent Vivieraf8ab2b2018-07-13 14:58:05 +020012426 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010012427 if (ret == 0) {
12428 ret = copyto(arg3, &fl);
12429 }
bellard77e46722003-04-29 20:39:06 +000012430 break;
12431
thsb1e341e2007-03-20 21:50:52 +000012432 case TARGET_F_SETLK64:
12433 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010012434 ret = copyfrom(&fl, arg3);
12435 if (ret) {
12436 break;
pbrookce4defa2006-02-09 16:49:55 +000012437 }
Peter Maydell435da5e2016-06-13 11:22:05 +010012438 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000012439 break;
bellard60cd49d2003-03-16 22:53:56 +000012440 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020012441 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000012442 break;
12443 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012444 return ret;
bellard77e46722003-04-29 20:39:06 +000012445 }
bellard60cd49d2003-03-16 22:53:56 +000012446#endif
ths7d600c82006-12-08 01:32:58 +000012447#ifdef TARGET_NR_cacheflush
12448 case TARGET_NR_cacheflush:
12449 /* self-modifying code is handled automatically, so nothing needed */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012450 return 0;
ths7d600c82006-12-08 01:32:58 +000012451#endif
bellardc573ff62004-01-04 15:51:36 +000012452#ifdef TARGET_NR_getpagesize
12453 case TARGET_NR_getpagesize:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012454 return TARGET_PAGE_SIZE;
bellardc573ff62004-01-04 15:51:36 +000012455#endif
bellard31e31b82003-02-18 22:55:36 +000012456 case TARGET_NR_gettid:
Daniel P. Berrangé71ba74f2019-03-20 16:18:42 +000012457 return get_errno(sys_gettid());
thse5febef2007-04-01 18:31:35 +000012458#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000012459 case TARGET_NR_readahead:
WANG Xueruieeed2292022-10-06 16:55:00 +080012460#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32)
James Clarke8bf8e9d2017-09-15 20:33:13 +010012461 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000012462 arg2 = arg3;
12463 arg3 = arg4;
12464 arg4 = arg5;
12465 }
Lena Djokic77c68502016-11-24 17:08:56 +010012466 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000012467#else
12468 ret = get_errno(readahead(arg1, arg2, arg3));
12469#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012470 return ret;
thse5febef2007-04-01 18:31:35 +000012471#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012472#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000012473#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000012474 case TARGET_NR_listxattr:
12475 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000012476 {
Laurent Vivier77c9f172023-09-25 17:10:29 +020012477 void *b = 0;
Peter Maydellfb5590f2011-12-14 15:37:19 +000012478 if (arg2) {
12479 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
12480 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012481 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000012482 }
12483 }
12484 p = lock_user_string(arg1);
12485 if (p) {
12486 if (num == TARGET_NR_listxattr) {
12487 ret = get_errno(listxattr(p, b, arg3));
12488 } else {
12489 ret = get_errno(llistxattr(p, b, arg3));
12490 }
12491 } else {
12492 ret = -TARGET_EFAULT;
12493 }
12494 unlock_user(p, arg1, 0);
12495 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012496 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000012497 }
12498 case TARGET_NR_flistxattr:
12499 {
12500 void *b = 0;
12501 if (arg2) {
12502 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
12503 if (!b) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012504 return -TARGET_EFAULT;
Peter Maydellfb5590f2011-12-14 15:37:19 +000012505 }
12506 }
12507 ret = get_errno(flistxattr(arg1, b, arg3));
12508 unlock_user(b, arg2, arg3);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012509 return ret;
Peter Maydellfb5590f2011-12-14 15:37:19 +000012510 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012511 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000012512 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012513 {
Laurent Vivier77c9f172023-09-25 17:10:29 +020012514 void *n, *v = 0;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012515 if (arg3) {
12516 v = lock_user(VERIFY_READ, arg3, arg4, 1);
12517 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012518 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012519 }
12520 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012521 p = lock_user_string(arg1);
12522 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012523 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000012524 if (num == TARGET_NR_setxattr) {
12525 ret = get_errno(setxattr(p, n, v, arg4, arg5));
12526 } else {
12527 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
12528 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012529 } else {
12530 ret = -TARGET_EFAULT;
12531 }
12532 unlock_user(p, arg1, 0);
12533 unlock_user(n, arg2, 0);
12534 unlock_user(v, arg3, 0);
12535 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012536 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000012537 case TARGET_NR_fsetxattr:
12538 {
12539 void *n, *v = 0;
12540 if (arg3) {
12541 v = lock_user(VERIFY_READ, arg3, arg4, 1);
12542 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012543 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000012544 }
12545 }
12546 n = lock_user_string(arg2);
12547 if (n) {
12548 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
12549 } else {
12550 ret = -TARGET_EFAULT;
12551 }
12552 unlock_user(n, arg2, 0);
12553 unlock_user(v, arg3, 0);
12554 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012555 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012556 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000012557 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012558 {
Laurent Vivier77c9f172023-09-25 17:10:29 +020012559 void *n, *v = 0;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012560 if (arg3) {
12561 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
12562 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012563 return -TARGET_EFAULT;
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012564 }
12565 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012566 p = lock_user_string(arg1);
12567 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000012568 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000012569 if (num == TARGET_NR_getxattr) {
12570 ret = get_errno(getxattr(p, n, v, arg4));
12571 } else {
12572 ret = get_errno(lgetxattr(p, n, v, arg4));
12573 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012574 } else {
12575 ret = -TARGET_EFAULT;
12576 }
12577 unlock_user(p, arg1, 0);
12578 unlock_user(n, arg2, 0);
12579 unlock_user(v, arg3, arg4);
12580 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012581 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000012582 case TARGET_NR_fgetxattr:
12583 {
12584 void *n, *v = 0;
12585 if (arg3) {
12586 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
12587 if (!v) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012588 return -TARGET_EFAULT;
Peter Maydell30297b52011-12-14 15:37:18 +000012589 }
12590 }
12591 n = lock_user_string(arg2);
12592 if (n) {
12593 ret = get_errno(fgetxattr(arg1, n, v, arg4));
12594 } else {
12595 ret = -TARGET_EFAULT;
12596 }
12597 unlock_user(n, arg2, 0);
12598 unlock_user(v, arg3, arg4);
12599 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012600 return ret;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012601 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000012602 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012603 {
Laurent Vivier77c9f172023-09-25 17:10:29 +020012604 void *n;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012605 p = lock_user_string(arg1);
12606 n = lock_user_string(arg2);
12607 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000012608 if (num == TARGET_NR_removexattr) {
12609 ret = get_errno(removexattr(p, n));
12610 } else {
12611 ret = get_errno(lremovexattr(p, n));
12612 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012613 } else {
12614 ret = -TARGET_EFAULT;
12615 }
12616 unlock_user(p, arg1, 0);
12617 unlock_user(n, arg2, 0);
12618 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012619 return ret;
Peter Maydell30297b52011-12-14 15:37:18 +000012620 case TARGET_NR_fremovexattr:
12621 {
12622 void *n;
12623 n = lock_user_string(arg2);
12624 if (n) {
12625 ret = get_errno(fremovexattr(arg1, n));
12626 } else {
12627 ret = -TARGET_EFAULT;
12628 }
12629 unlock_user(n, arg2, 0);
12630 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012631 return ret;
bellardebc05482003-09-30 21:08:41 +000012632#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012633#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000012634#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000012635 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012636#if defined(TARGET_MIPS)
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020012637 cpu_env->active_tc.CP0_UserLocal = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012638 return 0;
bellard8d18e892007-11-14 15:18:40 +000012639#elif defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012640 return do_set_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010012641#elif defined(TARGET_M68K)
12642 {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +000012643 TaskState *ts = get_task_state(cpu);
Peter Maydell1ccd9372013-07-16 18:44:55 +010012644 ts->tp_value = arg1;
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012645 return 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012646 }
ths6f5b89a2007-03-02 20:48:00 +000012647#else
Richard Henderson10f45d92018-08-18 12:01:07 -070012648 return -TARGET_ENOSYS;
ths6f5b89a2007-03-02 20:48:00 +000012649#endif
12650#endif
12651#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000012652 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012653#if defined(TARGET_I386) && defined(TARGET_ABI32)
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012654 return do_get_thread_area(cpu_env, arg1);
Peter Maydell1ccd9372013-07-16 18:44:55 +010012655#elif defined(TARGET_M68K)
12656 {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +000012657 TaskState *ts = get_task_state(cpu);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012658 return ts->tp_value;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012659 }
bellard8d18e892007-11-14 15:18:40 +000012660#else
Richard Henderson10f45d92018-08-18 12:01:07 -070012661 return -TARGET_ENOSYS;
bellardebc05482003-09-30 21:08:41 +000012662#endif
bellard8d18e892007-11-14 15:18:40 +000012663#endif
bellard48dc41e2006-06-21 18:15:50 +000012664#ifdef TARGET_NR_getdomainname
12665 case TARGET_NR_getdomainname:
Richard Henderson10f45d92018-08-18 12:01:07 -070012666 return -TARGET_ENOSYS;
bellard48dc41e2006-06-21 18:15:50 +000012667#endif
ths6f5b89a2007-03-02 20:48:00 +000012668
Max Filippov12e33402018-04-01 13:13:49 -070012669#ifdef TARGET_NR_clock_settime
12670 case TARGET_NR_clock_settime:
12671 {
12672 struct timespec ts;
12673
12674 ret = target_to_host_timespec(&ts, arg2);
12675 if (!is_error(ret)) {
12676 ret = get_errno(clock_settime(arg1, &ts));
12677 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012678 return ret;
Max Filippov12e33402018-04-01 13:13:49 -070012679 }
12680#endif
Alistair Francisc6c8d102020-03-12 15:13:53 -070012681#ifdef TARGET_NR_clock_settime64
12682 case TARGET_NR_clock_settime64:
12683 {
12684 struct timespec ts;
12685
12686 ret = target_to_host_timespec64(&ts, arg2);
12687 if (!is_error(ret)) {
12688 ret = get_errno(clock_settime(arg1, &ts));
12689 }
12690 return ret;
12691 }
12692#endif
thsb5906f92007-03-19 13:32:45 +000012693#ifdef TARGET_NR_clock_gettime
12694 case TARGET_NR_clock_gettime:
12695 {
12696 struct timespec ts;
12697 ret = get_errno(clock_gettime(arg1, &ts));
12698 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070012699 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000012700 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012701 return ret;
thsb5906f92007-03-19 13:32:45 +000012702 }
12703#endif
Alistair Francisc6c8d102020-03-12 15:13:53 -070012704#ifdef TARGET_NR_clock_gettime64
12705 case TARGET_NR_clock_gettime64:
12706 {
12707 struct timespec ts;
12708 ret = get_errno(clock_gettime(arg1, &ts));
12709 if (!is_error(ret)) {
12710 ret = host_to_target_timespec64(arg2, &ts);
12711 }
12712 return ret;
12713 }
12714#endif
thsb5906f92007-03-19 13:32:45 +000012715#ifdef TARGET_NR_clock_getres
12716 case TARGET_NR_clock_getres:
12717 {
12718 struct timespec ts;
12719 ret = get_errno(clock_getres(arg1, &ts));
12720 if (!is_error(ret)) {
12721 host_to_target_timespec(arg2, &ts);
12722 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012723 return ret;
thsb5906f92007-03-19 13:32:45 +000012724 }
12725#endif
Filip Bozuta828cb3a2020-07-22 17:34:21 +020012726#ifdef TARGET_NR_clock_getres_time64
12727 case TARGET_NR_clock_getres_time64:
12728 {
12729 struct timespec ts;
12730 ret = get_errno(clock_getres(arg1, &ts));
12731 if (!is_error(ret)) {
12732 host_to_target_timespec64(arg2, &ts);
12733 }
12734 return ret;
12735 }
12736#endif
pbrook63d76512008-05-29 13:43:29 +000012737#ifdef TARGET_NR_clock_nanosleep
12738 case TARGET_NR_clock_nanosleep:
12739 {
12740 struct timespec ts;
Filip Bozutab09d6402020-07-27 22:13:26 +020012741 if (target_to_host_timespec(&ts, arg3)) {
12742 return -TARGET_EFAULT;
12743 }
Peter Maydell9e518222016-06-06 19:58:09 +010012744 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12745 &ts, arg4 ? &ts : NULL));
Laurent Vivier8ec68a02020-07-24 07:45:05 +010012746 /*
12747 * if the call is interrupted by a signal handler, it fails
12748 * with error -TARGET_EINTR and if arg4 is not NULL and arg2 is not
12749 * TIMER_ABSTIME, it returns the remaining unslept time in arg4.
12750 */
Filip Bozutab09d6402020-07-27 22:13:26 +020012751 if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME &&
12752 host_to_target_timespec(arg4, &ts)) {
12753 return -TARGET_EFAULT;
Laurent Vivier8ec68a02020-07-24 07:45:05 +010012754 }
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012755
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012756 return ret;
pbrook63d76512008-05-29 13:43:29 +000012757 }
12758#endif
Filip Bozuta6ac03b22020-08-24 21:21:15 +020012759#ifdef TARGET_NR_clock_nanosleep_time64
12760 case TARGET_NR_clock_nanosleep_time64:
12761 {
12762 struct timespec ts;
12763
12764 if (target_to_host_timespec64(&ts, arg3)) {
12765 return -TARGET_EFAULT;
12766 }
12767
12768 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12769 &ts, arg4 ? &ts : NULL));
12770
12771 if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME &&
12772 host_to_target_timespec64(arg4, &ts)) {
12773 return -TARGET_EFAULT;
12774 }
12775 return ret;
12776 }
12777#endif
thsb5906f92007-03-19 13:32:45 +000012778
Helge Deller9a7f6822022-05-28 12:52:10 +020012779#if defined(TARGET_NR_set_tid_address)
ths6f5b89a2007-03-02 20:48:00 +000012780 case TARGET_NR_set_tid_address:
Helge Deller9a7f6822022-05-28 12:52:10 +020012781 {
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +000012782 TaskState *ts = get_task_state(cpu);
Helge Deller9a7f6822022-05-28 12:52:10 +020012783 ts->child_tidptr = arg1;
12784 /* do not call host set_tid_address() syscall, instead return tid() */
12785 return get_errno(sys_gettid());
12786 }
ths6f5b89a2007-03-02 20:48:00 +000012787#endif
12788
ths4cae1d12007-07-12 11:06:53 +000012789 case TARGET_NR_tkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012790 return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000012791
ths71455572007-06-21 21:45:30 +000012792 case TARGET_NR_tgkill:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012793 return get_errno(safe_tgkill((int)arg1, (int)arg2,
12794 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +000012795
ths4f2b1fe2007-06-21 21:57:12 +000012796#ifdef TARGET_NR_set_robust_list
12797 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000012798 case TARGET_NR_get_robust_list:
12799 /* The ABI for supporting robust futexes has userspace pass
12800 * the kernel a pointer to a linked list which is updated by
12801 * userspace after the syscall; the list is walked by the kernel
12802 * when the thread exits. Since the linked list in QEMU guest
12803 * memory isn't a valid linked list for the host and we have
12804 * no way to reliably intercept the thread-death event, we can't
12805 * support these. Silently return ENOSYS so that guest userspace
12806 * falls back to a non-robust futex implementation (which should
12807 * be OK except in the corner case of the guest crashing while
12808 * holding a mutex that is shared with another process via
12809 * shared memory).
12810 */
Richard Henderson10f45d92018-08-18 12:01:07 -070012811 return -TARGET_ENOSYS;
ths4f2b1fe2007-06-21 21:57:12 +000012812#endif
12813
Peter Maydell1acae9f2013-07-02 14:04:12 +010012814#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000012815 case TARGET_NR_utimensat:
12816 {
Riku Voipioebc996f2009-04-21 15:01:51 +030012817 struct timespec *tsp, ts[2];
12818 if (!arg3) {
12819 tsp = NULL;
12820 } else {
Filip Bozutab3a3af72020-08-11 13:31:01 +020012821 if (target_to_host_timespec(ts, arg3)) {
12822 return -TARGET_EFAULT;
12823 }
12824 if (target_to_host_timespec(ts + 1, arg3 +
12825 sizeof(struct target_timespec))) {
12826 return -TARGET_EFAULT;
12827 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012828 tsp = ts;
12829 }
ths9007f0e2007-09-25 17:50:37 +000012830 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030012831 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000012832 else {
bellard579a97f2007-11-11 14:26:47 +000012833 if (!(p = lock_user_string(arg2))) {
Richard Henderson259841c2018-08-18 12:01:09 -070012834 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012835 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012836 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000012837 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000012838 }
12839 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012840 return ret;
ths9007f0e2007-09-25 17:50:37 +000012841#endif
Filip Bozutacac46eb2020-08-25 00:30:50 +020012842#ifdef TARGET_NR_utimensat_time64
12843 case TARGET_NR_utimensat_time64:
12844 {
12845 struct timespec *tsp, ts[2];
12846 if (!arg3) {
12847 tsp = NULL;
12848 } else {
12849 if (target_to_host_timespec64(ts, arg3)) {
12850 return -TARGET_EFAULT;
12851 }
12852 if (target_to_host_timespec64(ts + 1, arg3 +
12853 sizeof(struct target__kernel_timespec))) {
12854 return -TARGET_EFAULT;
12855 }
12856 tsp = ts;
12857 }
12858 if (!arg2)
12859 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
12860 else {
12861 p = lock_user_string(arg2);
12862 if (!p) {
12863 return -TARGET_EFAULT;
12864 }
12865 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
12866 unlock_user(p, arg2, 0);
12867 }
12868 }
12869 return ret;
12870#endif
Alistair Francis859e8a82020-03-12 15:13:49 -070012871#ifdef TARGET_NR_futex
pbrookbd0c5662008-05-29 14:34:11 +000012872 case TARGET_NR_futex:
Richard Henderson0fbc0f82022-08-28 19:09:59 -070012873 return do_futex(cpu, false, arg1, arg2, arg3, arg4, arg5, arg6);
Alistair Francis859e8a82020-03-12 15:13:49 -070012874#endif
Alistair Francis14690292020-03-18 15:47:01 -070012875#ifdef TARGET_NR_futex_time64
12876 case TARGET_NR_futex_time64:
Richard Henderson0fbc0f82022-08-28 19:09:59 -070012877 return do_futex(cpu, true, arg1, arg2, arg3, arg4, arg5, arg6);
Alistair Francis14690292020-03-18 15:47:01 -070012878#endif
Paul Brook33f53ac2022-01-26 20:26:36 +000012879#ifdef CONFIG_INOTIFY
12880#if defined(TARGET_NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000012881 case TARGET_NR_inotify_init:
Paul Brook33f53ac2022-01-26 20:26:36 +000012882 ret = get_errno(inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012883 if (ret >= 0) {
12884 fd_trans_register(ret, &target_inotify_trans);
12885 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012886 return ret;
aurel3239b59762008-10-01 21:46:50 +000012887#endif
Paul Brook33f53ac2022-01-26 20:26:36 +000012888#if defined(TARGET_NR_inotify_init1) && defined(CONFIG_INOTIFY1)
Riku Voipioc05c7a72010-03-26 15:25:11 +000012889 case TARGET_NR_inotify_init1:
Paul Brook33f53ac2022-01-26 20:26:36 +000012890 ret = get_errno(inotify_init1(target_to_host_bitmask(arg1,
Lena Djokicfea243e2016-11-24 17:08:53 +010012891 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012892 if (ret >= 0) {
12893 fd_trans_register(ret, &target_inotify_trans);
12894 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012895 return ret;
Riku Voipioc05c7a72010-03-26 15:25:11 +000012896#endif
Paul Brook33f53ac2022-01-26 20:26:36 +000012897#if defined(TARGET_NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012898 case TARGET_NR_inotify_add_watch:
12899 p = lock_user_string(arg2);
Paul Brook33f53ac2022-01-26 20:26:36 +000012900 ret = get_errno(inotify_add_watch(arg1, path(p), arg3));
aurel3239b59762008-10-01 21:46:50 +000012901 unlock_user(p, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012902 return ret;
aurel3239b59762008-10-01 21:46:50 +000012903#endif
Paul Brook33f53ac2022-01-26 20:26:36 +000012904#if defined(TARGET_NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012905 case TARGET_NR_inotify_rm_watch:
Paul Brook33f53ac2022-01-26 20:26:36 +000012906 return get_errno(inotify_rm_watch(arg1, arg2));
12907#endif
aurel3239b59762008-10-01 21:46:50 +000012908#endif
ths9007f0e2007-09-25 17:50:37 +000012909
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012910#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012911 case TARGET_NR_mq_open:
12912 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012913 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012914 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012915 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012916
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012917 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012918 pposix_mq_attr = NULL;
12919 if (arg4) {
12920 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012921 return -TARGET_EFAULT;
Lena Djokic26400772016-11-24 17:08:58 +010012922 }
12923 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012924 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012925 p = lock_user_string(arg1 - 1);
12926 if (!p) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070012927 return -TARGET_EFAULT;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012928 }
Lena Djokic26400772016-11-24 17:08:58 +010012929 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012930 unlock_user (p, arg1, 0);
12931 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012932 return ret;
aurel3224e10032009-04-15 16:11:43 +000012933
12934 case TARGET_NR_mq_unlink:
12935 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012936 if (!p) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012937 return -TARGET_EFAULT;
Peter Maydell32112152016-07-12 13:02:13 +010012938 }
aurel3224e10032009-04-15 16:11:43 +000012939 ret = get_errno(mq_unlink(p));
12940 unlock_user (p, arg1, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012941 return ret;
aurel3224e10032009-04-15 16:11:43 +000012942
Alistair Francis859e8a82020-03-12 15:13:49 -070012943#ifdef TARGET_NR_mq_timedsend
aurel3224e10032009-04-15 16:11:43 +000012944 case TARGET_NR_mq_timedsend:
12945 {
12946 struct timespec ts;
12947
12948 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12949 if (arg5 != 0) {
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012950 if (target_to_host_timespec(&ts, arg5)) {
12951 return -TARGET_EFAULT;
12952 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012953 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012954 if (!is_error(ret) && host_to_target_timespec(arg5, &ts)) {
12955 return -TARGET_EFAULT;
12956 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012957 } else {
12958 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012959 }
aurel3224e10032009-04-15 16:11:43 +000012960 unlock_user (p, arg2, arg3);
12961 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070012962 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070012963#endif
Filip Bozutad107e372020-08-24 21:37:52 +020012964#ifdef TARGET_NR_mq_timedsend_time64
12965 case TARGET_NR_mq_timedsend_time64:
12966 {
12967 struct timespec ts;
12968
12969 p = lock_user(VERIFY_READ, arg2, arg3, 1);
12970 if (arg5 != 0) {
12971 if (target_to_host_timespec64(&ts, arg5)) {
12972 return -TARGET_EFAULT;
12973 }
12974 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
12975 if (!is_error(ret) && host_to_target_timespec64(arg5, &ts)) {
12976 return -TARGET_EFAULT;
12977 }
12978 } else {
12979 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
12980 }
12981 unlock_user(p, arg2, arg3);
12982 }
12983 return ret;
12984#endif
aurel3224e10032009-04-15 16:11:43 +000012985
Alistair Francis859e8a82020-03-12 15:13:49 -070012986#ifdef TARGET_NR_mq_timedreceive
aurel3224e10032009-04-15 16:11:43 +000012987 case TARGET_NR_mq_timedreceive:
12988 {
12989 struct timespec ts;
12990 unsigned int prio;
12991
12992 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12993 if (arg5 != 0) {
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012994 if (target_to_host_timespec(&ts, arg5)) {
12995 return -TARGET_EFAULT;
12996 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010012997 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12998 &prio, &ts));
Filip Bozutadcbcf5c2020-08-24 21:37:51 +020012999 if (!is_error(ret) && host_to_target_timespec(arg5, &ts)) {
13000 return -TARGET_EFAULT;
13001 }
Peter Maydelld40ecd62016-06-06 19:58:06 +010013002 } else {
13003 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
13004 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000013005 }
aurel3224e10032009-04-15 16:11:43 +000013006 unlock_user (p, arg2, arg3);
13007 if (arg4 != 0)
13008 put_user_u32(prio, arg4);
13009 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013010 return ret;
Alistair Francis859e8a82020-03-12 15:13:49 -070013011#endif
Filip Bozutad107e372020-08-24 21:37:52 +020013012#ifdef TARGET_NR_mq_timedreceive_time64
13013 case TARGET_NR_mq_timedreceive_time64:
13014 {
13015 struct timespec ts;
13016 unsigned int prio;
13017
13018 p = lock_user(VERIFY_READ, arg2, arg3, 1);
13019 if (arg5 != 0) {
13020 if (target_to_host_timespec64(&ts, arg5)) {
13021 return -TARGET_EFAULT;
13022 }
13023 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
13024 &prio, &ts));
13025 if (!is_error(ret) && host_to_target_timespec64(arg5, &ts)) {
13026 return -TARGET_EFAULT;
13027 }
13028 } else {
13029 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
13030 &prio, NULL));
13031 }
13032 unlock_user(p, arg2, arg3);
13033 if (arg4 != 0) {
13034 put_user_u32(prio, arg4);
13035 }
13036 }
13037 return ret;
13038#endif
aurel3224e10032009-04-15 16:11:43 +000013039
13040 /* Not implemented for now... */
13041/* case TARGET_NR_mq_notify: */
13042/* break; */
13043
13044 case TARGET_NR_mq_getsetattr:
13045 {
13046 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
13047 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000013048 if (arg2 != 0) {
13049 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070013050 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
13051 &posix_mq_attr_out));
13052 } else if (arg3 != 0) {
13053 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000013054 }
Max Filippova23ea402018-03-31 08:20:15 -070013055 if (ret == 0 && arg3 != 0) {
13056 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
13057 }
aurel3224e10032009-04-15 16:11:43 +000013058 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013059 return ret;
aurel3224e10032009-04-15 16:11:43 +000013060#endif
13061
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013062#ifdef CONFIG_SPLICE
13063#ifdef TARGET_NR_tee
13064 case TARGET_NR_tee:
13065 {
13066 ret = get_errno(tee(arg1,arg2,arg3,arg4));
13067 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013068 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013069#endif
13070#ifdef TARGET_NR_splice
13071 case TARGET_NR_splice:
13072 {
13073 loff_t loff_in, loff_out;
13074 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010013075 if (arg2) {
13076 if (get_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013077 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010013078 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013079 ploff_in = &loff_in;
13080 }
Andreas Schwab17644b32015-03-10 17:11:35 +010013081 if (arg4) {
13082 if (get_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013083 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010013084 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013085 ploff_out = &loff_out;
13086 }
13087 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010013088 if (arg2) {
13089 if (put_user_u64(loff_in, arg2)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013090 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010013091 }
13092 }
13093 if (arg4) {
13094 if (put_user_u64(loff_out, arg4)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013095 return -TARGET_EFAULT;
Andreas Schwab17644b32015-03-10 17:11:35 +010013096 }
13097 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013098 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013099 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013100#endif
13101#ifdef TARGET_NR_vmsplice
13102 case TARGET_NR_vmsplice:
13103 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070013104 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
13105 if (vec != NULL) {
13106 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
13107 unlock_iovec(vec, arg2, arg3, 0);
13108 } else {
13109 ret = -host_to_target_errno(errno);
13110 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013111 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013112 return ret;
vibisreenivasan3ce34df2009-05-16 18:32:41 +053013113#endif
13114#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030013115#ifdef CONFIG_EVENTFD
13116#if defined(TARGET_NR_eventfd)
13117 case TARGET_NR_eventfd:
13118 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030013119 if (ret >= 0) {
13120 fd_trans_register(ret, &target_eventfd_trans);
13121 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013122 return ret;
Riku Voipioc2882b92009-08-12 15:08:24 +030013123#endif
13124#if defined(TARGET_NR_eventfd2)
13125 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020013126 {
Helge Deller78721302021-02-10 07:12:14 +010013127 int host_flags = arg2 & (~(TARGET_O_NONBLOCK_MASK | TARGET_O_CLOEXEC));
Petar Jovanovic5947c692013-04-08 20:26:10 +020013128 if (arg2 & TARGET_O_NONBLOCK) {
13129 host_flags |= O_NONBLOCK;
13130 }
13131 if (arg2 & TARGET_O_CLOEXEC) {
13132 host_flags |= O_CLOEXEC;
13133 }
13134 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030013135 if (ret >= 0) {
13136 fd_trans_register(ret, &target_eventfd_trans);
13137 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013138 return ret;
Petar Jovanovic5947c692013-04-08 20:26:10 +020013139 }
Riku Voipioc2882b92009-08-12 15:08:24 +030013140#endif
13141#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030013142#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
13143 case TARGET_NR_fallocate:
WANG Xueruieeed2292022-10-06 16:55:00 +080013144#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32)
Alexander Graf20249ae2012-02-06 21:37:07 +010013145 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
13146 target_offset64(arg5, arg6)));
13147#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030013148 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010013149#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013150 return ret;
Ulrich Hechtd0927932009-09-17 20:22:14 +030013151#endif
Peter Maydellc727f472011-01-06 11:05:10 +000013152#if defined(CONFIG_SYNC_FILE_RANGE)
13153#if defined(TARGET_NR_sync_file_range)
13154 case TARGET_NR_sync_file_range:
WANG Xueruieeed2292022-10-06 16:55:00 +080013155#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32)
Riku Voipiobfcedc52011-06-20 16:24:39 +030013156#if defined(TARGET_MIPS)
13157 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
13158 target_offset64(arg5, arg6), arg7));
13159#else
Peter Maydellc727f472011-01-06 11:05:10 +000013160 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
13161 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030013162#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000013163#else
13164 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
13165#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013166 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000013167#endif
Laurent Vivier5bcb4982020-03-10 11:33:50 +010013168#if defined(TARGET_NR_sync_file_range2) || \
13169 defined(TARGET_NR_arm_sync_file_range)
Peter Maydellc727f472011-01-06 11:05:10 +000013170#if defined(TARGET_NR_sync_file_range2)
13171 case TARGET_NR_sync_file_range2:
Laurent Vivier5bcb4982020-03-10 11:33:50 +010013172#endif
13173#if defined(TARGET_NR_arm_sync_file_range)
13174 case TARGET_NR_arm_sync_file_range:
13175#endif
Peter Maydellc727f472011-01-06 11:05:10 +000013176 /* This is like sync_file_range but the arguments are reordered */
WANG Xueruieeed2292022-10-06 16:55:00 +080013177#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32)
Peter Maydellc727f472011-01-06 11:05:10 +000013178 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
13179 target_offset64(arg5, arg6), arg2));
13180#else
13181 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
13182#endif
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013183 return ret;
Peter Maydellc727f472011-01-06 11:05:10 +000013184#endif
13185#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020013186#if defined(TARGET_NR_signalfd4)
13187 case TARGET_NR_signalfd4:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013188 return do_signalfd4(arg1, arg2, arg4);
Laurent Viviere36800c2015-10-02 14:48:09 +020013189#endif
13190#if defined(TARGET_NR_signalfd)
13191 case TARGET_NR_signalfd:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013192 return do_signalfd4(arg1, arg2, 0);
Laurent Viviere36800c2015-10-02 14:48:09 +020013193#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000013194#if defined(CONFIG_EPOLL)
13195#if defined(TARGET_NR_epoll_create)
13196 case TARGET_NR_epoll_create:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013197 return get_errno(epoll_create(arg1));
Peter Maydell3b6edd12011-02-15 18:35:05 +000013198#endif
13199#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
13200 case TARGET_NR_epoll_create1:
Sergei Trofimovich386d3862020-04-15 23:05:08 +010013201 return get_errno(epoll_create1(target_to_host_bitmask(arg1, fcntl_flags_tbl)));
Peter Maydell3b6edd12011-02-15 18:35:05 +000013202#endif
13203#if defined(TARGET_NR_epoll_ctl)
13204 case TARGET_NR_epoll_ctl:
13205 {
13206 struct epoll_event ep;
13207 struct epoll_event *epp = 0;
13208 if (arg4) {
LemonBoyc7811022020-04-17 17:34:54 +020013209 if (arg2 != EPOLL_CTL_DEL) {
13210 struct target_epoll_event *target_ep;
13211 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
13212 return -TARGET_EFAULT;
13213 }
13214 ep.events = tswap32(target_ep->events);
13215 /*
13216 * The epoll_data_t union is just opaque data to the kernel,
13217 * so we transfer all 64 bits across and need not worry what
13218 * actual data type it is.
13219 */
13220 ep.data.u64 = tswap64(target_ep->data.u64);
13221 unlock_user_struct(target_ep, arg4, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000013222 }
LemonBoyc7811022020-04-17 17:34:54 +020013223 /*
13224 * before kernel 2.6.9, EPOLL_CTL_DEL operation required a
13225 * non-null pointer, even though this argument is ignored.
13226 *
Peter Maydell3b6edd12011-02-15 18:35:05 +000013227 */
Peter Maydell3b6edd12011-02-15 18:35:05 +000013228 epp = &ep;
13229 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013230 return get_errno(epoll_ctl(arg1, arg2, arg3, epp));
Peter Maydell3b6edd12011-02-15 18:35:05 +000013231 }
13232#endif
13233
Peter Maydell227f0212016-06-06 19:58:11 +010013234#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000013235#if defined(TARGET_NR_epoll_wait)
13236 case TARGET_NR_epoll_wait:
13237#endif
Peter Maydell227f0212016-06-06 19:58:11 +010013238#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000013239 case TARGET_NR_epoll_pwait:
13240#endif
13241 {
13242 struct target_epoll_event *target_ep;
13243 struct epoll_event *ep;
13244 int epfd = arg1;
13245 int maxevents = arg3;
13246 int timeout = arg4;
13247
Peter Maydell2ba7fae32016-07-18 15:35:59 +010013248 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013249 return -TARGET_EINVAL;
Peter Maydell2ba7fae32016-07-18 15:35:59 +010013250 }
13251
Peter Maydell3b6edd12011-02-15 18:35:05 +000013252 target_ep = lock_user(VERIFY_WRITE, arg2,
13253 maxevents * sizeof(struct target_epoll_event), 1);
13254 if (!target_ep) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013255 return -TARGET_EFAULT;
Peter Maydell3b6edd12011-02-15 18:35:05 +000013256 }
13257
Peter Maydell04c95f42016-07-18 15:36:00 +010013258 ep = g_try_new(struct epoll_event, maxevents);
13259 if (!ep) {
13260 unlock_user(target_ep, arg2, 0);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013261 return -TARGET_ENOMEM;
Peter Maydell04c95f42016-07-18 15:36:00 +010013262 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000013263
13264 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010013265#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000013266 case TARGET_NR_epoll_pwait:
13267 {
Richard Hendersoncd0e31a2022-03-15 01:43:07 -070013268 sigset_t *set = NULL;
Peter Maydell3b6edd12011-02-15 18:35:05 +000013269
13270 if (arg5) {
Richard Hendersoncd0e31a2022-03-15 01:43:07 -070013271 ret = process_sigsuspend_mask(&set, arg5, arg6);
13272 if (ret != 0) {
Peter Maydellc8157012016-06-30 14:23:24 +010013273 break;
13274 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000013275 }
13276
Peter Maydell227f0212016-06-06 19:58:11 +010013277 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
13278 set, SIGSET_T_SIZE));
Richard Hendersoncd0e31a2022-03-15 01:43:07 -070013279
13280 if (set) {
13281 finish_sigsuspend_mask(ret);
13282 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000013283 break;
13284 }
13285#endif
13286#if defined(TARGET_NR_epoll_wait)
13287 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010013288 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
13289 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000013290 break;
13291#endif
13292 default:
13293 ret = -TARGET_ENOSYS;
13294 }
13295 if (!is_error(ret)) {
13296 int i;
13297 for (i = 0; i < ret; i++) {
13298 target_ep[i].events = tswap32(ep[i].events);
13299 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
13300 }
Peter Maydell04c95f42016-07-18 15:36:00 +010013301 unlock_user(target_ep, arg2,
13302 ret * sizeof(struct target_epoll_event));
13303 } else {
13304 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000013305 }
Peter Maydell04c95f42016-07-18 15:36:00 +010013306 g_free(ep);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013307 return ret;
Peter Maydell3b6edd12011-02-15 18:35:05 +000013308 }
13309#endif
13310#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010013311#ifdef TARGET_NR_prlimit64
13312 case TARGET_NR_prlimit64:
13313 {
13314 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
13315 struct target_rlimit64 *target_rnew, *target_rold;
13316 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010013317 int resource = target_to_host_resource(arg2);
Tobias Koch055d92f2020-03-05 21:24:00 +010013318
13319 if (arg3 && (resource != RLIMIT_AS &&
13320 resource != RLIMIT_DATA &&
13321 resource != RLIMIT_STACK)) {
Peter Maydell163a05a2011-06-27 17:44:52 +010013322 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013323 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010013324 }
Ilya Leoshkevich9c1da8b2023-02-24 01:39:06 +010013325 __get_user(rnew.rlim_cur, &target_rnew->rlim_cur);
13326 __get_user(rnew.rlim_max, &target_rnew->rlim_max);
Peter Maydell163a05a2011-06-27 17:44:52 +010013327 unlock_user_struct(target_rnew, arg3, 0);
13328 rnewp = &rnew;
13329 }
13330
Felix Janda95018012014-12-02 22:11:17 +010013331 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010013332 if (!is_error(ret) && arg4) {
13333 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013334 return -TARGET_EFAULT;
Peter Maydell163a05a2011-06-27 17:44:52 +010013335 }
Ilya Leoshkevich9c1da8b2023-02-24 01:39:06 +010013336 __put_user(rold.rlim_cur, &target_rold->rlim_cur);
13337 __put_user(rold.rlim_max, &target_rold->rlim_max);
Peter Maydell163a05a2011-06-27 17:44:52 +010013338 unlock_user_struct(target_rold, arg4, 1);
13339 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013340 return ret;
Peter Maydell163a05a2011-06-27 17:44:52 +010013341 }
13342#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070013343#ifdef TARGET_NR_gethostname
13344 case TARGET_NR_gethostname:
13345 {
13346 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
13347 if (name) {
13348 ret = get_errno(gethostname(name, arg2));
13349 unlock_user(name, arg1, arg2);
13350 } else {
13351 ret = -TARGET_EFAULT;
13352 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013353 return ret;
Richard Henderson3d21d292012-09-15 13:20:46 -070013354 }
13355#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030013356#ifdef TARGET_NR_atomic_cmpxchg_32
13357 case TARGET_NR_atomic_cmpxchg_32:
13358 {
13359 /* should use start_exclusive from main.c */
13360 abi_ulong mem_value;
13361 if (get_user_u32(mem_value, arg6)) {
13362 target_siginfo_t info;
13363 info.si_signo = SIGSEGV;
13364 info.si_errno = 0;
13365 info.si_code = TARGET_SEGV_MAPERR;
13366 info._sifields._sigfault._addr = arg6;
Philippe Mathieu-Daudé0effdc22022-05-09 22:57:28 +020013367 queue_signal(cpu_env, info.si_signo, QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030013368 ret = 0xdeadbeef;
13369
13370 }
13371 if (mem_value == arg2)
13372 put_user_u32(arg1, arg6);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013373 return mem_value;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030013374 }
13375#endif
13376#ifdef TARGET_NR_atomic_barrier
13377 case TARGET_NR_atomic_barrier:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013378 /* Like the kernel implementation and the
13379 qemu arm barrier, no-op this? */
13380 return 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030013381#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013382
13383#ifdef TARGET_NR_timer_create
13384 case TARGET_NR_timer_create:
13385 {
13386 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
13387
13388 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013389
13390 int clkid = arg1;
13391 int timer_index = next_free_host_timer();
13392
13393 if (timer_index < 0) {
13394 ret = -TARGET_EAGAIN;
13395 } else {
13396 timer_t *phtimer = g_posix_timers + timer_index;
13397
13398 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013399 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010013400 ret = target_to_host_sigevent(phost_sevp, arg2);
13401 if (ret != 0) {
Peter Maydell9e598992022-07-25 12:00:35 +010013402 free_host_timer_slot(timer_index);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013403 return ret;
Peter Maydellc0659762014-08-09 15:42:32 +010013404 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013405 }
13406
13407 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
13408 if (ret) {
Peter Maydell9e598992022-07-25 12:00:35 +010013409 free_host_timer_slot(timer_index);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013410 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010013411 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Peter Maydell9e598992022-07-25 12:00:35 +010013412 timer_delete(*phtimer);
13413 free_host_timer_slot(timer_index);
Richard Henderson2852aaf2018-08-18 12:01:06 -070013414 return -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013415 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013416 }
13417 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013418 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013419 }
13420#endif
13421
13422#ifdef TARGET_NR_timer_settime
13423 case TARGET_NR_timer_settime:
13424 {
13425 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
13426 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010013427 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020013428
Alexander Grafaecc8862014-11-10 21:33:03 +010013429 if (timerid < 0) {
13430 ret = timerid;
13431 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013432 ret = -TARGET_EINVAL;
13433 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020013434 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013435 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
13436
Marc-André Lureau40c80b52017-01-19 10:15:32 -050013437 if (target_to_host_itimerspec(&hspec_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013438 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050013439 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013440 ret = get_errno(
13441 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050013442 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013443 return -TARGET_EFAULT;
Marc-André Lureau40c80b52017-01-19 10:15:32 -050013444 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013445 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013446 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013447 }
13448#endif
13449
Filip Bozuta828cb3a2020-07-22 17:34:21 +020013450#ifdef TARGET_NR_timer_settime64
13451 case TARGET_NR_timer_settime64:
13452 {
13453 target_timer_t timerid = get_timer_id(arg1);
13454
13455 if (timerid < 0) {
13456 ret = timerid;
13457 } else if (arg3 == 0) {
13458 ret = -TARGET_EINVAL;
13459 } else {
13460 timer_t htimer = g_posix_timers[timerid];
13461 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
13462
13463 if (target_to_host_itimerspec64(&hspec_new, arg3)) {
13464 return -TARGET_EFAULT;
13465 }
13466 ret = get_errno(
13467 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
13468 if (arg4 && host_to_target_itimerspec64(arg4, &hspec_old)) {
13469 return -TARGET_EFAULT;
13470 }
13471 }
13472 return ret;
13473 }
13474#endif
13475
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013476#ifdef TARGET_NR_timer_gettime
13477 case TARGET_NR_timer_gettime:
13478 {
13479 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010013480 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020013481
Alexander Grafaecc8862014-11-10 21:33:03 +010013482 if (timerid < 0) {
13483 ret = timerid;
13484 } else if (!arg2) {
13485 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013486 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020013487 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013488 struct itimerspec hspec;
13489 ret = get_errno(timer_gettime(htimer, &hspec));
13490
13491 if (host_to_target_itimerspec(arg2, &hspec)) {
13492 ret = -TARGET_EFAULT;
13493 }
13494 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013495 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013496 }
13497#endif
13498
Filip Bozuta828cb3a2020-07-22 17:34:21 +020013499#ifdef TARGET_NR_timer_gettime64
13500 case TARGET_NR_timer_gettime64:
13501 {
13502 /* args: timer_t timerid, struct itimerspec64 *curr_value */
13503 target_timer_t timerid = get_timer_id(arg1);
13504
13505 if (timerid < 0) {
13506 ret = timerid;
13507 } else if (!arg2) {
13508 ret = -TARGET_EFAULT;
13509 } else {
13510 timer_t htimer = g_posix_timers[timerid];
13511 struct itimerspec hspec;
13512 ret = get_errno(timer_gettime(htimer, &hspec));
13513
13514 if (host_to_target_itimerspec64(arg2, &hspec)) {
13515 ret = -TARGET_EFAULT;
13516 }
13517 }
13518 return ret;
13519 }
13520#endif
13521
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013522#ifdef TARGET_NR_timer_getoverrun
13523 case TARGET_NR_timer_getoverrun:
13524 {
13525 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010013526 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020013527
Alexander Grafaecc8862014-11-10 21:33:03 +010013528 if (timerid < 0) {
13529 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013530 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020013531 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013532 ret = get_errno(timer_getoverrun(htimer));
13533 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013534 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013535 }
13536#endif
13537
13538#ifdef TARGET_NR_timer_delete
13539 case TARGET_NR_timer_delete:
13540 {
13541 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010013542 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020013543
Alexander Grafaecc8862014-11-10 21:33:03 +010013544 if (timerid < 0) {
13545 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013546 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020013547 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013548 ret = get_errno(timer_delete(htimer));
Peter Maydell9e598992022-07-25 12:00:35 +010013549 free_host_timer_slot(timerid);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013550 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013551 return ret;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110013552 }
13553#endif
13554
Riku Voipio51834342014-06-22 11:25:42 +010013555#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
13556 case TARGET_NR_timerfd_create:
Mathis Mariond759a622023-02-20 09:58:19 +010013557 ret = get_errno(timerfd_create(arg1,
13558 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
13559 if (ret >= 0) {
13560 fd_trans_register(ret, &target_timerfd_trans);
13561 }
13562 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010013563#endif
13564
13565#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
13566 case TARGET_NR_timerfd_gettime:
13567 {
13568 struct itimerspec its_curr;
13569
13570 ret = get_errno(timerfd_gettime(arg1, &its_curr));
13571
13572 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013573 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010013574 }
13575 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013576 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010013577#endif
13578
Filip Bozuta828cb3a2020-07-22 17:34:21 +020013579#if defined(TARGET_NR_timerfd_gettime64) && defined(CONFIG_TIMERFD)
13580 case TARGET_NR_timerfd_gettime64:
13581 {
13582 struct itimerspec its_curr;
13583
13584 ret = get_errno(timerfd_gettime(arg1, &its_curr));
13585
13586 if (arg2 && host_to_target_itimerspec64(arg2, &its_curr)) {
13587 return -TARGET_EFAULT;
13588 }
13589 }
13590 return ret;
13591#endif
13592
Riku Voipio51834342014-06-22 11:25:42 +010013593#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
13594 case TARGET_NR_timerfd_settime:
13595 {
13596 struct itimerspec its_new, its_old, *p_new;
13597
13598 if (arg3) {
13599 if (target_to_host_itimerspec(&its_new, arg3)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013600 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010013601 }
13602 p_new = &its_new;
13603 } else {
13604 p_new = NULL;
13605 }
13606
13607 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
13608
13609 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
Richard Henderson2852aaf2018-08-18 12:01:06 -070013610 return -TARGET_EFAULT;
Riku Voipio51834342014-06-22 11:25:42 +010013611 }
13612 }
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013613 return ret;
Riku Voipio51834342014-06-22 11:25:42 +010013614#endif
13615
Filip Bozuta828cb3a2020-07-22 17:34:21 +020013616#if defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD)
13617 case TARGET_NR_timerfd_settime64:
13618 {
13619 struct itimerspec its_new, its_old, *p_new;
13620
13621 if (arg3) {
13622 if (target_to_host_itimerspec64(&its_new, arg3)) {
13623 return -TARGET_EFAULT;
13624 }
13625 p_new = &its_new;
13626 } else {
13627 p_new = NULL;
13628 }
13629
13630 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
13631
13632 if (arg4 && host_to_target_itimerspec64(arg4, &its_old)) {
13633 return -TARGET_EFAULT;
13634 }
13635 }
13636 return ret;
13637#endif
13638
Paul Burtonab31cda2014-06-22 11:25:43 +010013639#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
13640 case TARGET_NR_ioprio_get:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013641 return get_errno(ioprio_get(arg1, arg2));
Paul Burtonab31cda2014-06-22 11:25:43 +010013642#endif
13643
13644#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
13645 case TARGET_NR_ioprio_set:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013646 return get_errno(ioprio_set(arg1, arg2, arg3));
Paul Burtonab31cda2014-06-22 11:25:43 +010013647#endif
13648
Riku Voipio9af5c902014-08-12 15:58:57 +030013649#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
13650 case TARGET_NR_setns:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013651 return get_errno(setns(arg1, arg2));
Riku Voipio9af5c902014-08-12 15:58:57 +030013652#endif
13653#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
13654 case TARGET_NR_unshare:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013655 return get_errno(unshare(arg1));
Riku Voipio9af5c902014-08-12 15:58:57 +030013656#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020013657#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
13658 case TARGET_NR_kcmp:
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013659 return get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
Laurent Vivier2f147882016-09-25 22:20:20 +020013660#endif
Richard Hendersonfa97e382018-07-18 13:06:48 -070013661#ifdef TARGET_NR_swapcontext
13662 case TARGET_NR_swapcontext:
13663 /* PowerPC specific. */
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013664 return do_swapcontext(cpu_env, arg1, arg2, arg3);
Richard Hendersonfa97e382018-07-18 13:06:48 -070013665#endif
Shu-Chun Weng9bdfa4d2019-08-19 11:09:47 -070013666#ifdef TARGET_NR_memfd_create
13667 case TARGET_NR_memfd_create:
13668 p = lock_user_string(arg1);
13669 if (!p) {
13670 return -TARGET_EFAULT;
13671 }
13672 ret = get_errno(memfd_create(p, arg2));
13673 fd_trans_unregister(ret);
13674 unlock_user(p, arg1, 0);
13675 return ret;
13676#endif
Andreas Schwab85004762019-05-13 11:02:53 +020013677#if defined TARGET_NR_membarrier && defined __NR_membarrier
13678 case TARGET_NR_membarrier:
13679 return get_errno(membarrier(arg1, arg2));
13680#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030013681
Andreas Schwab84946452020-11-12 12:45:16 +010013682#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range)
13683 case TARGET_NR_copy_file_range:
13684 {
13685 loff_t inoff, outoff;
13686 loff_t *pinoff = NULL, *poutoff = NULL;
13687
13688 if (arg2) {
13689 if (get_user_u64(inoff, arg2)) {
13690 return -TARGET_EFAULT;
13691 }
13692 pinoff = &inoff;
13693 }
13694 if (arg4) {
13695 if (get_user_u64(outoff, arg4)) {
13696 return -TARGET_EFAULT;
13697 }
13698 poutoff = &outoff;
13699 }
Giuseppe Musacchio0fa259d2021-05-03 19:41:59 +020013700 /* Do not sign-extend the count parameter. */
Andreas Schwab84946452020-11-12 12:45:16 +010013701 ret = get_errno(safe_copy_file_range(arg1, pinoff, arg3, poutoff,
Giuseppe Musacchio0fa259d2021-05-03 19:41:59 +020013702 (abi_ulong)arg5, arg6));
Andreas Schwab84946452020-11-12 12:45:16 +010013703 if (!is_error(ret) && ret > 0) {
13704 if (arg2) {
13705 if (put_user_u64(inoff, arg2)) {
13706 return -TARGET_EFAULT;
13707 }
13708 }
13709 if (arg4) {
13710 if (put_user_u64(outoff, arg4)) {
13711 return -TARGET_EFAULT;
13712 }
13713 }
13714 }
13715 }
13716 return ret;
13717#endif
13718
YAMAMOTO Takashie10fbe82021-05-31 14:50:12 +090013719#if defined(TARGET_NR_pivot_root)
13720 case TARGET_NR_pivot_root:
13721 {
13722 void *p2;
13723 p = lock_user_string(arg1); /* new_root */
13724 p2 = lock_user_string(arg2); /* put_old */
13725 if (!p || !p2) {
13726 ret = -TARGET_EFAULT;
13727 } else {
13728 ret = get_errno(pivot_root(p, p2));
13729 }
13730 unlock_user(p2, arg2, 0);
13731 unlock_user(p, arg1, 0);
13732 }
13733 return ret;
13734#endif
13735
Robbin Ehn9e1c7d92023-06-19 10:24:03 +020013736#if defined(TARGET_NR_riscv_hwprobe)
13737 case TARGET_NR_riscv_hwprobe:
13738 return do_riscv_hwprobe(cpu_env, arg1, arg2, arg3, arg4, arg5);
13739#endif
13740
bellard31e31b82003-02-18 22:55:36 +000013741 default:
Philippe Mathieu-Daudé122f9c82018-07-06 12:51:25 -030013742 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
Richard Henderson72eb7ea2018-08-18 12:01:05 -070013743 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000013744 }
bellard31e31b82003-02-18 22:55:36 +000013745 return ret;
13746}
Richard Hendersondc1ce182018-08-18 12:01:04 -070013747
Philippe Mathieu-Daudéa0939b82022-05-09 22:57:27 +020013748abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
Richard Hendersondc1ce182018-08-18 12:01:04 -070013749 abi_long arg2, abi_long arg3, abi_long arg4,
13750 abi_long arg5, abi_long arg6, abi_long arg7,
13751 abi_long arg8)
13752{
Richard Henderson29a0af62019-03-22 16:07:18 -070013753 CPUState *cpu = env_cpu(cpu_env);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013754 abi_long ret;
13755
13756#ifdef DEBUG_ERESTARTSYS
13757 /* Debug-only code for exercising the syscall-restart code paths
13758 * in the per-architecture cpu main loops: restart every syscall
13759 * the guest makes once before letting it through.
13760 */
13761 {
13762 static bool flag;
13763 flag = !flag;
13764 if (flag) {
Richard Hendersonaf254a22021-11-22 19:47:33 +010013765 return -QEMU_ERESTARTSYS;
Richard Hendersondc1ce182018-08-18 12:01:04 -070013766 }
13767 }
13768#endif
13769
Emilio G. Cotac36f7a62018-10-21 13:27:44 -040013770 record_syscall_start(cpu, num, arg1,
13771 arg2, arg3, arg4, arg5, arg6, arg7, arg8);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013772
Josh Kunz4b25a502020-02-03 18:54:14 -080013773 if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
Filip Bozutae400e112020-08-11 18:45:49 +020013774 print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6);
Josh Kunz4b25a502020-02-03 18:54:14 -080013775 }
13776
13777 ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
13778 arg5, arg6, arg7, arg8);
13779
13780 if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
Filip Bozutae400e112020-08-11 18:45:49 +020013781 print_syscall_ret(cpu_env, num, ret, arg1, arg2,
13782 arg3, arg4, arg5, arg6);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013783 }
13784
Emilio G. Cotac36f7a62018-10-21 13:27:44 -040013785 record_syscall_return(cpu, num, ret);
Richard Hendersondc1ce182018-08-18 12:01:04 -070013786 return ret;
13787}