blob: 1806b33b02fc3f2a192b83a75f1911379775d05f [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
Peter Maydelld39594e2016-01-26 18:17:02 +000020#include "qemu/osdep.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020021#include "qemu/cutils.h"
22#include "qemu/path.h"
bellard31e31b82003-02-18 22:55:36 +000023#include <elf.h>
24#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010025#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000026#include <sys/ipc.h>
27#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000029#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010030#include <sys/file.h>
31#include <sys/fsuid.h>
32#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000033#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000036#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000037#include <sched.h>
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020038#include <sys/timex.h>
bellard31e31b82003-02-18 22:55:36 +000039#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000040#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000041#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040042#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000043#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000044#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000045#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000046#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000047#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000048#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020049#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000050//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000051#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000052#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020053#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000054#include <linux/icmp.h>
Helge Delleree1ac3a2017-02-18 23:31:30 +010055#include <linux/icmpv6.h>
56#include <linux/errqueue.h>
Marco A L Barbosad6d6d6f2017-10-05 10:55:30 -030057#include <linux/random.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020058#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030059#ifdef CONFIG_TIMERFD
60#include <sys/timerfd.h>
61#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020062#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000063#include <sys/gmon.h>
64#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030065#ifdef CONFIG_EVENTFD
66#include <sys/eventfd.h>
67#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000068#ifdef CONFIG_EPOLL
69#include <sys/epoll.h>
70#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070071#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010072#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000074#ifdef CONFIG_SENDFILE
75#include <sys/sendfile.h>
76#endif
bellard31e31b82003-02-18 22:55:36 +000077
78#define termios host_termios
79#define winsize host_winsize
80#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000081#define sgttyb host_sgttyb /* same as target */
82#define tchars host_tchars /* same as target */
83#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000084
85#include <linux/termios.h>
86#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000087#include <linux/cdrom.h>
88#include <linux/hdreg.h>
89#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000090#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000091#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030092#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000093#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000094#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020096#include <linux/fb.h>
97#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010098#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +000099#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100100#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200101#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100102#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200103#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200104#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200105#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200106#include <linux/rtnetlink.h>
Laurent Vivierc5dff282016-06-27 18:54:30 +0200107#include <linux/if_bridge.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200108#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200109#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000110#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200111#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000112
bellard3ef693a2003-03-23 20:17:16 +0000113#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000114
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100115#ifndef CLONE_IO
116#define CLONE_IO 0x80000000 /* Clone io context */
117#endif
118
119/* We can't directly call the host clone syscall, because this will
120 * badly confuse libc (breaking mutexes, for example). So we must
121 * divide clone flags into:
122 * * flag combinations that look like pthread_create()
123 * * flag combinations that look like fork()
124 * * flags we can implement within QEMU itself
125 * * flags we can't support and will return an error for
126 */
127/* For thread creation, all these flags must be present; for
128 * fork, none must be present.
129 */
130#define CLONE_THREAD_FLAGS \
131 (CLONE_VM | CLONE_FS | CLONE_FILES | \
132 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
133
134/* These flags are ignored:
135 * CLONE_DETACHED is now ignored by the kernel;
136 * CLONE_IO is just an optimisation hint to the I/O scheduler
137 */
138#define CLONE_IGNORED_FLAGS \
139 (CLONE_DETACHED | CLONE_IO)
140
141/* Flags for fork which we can implement within QEMU itself */
142#define CLONE_OPTIONAL_FORK_FLAGS \
143 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
144 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
145
146/* Flags for thread creation which we can implement within QEMU itself */
147#define CLONE_OPTIONAL_THREAD_FLAGS \
148 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
149 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
150
151#define CLONE_INVALID_FORK_FLAGS \
152 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
153
154#define CLONE_INVALID_THREAD_FLAGS \
155 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
156 CLONE_IGNORED_FLAGS))
157
158/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
159 * have almost all been allocated. We cannot support any of
160 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
161 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
162 * The checks against the invalid thread masks above will catch these.
163 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
164 */
pbrook30813ce2008-06-02 15:45:44 +0000165
bellard72f03902003-02-18 23:33:18 +0000166//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100167/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
168 * once. This exercises the codepaths for restart.
169 */
170//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000171
bellard1a9353d2003-03-16 20:28:50 +0000172//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000173#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
174#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000175
bellard70a194b2003-08-11 22:20:16 +0000176#undef _syscall0
177#undef _syscall1
178#undef _syscall2
179#undef _syscall3
180#undef _syscall4
181#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000182#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000183
bellard83fcb512006-06-14 13:37:16 +0000184#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000185static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000186{ \
187 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000188}
189
bellard83fcb512006-06-14 13:37:16 +0000190#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000191static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000192{ \
193 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000194}
195
bellard83fcb512006-06-14 13:37:16 +0000196#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000197static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000198{ \
199 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000200}
201
bellard83fcb512006-06-14 13:37:16 +0000202#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000203static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000204{ \
205 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000206}
207
bellard83fcb512006-06-14 13:37:16 +0000208#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000209static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000210{ \
211 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000212}
213
bellard83fcb512006-06-14 13:37:16 +0000214#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
215 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000216static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000217{ \
218 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000219}
bellard83fcb512006-06-14 13:37:16 +0000220
221
222#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
223 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000224static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
225 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000226{ \
227 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
228}
229
bellard70a194b2003-08-11 22:20:16 +0000230
bellard31e31b82003-02-18 22:55:36 +0000231#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000232#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000233#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000234#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000235#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000236#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200237#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000238#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000239#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000240#define __NR_sys_inotify_init __NR_inotify_init
241#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
242#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000243
Peter Maydellb1cef6d2018-01-25 16:19:49 +0000244#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000245#define __NR__llseek __NR_lseek
246#endif
247
James Hogana29e5ba2014-03-25 21:51:08 +0000248/* Newer kernel ports have llseek() instead of _llseek() */
249#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
250#define TARGET_NR__llseek TARGET_NR_llseek
251#endif
252
bellard72f03902003-02-18 23:33:18 +0000253#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000254_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000255#else
ths0da46a62007-10-20 20:23:07 +0000256/* This is a replacement for the host gettid() and must return a host
257 errno. */
bellard72f03902003-02-18 23:33:18 +0000258static int gettid(void) {
259 return -ENOSYS;
260}
261#endif
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100262
263/* For the 64-bit guest on 32-bit host case we must emulate
264 * getdents using getdents64, because otherwise the host
265 * might hand us back more dirent records than we can fit
266 * into the guest buffer after structure format conversion.
267 * Otherwise we emulate getdents with getdents if the host has it.
268 */
269#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
270#define EMULATE_GETDENTS_WITH_GETDENTS
271#endif
272
273#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
aurel323b3f24a2009-04-15 16:12:13 +0000274_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100275#endif
Peter Maydell2b3f64c2018-04-19 13:57:40 +0100276#if (defined(TARGET_NR_getdents) && \
277 !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
Peter Maydell3307e232013-06-12 16:20:21 +0100278 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000279_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
280#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700281#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000282_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
283 loff_t *, res, uint, wh);
284#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200285_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200286_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
287 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000288_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000289#ifdef __NR_exit_group
290_syscall1(int,exit_group,int,error_code)
291#endif
292#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
293_syscall1(int,set_tid_address,int *,tidptr)
294#endif
aurel323b3f24a2009-04-15 16:12:13 +0000295#if defined(TARGET_NR_futex) && defined(__NR_futex)
296_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
297 const struct timespec *,timeout,int *,uaddr2,int,val3)
298#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500299#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
300_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
301 unsigned long *, user_mask_ptr);
302#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
303_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
304 unsigned long *, user_mask_ptr);
Samuel Thibaultb827c3e2018-01-12 09:14:35 +0100305#define __NR_sys_getcpu __NR_getcpu
306_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200307_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
308 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000309_syscall2(int, capget, struct __user_cap_header_struct *, header,
310 struct __user_cap_data_struct *, data);
311_syscall2(int, capset, struct __user_cap_header_struct *, header,
312 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100313#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
314_syscall2(int, ioprio_get, int, which, int, who)
315#endif
316#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
317_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
318#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100319#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
320_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
321#endif
aurel323b3f24a2009-04-15 16:12:13 +0000322
Laurent Vivier2f147882016-09-25 22:20:20 +0200323#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
324_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
325 unsigned long, idx1, unsigned long, idx2)
326#endif
327
aurel323b3f24a2009-04-15 16:12:13 +0000328static bitmask_transtbl fcntl_flags_tbl[] = {
329 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
330 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
331 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
332 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
333 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
334 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
335 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
336 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700337 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000338 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
339 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
340 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
341 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000342#if defined(O_DIRECT)
343 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
344#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700345#if defined(O_NOATIME)
346 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
347#endif
348#if defined(O_CLOEXEC)
349 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
350#endif
351#if defined(O_PATH)
352 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
353#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300354#if defined(O_TMPFILE)
355 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
356#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700357 /* Don't terminate the list prematurely on 64-bit host+guest. */
358#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
359 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
360#endif
aurel323b3f24a2009-04-15 16:12:13 +0000361 { 0, 0, 0, 0 }
362};
363
Michal Privoznik60c6b792016-08-19 10:06:40 +0200364enum {
365 QEMU_IFLA_BR_UNSPEC,
366 QEMU_IFLA_BR_FORWARD_DELAY,
367 QEMU_IFLA_BR_HELLO_TIME,
368 QEMU_IFLA_BR_MAX_AGE,
369 QEMU_IFLA_BR_AGEING_TIME,
370 QEMU_IFLA_BR_STP_STATE,
371 QEMU_IFLA_BR_PRIORITY,
372 QEMU_IFLA_BR_VLAN_FILTERING,
373 QEMU_IFLA_BR_VLAN_PROTOCOL,
374 QEMU_IFLA_BR_GROUP_FWD_MASK,
375 QEMU_IFLA_BR_ROOT_ID,
376 QEMU_IFLA_BR_BRIDGE_ID,
377 QEMU_IFLA_BR_ROOT_PORT,
378 QEMU_IFLA_BR_ROOT_PATH_COST,
379 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
380 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
381 QEMU_IFLA_BR_HELLO_TIMER,
382 QEMU_IFLA_BR_TCN_TIMER,
383 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
384 QEMU_IFLA_BR_GC_TIMER,
385 QEMU_IFLA_BR_GROUP_ADDR,
386 QEMU_IFLA_BR_FDB_FLUSH,
387 QEMU_IFLA_BR_MCAST_ROUTER,
388 QEMU_IFLA_BR_MCAST_SNOOPING,
389 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
390 QEMU_IFLA_BR_MCAST_QUERIER,
391 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
392 QEMU_IFLA_BR_MCAST_HASH_MAX,
393 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
394 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
395 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
396 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
397 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
398 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
399 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
400 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
401 QEMU_IFLA_BR_NF_CALL_IPTABLES,
402 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
403 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
404 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
405 QEMU_IFLA_BR_PAD,
406 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
407 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
Laurent Vivierc1e703f2018-05-17 00:12:13 +0200408 QEMU_IFLA_BR_MCAST_IGMP_VERSION,
409 QEMU_IFLA_BR_MCAST_MLD_VERSION,
Michal Privoznik60c6b792016-08-19 10:06:40 +0200410 QEMU___IFLA_BR_MAX,
411};
412
413enum {
414 QEMU_IFLA_UNSPEC,
415 QEMU_IFLA_ADDRESS,
416 QEMU_IFLA_BROADCAST,
417 QEMU_IFLA_IFNAME,
418 QEMU_IFLA_MTU,
419 QEMU_IFLA_LINK,
420 QEMU_IFLA_QDISC,
421 QEMU_IFLA_STATS,
422 QEMU_IFLA_COST,
423 QEMU_IFLA_PRIORITY,
424 QEMU_IFLA_MASTER,
425 QEMU_IFLA_WIRELESS,
426 QEMU_IFLA_PROTINFO,
427 QEMU_IFLA_TXQLEN,
428 QEMU_IFLA_MAP,
429 QEMU_IFLA_WEIGHT,
430 QEMU_IFLA_OPERSTATE,
431 QEMU_IFLA_LINKMODE,
432 QEMU_IFLA_LINKINFO,
433 QEMU_IFLA_NET_NS_PID,
434 QEMU_IFLA_IFALIAS,
435 QEMU_IFLA_NUM_VF,
436 QEMU_IFLA_VFINFO_LIST,
437 QEMU_IFLA_STATS64,
438 QEMU_IFLA_VF_PORTS,
439 QEMU_IFLA_PORT_SELF,
440 QEMU_IFLA_AF_SPEC,
441 QEMU_IFLA_GROUP,
442 QEMU_IFLA_NET_NS_FD,
443 QEMU_IFLA_EXT_MASK,
444 QEMU_IFLA_PROMISCUITY,
445 QEMU_IFLA_NUM_TX_QUEUES,
446 QEMU_IFLA_NUM_RX_QUEUES,
447 QEMU_IFLA_CARRIER,
448 QEMU_IFLA_PHYS_PORT_ID,
449 QEMU_IFLA_CARRIER_CHANGES,
450 QEMU_IFLA_PHYS_SWITCH_ID,
451 QEMU_IFLA_LINK_NETNSID,
452 QEMU_IFLA_PHYS_PORT_NAME,
453 QEMU_IFLA_PROTO_DOWN,
454 QEMU_IFLA_GSO_MAX_SEGS,
455 QEMU_IFLA_GSO_MAX_SIZE,
456 QEMU_IFLA_PAD,
457 QEMU_IFLA_XDP,
Laurent Vivierc1e703f2018-05-17 00:12:13 +0200458 QEMU_IFLA_EVENT,
459 QEMU_IFLA_NEW_NETNSID,
460 QEMU_IFLA_IF_NETNSID,
461 QEMU_IFLA_CARRIER_UP_COUNT,
462 QEMU_IFLA_CARRIER_DOWN_COUNT,
463 QEMU_IFLA_NEW_IFINDEX,
Michal Privoznik60c6b792016-08-19 10:06:40 +0200464 QEMU___IFLA_MAX
465};
466
467enum {
468 QEMU_IFLA_BRPORT_UNSPEC,
469 QEMU_IFLA_BRPORT_STATE,
470 QEMU_IFLA_BRPORT_PRIORITY,
471 QEMU_IFLA_BRPORT_COST,
472 QEMU_IFLA_BRPORT_MODE,
473 QEMU_IFLA_BRPORT_GUARD,
474 QEMU_IFLA_BRPORT_PROTECT,
475 QEMU_IFLA_BRPORT_FAST_LEAVE,
476 QEMU_IFLA_BRPORT_LEARNING,
477 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
478 QEMU_IFLA_BRPORT_PROXYARP,
479 QEMU_IFLA_BRPORT_LEARNING_SYNC,
480 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
481 QEMU_IFLA_BRPORT_ROOT_ID,
482 QEMU_IFLA_BRPORT_BRIDGE_ID,
483 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
484 QEMU_IFLA_BRPORT_DESIGNATED_COST,
485 QEMU_IFLA_BRPORT_ID,
486 QEMU_IFLA_BRPORT_NO,
487 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
488 QEMU_IFLA_BRPORT_CONFIG_PENDING,
489 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
490 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
491 QEMU_IFLA_BRPORT_HOLD_TIMER,
492 QEMU_IFLA_BRPORT_FLUSH,
493 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
494 QEMU_IFLA_BRPORT_PAD,
Laurent Vivierc1e703f2018-05-17 00:12:13 +0200495 QEMU_IFLA_BRPORT_MCAST_FLOOD,
496 QEMU_IFLA_BRPORT_MCAST_TO_UCAST,
497 QEMU_IFLA_BRPORT_VLAN_TUNNEL,
498 QEMU_IFLA_BRPORT_BCAST_FLOOD,
499 QEMU_IFLA_BRPORT_GROUP_FWD_MASK,
500 QEMU_IFLA_BRPORT_NEIGH_SUPPRESS,
Michal Privoznik60c6b792016-08-19 10:06:40 +0200501 QEMU___IFLA_BRPORT_MAX
502};
503
504enum {
505 QEMU_IFLA_INFO_UNSPEC,
506 QEMU_IFLA_INFO_KIND,
507 QEMU_IFLA_INFO_DATA,
508 QEMU_IFLA_INFO_XSTATS,
509 QEMU_IFLA_INFO_SLAVE_KIND,
510 QEMU_IFLA_INFO_SLAVE_DATA,
511 QEMU___IFLA_INFO_MAX,
512};
513
514enum {
515 QEMU_IFLA_INET_UNSPEC,
516 QEMU_IFLA_INET_CONF,
517 QEMU___IFLA_INET_MAX,
518};
519
520enum {
521 QEMU_IFLA_INET6_UNSPEC,
522 QEMU_IFLA_INET6_FLAGS,
523 QEMU_IFLA_INET6_CONF,
524 QEMU_IFLA_INET6_STATS,
525 QEMU_IFLA_INET6_MCAST,
526 QEMU_IFLA_INET6_CACHEINFO,
527 QEMU_IFLA_INET6_ICMP6STATS,
528 QEMU_IFLA_INET6_TOKEN,
529 QEMU_IFLA_INET6_ADDR_GEN_MODE,
530 QEMU___IFLA_INET6_MAX
531};
532
Laurent Vivierc1e703f2018-05-17 00:12:13 +0200533enum {
534 QEMU_IFLA_XDP_UNSPEC,
535 QEMU_IFLA_XDP_FD,
536 QEMU_IFLA_XDP_ATTACHED,
537 QEMU_IFLA_XDP_FLAGS,
538 QEMU_IFLA_XDP_PROG_ID,
539 QEMU___IFLA_XDP_MAX,
540};
541
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100542typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100543typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200544typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100545 TargetFdDataFunc host_to_target_data;
546 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100547 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200548} TargetFdTrans;
549
550static TargetFdTrans **target_fd_trans;
551
552static unsigned int target_fd_max;
553
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200554static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
555{
556 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
557 return target_fd_trans[fd]->target_to_host_data;
558 }
559 return NULL;
560}
561
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100562static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200563{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100564 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100565 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200566 }
567 return NULL;
568}
569
Laurent Vivier7b36f782015-10-28 21:40:44 +0100570static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
571{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100572 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100573 return target_fd_trans[fd]->target_to_host_addr;
574 }
575 return NULL;
576}
577
Laurent Viviere36800c2015-10-02 14:48:09 +0200578static void fd_trans_register(int fd, TargetFdTrans *trans)
579{
580 unsigned int oldmax;
581
582 if (fd >= target_fd_max) {
583 oldmax = target_fd_max;
584 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100585 target_fd_trans = g_renew(TargetFdTrans *,
586 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200587 memset((void *)(target_fd_trans + oldmax), 0,
588 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
589 }
590 target_fd_trans[fd] = trans;
591}
592
593static void fd_trans_unregister(int fd)
594{
595 if (fd >= 0 && fd < target_fd_max) {
596 target_fd_trans[fd] = NULL;
597 }
598}
599
600static void fd_trans_dup(int oldfd, int newfd)
601{
602 fd_trans_unregister(newfd);
603 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
604 fd_trans_register(newfd, target_fd_trans[oldfd]);
605 }
606}
607
aurel323b3f24a2009-04-15 16:12:13 +0000608static int sys_getcwd1(char *buf, size_t size)
609{
610 if (getcwd(buf, size) == NULL) {
611 /* getcwd() sets errno */
612 return (-1);
613 }
aurel32aaf4ad32009-04-16 14:17:14 +0000614 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000615}
616
Peter Maydell1acae9f2013-07-02 14:04:12 +0100617#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100618#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100619#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000620_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
621 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100622#else
623static int sys_utimensat(int dirfd, const char *pathname,
624 const struct timespec times[2], int flags)
625{
626 errno = ENOSYS;
627 return -1;
628}
ths9007f0e2007-09-25 17:50:37 +0000629#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100630#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000631
Andreas Schwab95d03072018-01-23 11:53:31 +0100632#ifdef TARGET_NR_renameat2
633#if defined(__NR_renameat2)
634#define __NR_sys_renameat2 __NR_renameat2
635_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
636 const char *, new, unsigned int, flags)
637#else
638static int sys_renameat2(int oldfd, const char *old,
639 int newfd, const char *new, int flags)
640{
641 if (flags == 0) {
642 return renameat(oldfd, old, newfd, new);
643 }
644 errno = ENOSYS;
645 return -1;
646}
647#endif
648#endif /* TARGET_NR_renameat2 */
649
aurel323b3f24a2009-04-15 16:12:13 +0000650#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000651#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000652
aurel3239b59762008-10-01 21:46:50 +0000653#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000654static int sys_inotify_init(void)
655{
656 return (inotify_init());
657}
aurel3239b59762008-10-01 21:46:50 +0000658#endif
659#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000660static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
661{
662 return (inotify_add_watch(fd, pathname, mask));
663}
aurel3239b59762008-10-01 21:46:50 +0000664#endif
665#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000666static int sys_inotify_rm_watch(int fd, int32_t wd)
667{
aurel328690e422009-04-17 13:50:32 +0000668 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000669}
aurel3239b59762008-10-01 21:46:50 +0000670#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000671#ifdef CONFIG_INOTIFY1
672#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
673static int sys_inotify_init1(int flags)
674{
675 return (inotify_init1(flags));
676}
677#endif
678#endif
aurel323b3f24a2009-04-15 16:12:13 +0000679#else
680/* Userspace can usually survive runtime without inotify */
681#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000682#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000683#undef TARGET_NR_inotify_add_watch
684#undef TARGET_NR_inotify_rm_watch
685#endif /* CONFIG_INOTIFY */
686
Peter Maydell163a05a2011-06-27 17:44:52 +0100687#if defined(TARGET_NR_prlimit64)
688#ifndef __NR_prlimit64
689# define __NR_prlimit64 -1
690#endif
691#define __NR_sys_prlimit64 __NR_prlimit64
692/* The glibc rlimit structure may not be that used by the underlying syscall */
693struct host_rlimit64 {
694 uint64_t rlim_cur;
695 uint64_t rlim_max;
696};
697_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
698 const struct host_rlimit64 *, new_limit,
699 struct host_rlimit64 *, old_limit)
700#endif
701
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100702
703#if defined(TARGET_NR_timer_create)
704/* Maxiumum of 32 active POSIX timers allowed at any one time. */
705static timer_t g_posix_timers[32] = { 0, } ;
706
707static inline int next_free_host_timer(void)
708{
709 int k ;
710 /* FIXME: Does finding the next free slot require a lock? */
711 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
712 if (g_posix_timers[k] == 0) {
713 g_posix_timers[k] = (timer_t) 1;
714 return k;
715 }
716 }
717 return -1;
718}
719#endif
720
Riku Voipio48e515d2011-07-12 15:40:51 +0300721/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000722#ifdef TARGET_ARM
James Clarke8bf8e9d2017-09-15 20:33:13 +0100723static inline int regpairs_aligned(void *cpu_env, int num)
724{
Riku Voipio48e515d2011-07-12 15:40:51 +0300725 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
726}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200727#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
James Clarke8bf8e9d2017-09-15 20:33:13 +0100728static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000729#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
730/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
731 * of registers which translates to the same as ARM/MIPS, because we start with
732 * r3 as arg1 */
James Clarke8bf8e9d2017-09-15 20:33:13 +0100733static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
734#elif defined(TARGET_SH4)
735/* SH4 doesn't align register pairs, except for p{read,write}64 */
736static inline int regpairs_aligned(void *cpu_env, int num)
737{
738 switch (num) {
739 case TARGET_NR_pread64:
740 case TARGET_NR_pwrite64:
741 return 1;
742
743 default:
744 return 0;
745 }
746}
Max Filippovba7651f2017-01-25 10:54:11 -0800747#elif defined(TARGET_XTENSA)
748static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300749#else
James Clarke8bf8e9d2017-09-15 20:33:13 +0100750static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300751#endif
752
thsb92c47c2007-11-01 00:07:38 +0000753#define ERRNO_TABLE_SIZE 1200
754
755/* target_to_host_errno_table[] is initialized from
756 * host_to_target_errno_table[] in syscall_init(). */
757static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
758};
759
ths637947f2007-06-01 12:09:19 +0000760/*
thsfe8f0962007-07-12 10:59:21 +0000761 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000762 * minus the errnos that are not actually generic to all archs.
763 */
thsb92c47c2007-11-01 00:07:38 +0000764static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800765 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000766 [EIDRM] = TARGET_EIDRM,
767 [ECHRNG] = TARGET_ECHRNG,
768 [EL2NSYNC] = TARGET_EL2NSYNC,
769 [EL3HLT] = TARGET_EL3HLT,
770 [EL3RST] = TARGET_EL3RST,
771 [ELNRNG] = TARGET_ELNRNG,
772 [EUNATCH] = TARGET_EUNATCH,
773 [ENOCSI] = TARGET_ENOCSI,
774 [EL2HLT] = TARGET_EL2HLT,
775 [EDEADLK] = TARGET_EDEADLK,
776 [ENOLCK] = TARGET_ENOLCK,
777 [EBADE] = TARGET_EBADE,
778 [EBADR] = TARGET_EBADR,
779 [EXFULL] = TARGET_EXFULL,
780 [ENOANO] = TARGET_ENOANO,
781 [EBADRQC] = TARGET_EBADRQC,
782 [EBADSLT] = TARGET_EBADSLT,
783 [EBFONT] = TARGET_EBFONT,
784 [ENOSTR] = TARGET_ENOSTR,
785 [ENODATA] = TARGET_ENODATA,
786 [ETIME] = TARGET_ETIME,
787 [ENOSR] = TARGET_ENOSR,
788 [ENONET] = TARGET_ENONET,
789 [ENOPKG] = TARGET_ENOPKG,
790 [EREMOTE] = TARGET_EREMOTE,
791 [ENOLINK] = TARGET_ENOLINK,
792 [EADV] = TARGET_EADV,
793 [ESRMNT] = TARGET_ESRMNT,
794 [ECOMM] = TARGET_ECOMM,
795 [EPROTO] = TARGET_EPROTO,
796 [EDOTDOT] = TARGET_EDOTDOT,
797 [EMULTIHOP] = TARGET_EMULTIHOP,
798 [EBADMSG] = TARGET_EBADMSG,
799 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
800 [EOVERFLOW] = TARGET_EOVERFLOW,
801 [ENOTUNIQ] = TARGET_ENOTUNIQ,
802 [EBADFD] = TARGET_EBADFD,
803 [EREMCHG] = TARGET_EREMCHG,
804 [ELIBACC] = TARGET_ELIBACC,
805 [ELIBBAD] = TARGET_ELIBBAD,
806 [ELIBSCN] = TARGET_ELIBSCN,
807 [ELIBMAX] = TARGET_ELIBMAX,
808 [ELIBEXEC] = TARGET_ELIBEXEC,
809 [EILSEQ] = TARGET_EILSEQ,
810 [ENOSYS] = TARGET_ENOSYS,
811 [ELOOP] = TARGET_ELOOP,
812 [ERESTART] = TARGET_ERESTART,
813 [ESTRPIPE] = TARGET_ESTRPIPE,
814 [ENOTEMPTY] = TARGET_ENOTEMPTY,
815 [EUSERS] = TARGET_EUSERS,
816 [ENOTSOCK] = TARGET_ENOTSOCK,
817 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
818 [EMSGSIZE] = TARGET_EMSGSIZE,
819 [EPROTOTYPE] = TARGET_EPROTOTYPE,
820 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
821 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
822 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
823 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
824 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
825 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
826 [EADDRINUSE] = TARGET_EADDRINUSE,
827 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
828 [ENETDOWN] = TARGET_ENETDOWN,
829 [ENETUNREACH] = TARGET_ENETUNREACH,
830 [ENETRESET] = TARGET_ENETRESET,
831 [ECONNABORTED] = TARGET_ECONNABORTED,
832 [ECONNRESET] = TARGET_ECONNRESET,
833 [ENOBUFS] = TARGET_ENOBUFS,
834 [EISCONN] = TARGET_EISCONN,
835 [ENOTCONN] = TARGET_ENOTCONN,
836 [EUCLEAN] = TARGET_EUCLEAN,
837 [ENOTNAM] = TARGET_ENOTNAM,
838 [ENAVAIL] = TARGET_ENAVAIL,
839 [EISNAM] = TARGET_EISNAM,
840 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200841 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000842 [ESHUTDOWN] = TARGET_ESHUTDOWN,
843 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
844 [ETIMEDOUT] = TARGET_ETIMEDOUT,
845 [ECONNREFUSED] = TARGET_ECONNREFUSED,
846 [EHOSTDOWN] = TARGET_EHOSTDOWN,
847 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
848 [EALREADY] = TARGET_EALREADY,
849 [EINPROGRESS] = TARGET_EINPROGRESS,
850 [ESTALE] = TARGET_ESTALE,
851 [ECANCELED] = TARGET_ECANCELED,
852 [ENOMEDIUM] = TARGET_ENOMEDIUM,
853 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000854#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000855 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000856#endif
857#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000858 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000859#endif
860#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000861 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000862#endif
863#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000864 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000865#endif
866#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000867 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000868#endif
869#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000870 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000871#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200872#ifdef ENOMSG
873 [ENOMSG] = TARGET_ENOMSG,
874#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800875#ifdef ERKFILL
876 [ERFKILL] = TARGET_ERFKILL,
877#endif
878#ifdef EHWPOISON
879 [EHWPOISON] = TARGET_EHWPOISON,
880#endif
thsb92c47c2007-11-01 00:07:38 +0000881};
ths637947f2007-06-01 12:09:19 +0000882
883static inline int host_to_target_errno(int err)
884{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100885 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
886 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000887 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100888 }
ths637947f2007-06-01 12:09:19 +0000889 return err;
890}
891
thsb92c47c2007-11-01 00:07:38 +0000892static inline int target_to_host_errno(int err)
893{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100894 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
895 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000896 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100897 }
thsb92c47c2007-11-01 00:07:38 +0000898 return err;
899}
900
blueswir1992f48a2007-10-14 16:27:31 +0000901static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000902{
903 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000904 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000905 else
906 return ret;
907}
908
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100909const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000910{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100911 if (err == TARGET_ERESTARTSYS) {
912 return "To be restarted";
913 }
914 if (err == TARGET_QEMU_ESIGRETURN) {
915 return "Successful exit from sigreturn";
916 }
917
Alexander Graf962b2892011-11-21 12:04:07 +0100918 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
919 return NULL;
920 }
thsb92c47c2007-11-01 00:07:38 +0000921 return strerror(target_to_host_errno(err));
922}
923
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100924#define safe_syscall0(type, name) \
925static type safe_##name(void) \
926{ \
927 return safe_syscall(__NR_##name); \
928}
929
930#define safe_syscall1(type, name, type1, arg1) \
931static type safe_##name(type1 arg1) \
932{ \
933 return safe_syscall(__NR_##name, arg1); \
934}
935
936#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
937static type safe_##name(type1 arg1, type2 arg2) \
938{ \
939 return safe_syscall(__NR_##name, arg1, arg2); \
940}
941
942#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
943static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
944{ \
945 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
946}
947
948#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
949 type4, arg4) \
950static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
951{ \
952 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
953}
954
955#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
956 type4, arg4, type5, arg5) \
957static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
958 type5 arg5) \
959{ \
960 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
961}
962
963#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
964 type4, arg4, type5, arg5, type6, arg6) \
965static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
966 type5 arg5, type6 arg6) \
967{ \
968 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
969}
970
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100971safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
972safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100973safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
974 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100975safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
976 struct rusage *, rusage)
977safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
978 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100979safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100980safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
981 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100982safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
983 struct timespec *, tsp, const sigset_t *, sigmask,
984 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100985safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
986 int, maxevents, int, timeout, const sigset_t *, sigmask,
987 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100988safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
989 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100990safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100991safe_syscall2(int, kill, pid_t, pid, int, sig)
992safe_syscall2(int, tkill, int, tid, int, sig)
993safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100994safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
995safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200996safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
997 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200998safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
999 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +01001000safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
1001 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +01001002safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
1003 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
1004safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
1005 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
1006safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
1007safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +01001008safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +01001009safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
1010 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +01001011safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
1012 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +01001013safe_syscall2(int, nanosleep, const struct timespec *, req,
1014 struct timespec *, rem)
1015#ifdef TARGET_NR_clock_nanosleep
1016safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
1017 const struct timespec *, req, struct timespec *, rem)
1018#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +01001019#ifdef __NR_msgsnd
1020safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
1021 int, flags)
1022safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
1023 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +01001024safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
1025 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +01001026#else
1027/* This host kernel architecture uses a single ipc syscall; fake up
1028 * wrappers for the sub-operations to hide this implementation detail.
1029 * Annoyingly we can't include linux/ipc.h to get the constant definitions
1030 * for the call parameter because some structs in there conflict with the
1031 * sys/ipc.h ones. So we just define them here, and rely on them being
1032 * the same for all host architectures.
1033 */
Peter Maydellffb7ee72016-06-06 19:58:12 +01001034#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +01001035#define Q_MSGSND 11
1036#define Q_MSGRCV 12
1037#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
1038
1039safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
1040 void *, ptr, long, fifth)
1041static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
1042{
1043 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
1044}
1045static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
1046{
1047 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
1048}
Peter Maydellffb7ee72016-06-06 19:58:12 +01001049static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
1050 const struct timespec *timeout)
1051{
1052 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
1053 (long)timeout);
1054}
Peter Maydell89f9fe42016-06-06 19:58:05 +01001055#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +01001056#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1057safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
1058 size_t, len, unsigned, prio, const struct timespec *, timeout)
1059safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
1060 size_t, len, unsigned *, prio, const struct timespec *, timeout)
1061#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +01001062/* We do ioctl like this rather than via safe_syscall3 to preserve the
1063 * "third argument might be integer or pointer or not present" behaviour of
1064 * the libc function.
1065 */
1066#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +01001067/* Similarly for fcntl. Note that callers must always:
1068 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1069 * use the flock64 struct rather than unsuffixed flock
1070 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1071 */
1072#ifdef __NR_fcntl64
1073#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1074#else
1075#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1076#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001077
Paul Burton8289d112014-06-22 11:25:33 +01001078static inline int host_to_target_sock_type(int host_type)
1079{
1080 int target_type;
1081
1082 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1083 case SOCK_DGRAM:
1084 target_type = TARGET_SOCK_DGRAM;
1085 break;
1086 case SOCK_STREAM:
1087 target_type = TARGET_SOCK_STREAM;
1088 break;
1089 default:
1090 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1091 break;
1092 }
1093
1094#if defined(SOCK_CLOEXEC)
1095 if (host_type & SOCK_CLOEXEC) {
1096 target_type |= TARGET_SOCK_CLOEXEC;
1097 }
1098#endif
1099
1100#if defined(SOCK_NONBLOCK)
1101 if (host_type & SOCK_NONBLOCK) {
1102 target_type |= TARGET_SOCK_NONBLOCK;
1103 }
1104#endif
1105
1106 return target_type;
1107}
1108
blueswir1992f48a2007-10-14 16:27:31 +00001109static abi_ulong target_brk;
1110static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001111static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001112
blueswir1992f48a2007-10-14 16:27:31 +00001113void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001114{
blueswir14c1de732007-07-07 20:45:44 +00001115 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001116 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001117}
1118
vincent4d1de872011-06-14 21:56:33 +00001119//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1120#define DEBUGF_BRK(message, args...)
1121
ths0da46a62007-10-20 20:23:07 +00001122/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001123abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001124{
blueswir1992f48a2007-10-14 16:27:31 +00001125 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001126 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001127
Paul Brook3a0c6c42012-02-09 19:04:27 +00001128 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001129
vincent4d1de872011-06-14 21:56:33 +00001130 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001131 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001132 return target_brk;
1133 }
1134 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001135 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1136 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001137 return target_brk;
1138 }
bellard31e31b82003-02-18 22:55:36 +00001139
vincent4d1de872011-06-14 21:56:33 +00001140 /* If the new brk is less than the highest page reserved to the
1141 * target heap allocation, set it and we're almost done... */
1142 if (new_brk <= brk_page) {
1143 /* Heap contents are initialized to zero, as for anonymous
1144 * mapped pages. */
1145 if (new_brk > target_brk) {
1146 memset(g2h(target_brk), 0, new_brk - target_brk);
1147 }
bellard31e31b82003-02-18 22:55:36 +00001148 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001149 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001150 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001151 }
1152
Peter Maydell00faf082011-04-18 16:34:24 +01001153 /* We need to allocate more memory after the brk... Note that
1154 * we don't use MAP_FIXED because that will map over the top of
1155 * any existing mapping (like the one with the host libc or qemu
1156 * itself); instead we treat "mapped but at wrong address" as
1157 * a failure and unmap again.
1158 */
vincent4d1de872011-06-14 21:56:33 +00001159 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001160 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001161 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001162 MAP_ANON|MAP_PRIVATE, 0, 0));
1163
1164 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001165 /* Heap contents are initialized to zero, as for anonymous
1166 * mapped pages. Technically the new pages are already
1167 * initialized to zero since they *are* anonymous mapped
1168 * pages, however we have to take care with the contents that
1169 * come from the remaining part of the previous page: it may
1170 * contains garbage data due to a previous heap usage (grown
1171 * then shrunken). */
1172 memset(g2h(target_brk), 0, brk_page - target_brk);
1173
Peter Maydell00faf082011-04-18 16:34:24 +01001174 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001175 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001176 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1177 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001178 return target_brk;
1179 } else if (mapped_addr != -1) {
1180 /* Mapped but at wrong address, meaning there wasn't actually
1181 * enough space for this brk.
1182 */
1183 target_munmap(mapped_addr, new_alloc_size);
1184 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001185 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001186 }
1187 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001188 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001189 }
balrog7ab240a2008-04-26 12:17:34 +00001190
Richard Henderson7dd46c02010-05-03 10:07:49 -07001191#if defined(TARGET_ALPHA)
1192 /* We (partially) emulate OSF/1 on Alpha, which requires we
1193 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001194 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001195#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001196 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001197 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001198}
1199
ths26edcf42007-12-09 02:25:24 +00001200static inline abi_long copy_from_user_fdset(fd_set *fds,
1201 abi_ulong target_fds_addr,
1202 int n)
bellard31e31b82003-02-18 22:55:36 +00001203{
ths26edcf42007-12-09 02:25:24 +00001204 int i, nw, j, k;
1205 abi_ulong b, *target_fds;
1206
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001207 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001208 if (!(target_fds = lock_user(VERIFY_READ,
1209 target_fds_addr,
1210 sizeof(abi_ulong) * nw,
1211 1)))
1212 return -TARGET_EFAULT;
1213
1214 FD_ZERO(fds);
1215 k = 0;
1216 for (i = 0; i < nw; i++) {
1217 /* grab the abi_ulong */
1218 __get_user(b, &target_fds[i]);
1219 for (j = 0; j < TARGET_ABI_BITS; j++) {
1220 /* check the bit inside the abi_ulong */
1221 if ((b >> j) & 1)
1222 FD_SET(k, fds);
1223 k++;
bellard31e31b82003-02-18 22:55:36 +00001224 }
bellard31e31b82003-02-18 22:55:36 +00001225 }
ths26edcf42007-12-09 02:25:24 +00001226
1227 unlock_user(target_fds, target_fds_addr, 0);
1228
1229 return 0;
bellard31e31b82003-02-18 22:55:36 +00001230}
1231
Mike Frysinger055e0902011-06-03 17:01:49 -04001232static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1233 abi_ulong target_fds_addr,
1234 int n)
1235{
1236 if (target_fds_addr) {
1237 if (copy_from_user_fdset(fds, target_fds_addr, n))
1238 return -TARGET_EFAULT;
1239 *fds_ptr = fds;
1240 } else {
1241 *fds_ptr = NULL;
1242 }
1243 return 0;
1244}
1245
ths26edcf42007-12-09 02:25:24 +00001246static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1247 const fd_set *fds,
1248 int n)
bellard31e31b82003-02-18 22:55:36 +00001249{
bellard31e31b82003-02-18 22:55:36 +00001250 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001251 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001252 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001253
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001254 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001255 if (!(target_fds = lock_user(VERIFY_WRITE,
1256 target_fds_addr,
1257 sizeof(abi_ulong) * nw,
1258 0)))
1259 return -TARGET_EFAULT;
1260
1261 k = 0;
1262 for (i = 0; i < nw; i++) {
1263 v = 0;
1264 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001265 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001266 k++;
bellard31e31b82003-02-18 22:55:36 +00001267 }
ths26edcf42007-12-09 02:25:24 +00001268 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001269 }
ths26edcf42007-12-09 02:25:24 +00001270
1271 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1272
1273 return 0;
bellard31e31b82003-02-18 22:55:36 +00001274}
1275
bellardc596ed12003-07-13 17:32:31 +00001276#if defined(__alpha__)
1277#define HOST_HZ 1024
1278#else
1279#define HOST_HZ 100
1280#endif
1281
blueswir1992f48a2007-10-14 16:27:31 +00001282static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001283{
1284#if HOST_HZ == TARGET_HZ
1285 return ticks;
1286#else
1287 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1288#endif
1289}
1290
bellard579a97f2007-11-11 14:26:47 +00001291static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1292 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001293{
pbrook53a59602006-03-25 19:31:22 +00001294 struct target_rusage *target_rusage;
1295
bellard579a97f2007-11-11 14:26:47 +00001296 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1297 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001298 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1299 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1300 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1301 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1302 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1303 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1304 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1305 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1306 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1307 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1308 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1309 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1310 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1311 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1312 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1313 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1314 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1315 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001316 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001317
1318 return 0;
bellardb4091862003-05-16 15:39:34 +00001319}
1320
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001321static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001322{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001323 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001324 rlim_t result;
1325
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001326 target_rlim_swap = tswapal(target_rlim);
1327 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1328 return RLIM_INFINITY;
1329
1330 result = target_rlim_swap;
1331 if (target_rlim_swap != (rlim_t)result)
1332 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001333
1334 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001335}
1336
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001337static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001338{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001339 abi_ulong target_rlim_swap;
1340 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001341
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001342 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001343 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001344 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001345 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001346 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001347
1348 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001349}
1350
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001351static inline int target_to_host_resource(int code)
1352{
1353 switch (code) {
1354 case TARGET_RLIMIT_AS:
1355 return RLIMIT_AS;
1356 case TARGET_RLIMIT_CORE:
1357 return RLIMIT_CORE;
1358 case TARGET_RLIMIT_CPU:
1359 return RLIMIT_CPU;
1360 case TARGET_RLIMIT_DATA:
1361 return RLIMIT_DATA;
1362 case TARGET_RLIMIT_FSIZE:
1363 return RLIMIT_FSIZE;
1364 case TARGET_RLIMIT_LOCKS:
1365 return RLIMIT_LOCKS;
1366 case TARGET_RLIMIT_MEMLOCK:
1367 return RLIMIT_MEMLOCK;
1368 case TARGET_RLIMIT_MSGQUEUE:
1369 return RLIMIT_MSGQUEUE;
1370 case TARGET_RLIMIT_NICE:
1371 return RLIMIT_NICE;
1372 case TARGET_RLIMIT_NOFILE:
1373 return RLIMIT_NOFILE;
1374 case TARGET_RLIMIT_NPROC:
1375 return RLIMIT_NPROC;
1376 case TARGET_RLIMIT_RSS:
1377 return RLIMIT_RSS;
1378 case TARGET_RLIMIT_RTPRIO:
1379 return RLIMIT_RTPRIO;
1380 case TARGET_RLIMIT_SIGPENDING:
1381 return RLIMIT_SIGPENDING;
1382 case TARGET_RLIMIT_STACK:
1383 return RLIMIT_STACK;
1384 default:
1385 return code;
1386 }
1387}
1388
ths788f5ec2007-12-09 02:37:05 +00001389static inline abi_long copy_from_user_timeval(struct timeval *tv,
1390 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001391{
pbrook53a59602006-03-25 19:31:22 +00001392 struct target_timeval *target_tv;
1393
ths788f5ec2007-12-09 02:37:05 +00001394 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001395 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001396
1397 __get_user(tv->tv_sec, &target_tv->tv_sec);
1398 __get_user(tv->tv_usec, &target_tv->tv_usec);
1399
1400 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001401
1402 return 0;
bellard31e31b82003-02-18 22:55:36 +00001403}
1404
ths788f5ec2007-12-09 02:37:05 +00001405static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1406 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001407{
pbrook53a59602006-03-25 19:31:22 +00001408 struct target_timeval *target_tv;
1409
ths788f5ec2007-12-09 02:37:05 +00001410 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001411 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001412
1413 __put_user(tv->tv_sec, &target_tv->tv_sec);
1414 __put_user(tv->tv_usec, &target_tv->tv_usec);
1415
1416 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001417
1418 return 0;
bellard31e31b82003-02-18 22:55:36 +00001419}
1420
Paul Burtonef4467e2014-06-22 11:25:40 +01001421static inline abi_long copy_from_user_timezone(struct timezone *tz,
1422 abi_ulong target_tz_addr)
1423{
1424 struct target_timezone *target_tz;
1425
1426 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1427 return -TARGET_EFAULT;
1428 }
1429
1430 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1431 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1432
1433 unlock_user_struct(target_tz, target_tz_addr, 0);
1434
1435 return 0;
1436}
1437
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001438#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1439#include <mqueue.h>
1440
aurel3224e10032009-04-15 16:11:43 +00001441static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1442 abi_ulong target_mq_attr_addr)
1443{
1444 struct target_mq_attr *target_mq_attr;
1445
1446 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1447 target_mq_attr_addr, 1))
1448 return -TARGET_EFAULT;
1449
1450 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1451 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1452 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1453 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1454
1455 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1456
1457 return 0;
1458}
1459
1460static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1461 const struct mq_attr *attr)
1462{
1463 struct target_mq_attr *target_mq_attr;
1464
1465 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1466 target_mq_attr_addr, 0))
1467 return -TARGET_EFAULT;
1468
1469 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1470 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1471 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1472 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1473
1474 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1475
1476 return 0;
1477}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001478#endif
bellard31e31b82003-02-18 22:55:36 +00001479
Mike Frysinger055e0902011-06-03 17:01:49 -04001480#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001481/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001482static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001483 abi_ulong rfd_addr, abi_ulong wfd_addr,
1484 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001485{
1486 fd_set rfds, wfds, efds;
1487 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001488 struct timeval tv;
1489 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001490 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001491
Mike Frysinger055e0902011-06-03 17:01:49 -04001492 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1493 if (ret) {
1494 return ret;
pbrook53a59602006-03-25 19:31:22 +00001495 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001496 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1497 if (ret) {
1498 return ret;
pbrook53a59602006-03-25 19:31:22 +00001499 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001500 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1501 if (ret) {
1502 return ret;
pbrook53a59602006-03-25 19:31:22 +00001503 }
ths3b46e622007-09-17 08:09:54 +00001504
ths26edcf42007-12-09 02:25:24 +00001505 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001506 if (copy_from_user_timeval(&tv, target_tv_addr))
1507 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001508 ts.tv_sec = tv.tv_sec;
1509 ts.tv_nsec = tv.tv_usec * 1000;
1510 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001511 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001512 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001513 }
ths26edcf42007-12-09 02:25:24 +00001514
Peter Maydell6df9d382016-05-12 18:47:51 +01001515 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1516 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001517
ths26edcf42007-12-09 02:25:24 +00001518 if (!is_error(ret)) {
1519 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1520 return -TARGET_EFAULT;
1521 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1522 return -TARGET_EFAULT;
1523 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1524 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001525
Peter Maydell6df9d382016-05-12 18:47:51 +01001526 if (target_tv_addr) {
1527 tv.tv_sec = ts.tv_sec;
1528 tv.tv_usec = ts.tv_nsec / 1000;
1529 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1530 return -TARGET_EFAULT;
1531 }
1532 }
bellard31e31b82003-02-18 22:55:36 +00001533 }
bellard579a97f2007-11-11 14:26:47 +00001534
bellard31e31b82003-02-18 22:55:36 +00001535 return ret;
1536}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001537
1538#if defined(TARGET_WANT_OLD_SYS_SELECT)
1539static abi_long do_old_select(abi_ulong arg1)
1540{
1541 struct target_sel_arg_struct *sel;
1542 abi_ulong inp, outp, exp, tvp;
1543 long nsel;
1544
1545 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1546 return -TARGET_EFAULT;
1547 }
1548
1549 nsel = tswapal(sel->n);
1550 inp = tswapal(sel->inp);
1551 outp = tswapal(sel->outp);
1552 exp = tswapal(sel->exp);
1553 tvp = tswapal(sel->tvp);
1554
1555 unlock_user_struct(sel, arg1, 0);
1556
1557 return do_select(nsel, inp, outp, exp, tvp);
1558}
1559#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001560#endif
bellard31e31b82003-02-18 22:55:36 +00001561
Riku Voipio099d6b02009-05-05 12:10:04 +03001562static abi_long do_pipe2(int host_pipe[], int flags)
1563{
1564#ifdef CONFIG_PIPE2
1565 return pipe2(host_pipe, flags);
1566#else
1567 return -ENOSYS;
1568#endif
1569}
1570
Richard Hendersonfb41a662010-05-03 10:07:52 -07001571static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1572 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001573{
1574 int host_pipe[2];
1575 abi_long ret;
1576 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1577
1578 if (is_error(ret))
1579 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001580
1581 /* Several targets have special calling conventions for the original
1582 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1583 if (!is_pipe2) {
1584#if defined(TARGET_ALPHA)
1585 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1586 return host_pipe[0];
1587#elif defined(TARGET_MIPS)
1588 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1589 return host_pipe[0];
1590#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001591 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001592 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001593#elif defined(TARGET_SPARC)
1594 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1595 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001596#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001597 }
1598
Riku Voipio099d6b02009-05-05 12:10:04 +03001599 if (put_user_s32(host_pipe[0], pipedes)
1600 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1601 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001602 return get_errno(ret);
1603}
1604
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001605static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1606 abi_ulong target_addr,
1607 socklen_t len)
1608{
1609 struct target_ip_mreqn *target_smreqn;
1610
1611 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1612 if (!target_smreqn)
1613 return -TARGET_EFAULT;
1614 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1615 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1616 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001617 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001618 unlock_user(target_smreqn, target_addr, 0);
1619
1620 return 0;
1621}
1622
Laurent Vivier7b36f782015-10-28 21:40:44 +01001623static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001624 abi_ulong target_addr,
1625 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001626{
aurel32607175e2009-04-15 16:11:59 +00001627 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1628 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001629 struct target_sockaddr *target_saddr;
1630
Laurent Vivier7b36f782015-10-28 21:40:44 +01001631 if (fd_trans_target_to_host_addr(fd)) {
1632 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1633 }
1634
bellard579a97f2007-11-11 14:26:47 +00001635 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1636 if (!target_saddr)
1637 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001638
1639 sa_family = tswap16(target_saddr->sa_family);
1640
1641 /* Oops. The caller might send a incomplete sun_path; sun_path
1642 * must be terminated by \0 (see the manual page), but
1643 * unfortunately it is quite common to specify sockaddr_un
1644 * length as "strlen(x->sun_path)" while it should be
1645 * "strlen(...) + 1". We'll fix that here if needed.
1646 * Linux kernel has a similar feature.
1647 */
1648
1649 if (sa_family == AF_UNIX) {
1650 if (len < unix_maxlen && len > 0) {
1651 char *cp = (char*)target_saddr;
1652
1653 if ( cp[len-1] && !cp[len] )
1654 len++;
1655 }
1656 if (len > unix_maxlen)
1657 len = unix_maxlen;
1658 }
1659
pbrook53a59602006-03-25 19:31:22 +00001660 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001661 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001662 if (sa_family == AF_NETLINK) {
1663 struct sockaddr_nl *nladdr;
1664
1665 nladdr = (struct sockaddr_nl *)addr;
1666 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1667 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1668 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001669 struct target_sockaddr_ll *lladdr;
1670
1671 lladdr = (struct target_sockaddr_ll *)addr;
1672 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1673 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1674 }
pbrook53a59602006-03-25 19:31:22 +00001675 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001676
1677 return 0;
bellard7854b052003-03-29 17:22:23 +00001678}
1679
bellard579a97f2007-11-11 14:26:47 +00001680static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1681 struct sockaddr *addr,
1682 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001683{
pbrook53a59602006-03-25 19:31:22 +00001684 struct target_sockaddr *target_saddr;
1685
Peter Maydella1e22192016-07-07 15:44:43 +01001686 if (len == 0) {
1687 return 0;
1688 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001689 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001690
bellard579a97f2007-11-11 14:26:47 +00001691 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1692 if (!target_saddr)
1693 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001694 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001695 if (len >= offsetof(struct target_sockaddr, sa_family) +
1696 sizeof(target_saddr->sa_family)) {
1697 target_saddr->sa_family = tswap16(addr->sa_family);
1698 }
1699 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001700 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1701 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1702 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001703 } else if (addr->sa_family == AF_PACKET) {
1704 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1705 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1706 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001707 } else if (addr->sa_family == AF_INET6 &&
1708 len >= sizeof(struct target_sockaddr_in6)) {
1709 struct target_sockaddr_in6 *target_in6 =
1710 (struct target_sockaddr_in6 *)target_saddr;
1711 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001712 }
pbrook53a59602006-03-25 19:31:22 +00001713 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001714
1715 return 0;
bellard7854b052003-03-29 17:22:23 +00001716}
1717
bellard5a4a8982007-11-11 17:39:18 +00001718static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1719 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001720{
1721 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001722 abi_long msg_controllen;
1723 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001724 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001725 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001726
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001727 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001728 if (msg_controllen < sizeof (struct target_cmsghdr))
1729 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001730 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001731 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001732 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001733 if (!target_cmsg)
1734 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001735
1736 while (cmsg && target_cmsg) {
1737 void *data = CMSG_DATA(cmsg);
1738 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1739
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001740 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001741 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001742
1743 space += CMSG_SPACE(len);
1744 if (space > msgh->msg_controllen) {
1745 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001746 /* This is a QEMU bug, since we allocated the payload
1747 * area ourselves (unlike overflow in host-to-target
1748 * conversion, which is just the guest giving us a buffer
1749 * that's too small). It can't happen for the payload types
1750 * we currently support; if it becomes an issue in future
1751 * we would need to improve our allocation strategy to
1752 * something more intelligent than "twice the size of the
1753 * target buffer we're reading from".
1754 */
bellard31febb72005-12-18 20:03:27 +00001755 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001756 break;
1757 }
1758
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001759 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1760 cmsg->cmsg_level = SOL_SOCKET;
1761 } else {
1762 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1763 }
bellard7854b052003-03-29 17:22:23 +00001764 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1765 cmsg->cmsg_len = CMSG_LEN(len);
1766
Alex Suykov30b8b682014-12-23 07:52:58 +02001767 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001768 int *fd = (int *)data;
1769 int *target_fd = (int *)target_data;
1770 int i, numfds = len / sizeof(int);
1771
Peter Maydell876e23c2015-05-26 19:46:32 +01001772 for (i = 0; i < numfds; i++) {
1773 __get_user(fd[i], target_fd + i);
1774 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001775 } else if (cmsg->cmsg_level == SOL_SOCKET
1776 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1777 struct ucred *cred = (struct ucred *)data;
1778 struct target_ucred *target_cred =
1779 (struct target_ucred *)target_data;
1780
Peter Maydell876e23c2015-05-26 19:46:32 +01001781 __get_user(cred->pid, &target_cred->pid);
1782 __get_user(cred->uid, &target_cred->uid);
1783 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001784 } else {
1785 gemu_log("Unsupported ancillary data: %d/%d\n",
1786 cmsg->cmsg_level, cmsg->cmsg_type);
1787 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001788 }
1789
1790 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001791 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1792 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001793 }
bellard5a4a8982007-11-11 17:39:18 +00001794 unlock_user(target_cmsg, target_cmsg_addr, 0);
1795 the_end:
bellard7854b052003-03-29 17:22:23 +00001796 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001797 return 0;
bellard7854b052003-03-29 17:22:23 +00001798}
1799
bellard5a4a8982007-11-11 17:39:18 +00001800static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1801 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001802{
1803 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001804 abi_long msg_controllen;
1805 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001806 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001807 socklen_t space = 0;
1808
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001809 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001810 if (msg_controllen < sizeof (struct target_cmsghdr))
1811 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001812 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001813 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001814 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001815 if (!target_cmsg)
1816 return -TARGET_EFAULT;
1817
bellard7854b052003-03-29 17:22:23 +00001818 while (cmsg && target_cmsg) {
1819 void *data = CMSG_DATA(cmsg);
1820 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1821
Peter Maydellad762b92017-12-15 13:52:56 +00001822 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001823 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001824
Peter Maydellc2aeb252015-05-26 19:46:31 +01001825 /* We never copy a half-header but may copy half-data;
1826 * this is Linux's behaviour in put_cmsg(). Note that
1827 * truncation here is a guest problem (which we report
1828 * to the guest via the CTRUNC bit), unlike truncation
1829 * in target_to_host_cmsg, which is a QEMU bug.
1830 */
Peter Maydell71749702017-12-15 13:52:55 +00001831 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001832 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001833 break;
1834 }
1835
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001836 if (cmsg->cmsg_level == SOL_SOCKET) {
1837 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1838 } else {
1839 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1840 }
bellard7854b052003-03-29 17:22:23 +00001841 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001842
Peter Maydellc2aeb252015-05-26 19:46:31 +01001843 /* Payload types which need a different size of payload on
1844 * the target must adjust tgt_len here.
1845 */
Peter Maydell309786c2018-05-18 19:47:15 +01001846 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001847 switch (cmsg->cmsg_level) {
1848 case SOL_SOCKET:
1849 switch (cmsg->cmsg_type) {
1850 case SO_TIMESTAMP:
1851 tgt_len = sizeof(struct target_timeval);
1852 break;
1853 default:
1854 break;
1855 }
Peter Maydell309786c2018-05-18 19:47:15 +01001856 break;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001857 default:
1858 break;
1859 }
1860
Peter Maydell71749702017-12-15 13:52:55 +00001861 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001862 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001863 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001864 }
1865
1866 /* We must now copy-and-convert len bytes of payload
1867 * into tgt_len bytes of destination space. Bear in mind
1868 * that in both source and destination we may be dealing
1869 * with a truncated value!
1870 */
Huw Davies52b65492014-04-17 14:02:47 +01001871 switch (cmsg->cmsg_level) {
1872 case SOL_SOCKET:
1873 switch (cmsg->cmsg_type) {
1874 case SCM_RIGHTS:
1875 {
1876 int *fd = (int *)data;
1877 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001878 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001879
Peter Maydell876e23c2015-05-26 19:46:32 +01001880 for (i = 0; i < numfds; i++) {
1881 __put_user(fd[i], target_fd + i);
1882 }
Huw Davies52b65492014-04-17 14:02:47 +01001883 break;
1884 }
1885 case SO_TIMESTAMP:
1886 {
1887 struct timeval *tv = (struct timeval *)data;
1888 struct target_timeval *target_tv =
1889 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001890
Peter Maydellc2aeb252015-05-26 19:46:31 +01001891 if (len != sizeof(struct timeval) ||
1892 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001893 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001894 }
Huw Davies52b65492014-04-17 14:02:47 +01001895
1896 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001897 __put_user(tv->tv_sec, &target_tv->tv_sec);
1898 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001899 break;
1900 }
Huw Davies4bc29752014-04-17 14:02:48 +01001901 case SCM_CREDENTIALS:
1902 {
1903 struct ucred *cred = (struct ucred *)data;
1904 struct target_ucred *target_cred =
1905 (struct target_ucred *)target_data;
1906
1907 __put_user(cred->pid, &target_cred->pid);
1908 __put_user(cred->uid, &target_cred->uid);
1909 __put_user(cred->gid, &target_cred->gid);
1910 break;
1911 }
Huw Davies52b65492014-04-17 14:02:47 +01001912 default:
1913 goto unimplemented;
1914 }
1915 break;
1916
Helge Delleree1ac3a2017-02-18 23:31:30 +01001917 case SOL_IP:
1918 switch (cmsg->cmsg_type) {
1919 case IP_TTL:
1920 {
1921 uint32_t *v = (uint32_t *)data;
1922 uint32_t *t_int = (uint32_t *)target_data;
1923
Peter Maydell71749702017-12-15 13:52:55 +00001924 if (len != sizeof(uint32_t) ||
1925 tgt_len != sizeof(uint32_t)) {
1926 goto unimplemented;
1927 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001928 __put_user(*v, t_int);
1929 break;
1930 }
1931 case IP_RECVERR:
1932 {
1933 struct errhdr_t {
1934 struct sock_extended_err ee;
1935 struct sockaddr_in offender;
1936 };
1937 struct errhdr_t *errh = (struct errhdr_t *)data;
1938 struct errhdr_t *target_errh =
1939 (struct errhdr_t *)target_data;
1940
Peter Maydell71749702017-12-15 13:52:55 +00001941 if (len != sizeof(struct errhdr_t) ||
1942 tgt_len != sizeof(struct errhdr_t)) {
1943 goto unimplemented;
1944 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001945 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1946 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1947 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1948 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1949 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1950 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1951 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1952 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1953 (void *) &errh->offender, sizeof(errh->offender));
1954 break;
1955 }
1956 default:
1957 goto unimplemented;
1958 }
1959 break;
1960
1961 case SOL_IPV6:
1962 switch (cmsg->cmsg_type) {
1963 case IPV6_HOPLIMIT:
1964 {
1965 uint32_t *v = (uint32_t *)data;
1966 uint32_t *t_int = (uint32_t *)target_data;
1967
Peter Maydell71749702017-12-15 13:52:55 +00001968 if (len != sizeof(uint32_t) ||
1969 tgt_len != sizeof(uint32_t)) {
1970 goto unimplemented;
1971 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001972 __put_user(*v, t_int);
1973 break;
1974 }
1975 case IPV6_RECVERR:
1976 {
1977 struct errhdr6_t {
1978 struct sock_extended_err ee;
1979 struct sockaddr_in6 offender;
1980 };
1981 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1982 struct errhdr6_t *target_errh =
1983 (struct errhdr6_t *)target_data;
1984
Peter Maydell71749702017-12-15 13:52:55 +00001985 if (len != sizeof(struct errhdr6_t) ||
1986 tgt_len != sizeof(struct errhdr6_t)) {
1987 goto unimplemented;
1988 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001989 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1990 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1991 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1992 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1993 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1994 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1995 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1996 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1997 (void *) &errh->offender, sizeof(errh->offender));
1998 break;
1999 }
2000 default:
2001 goto unimplemented;
2002 }
2003 break;
2004
Huw Davies52b65492014-04-17 14:02:47 +01002005 default:
2006 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00002007 gemu_log("Unsupported ancillary data: %d/%d\n",
2008 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002009 memcpy(target_data, data, MIN(len, tgt_len));
2010 if (tgt_len > len) {
2011 memset(target_data + len, 0, tgt_len - len);
2012 }
bellard7854b052003-03-29 17:22:23 +00002013 }
2014
Peter Maydell71749702017-12-15 13:52:55 +00002015 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
2016 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01002017 if (msg_controllen < tgt_space) {
2018 tgt_space = msg_controllen;
2019 }
2020 msg_controllen -= tgt_space;
2021 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00002022 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02002023 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
2024 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00002025 }
bellard5a4a8982007-11-11 17:39:18 +00002026 unlock_user(target_cmsg, target_cmsg_addr, space);
2027 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002028 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00002029 return 0;
bellard7854b052003-03-29 17:22:23 +00002030}
2031
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002032static void tswap_nlmsghdr(struct nlmsghdr *nlh)
2033{
2034 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
2035 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
2036 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
2037 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
2038 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
2039}
2040
2041static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
2042 size_t len,
2043 abi_long (*host_to_target_nlmsg)
2044 (struct nlmsghdr *))
2045{
2046 uint32_t nlmsg_len;
2047 abi_long ret;
2048
2049 while (len > sizeof(struct nlmsghdr)) {
2050
2051 nlmsg_len = nlh->nlmsg_len;
2052 if (nlmsg_len < sizeof(struct nlmsghdr) ||
2053 nlmsg_len > len) {
2054 break;
2055 }
2056
2057 switch (nlh->nlmsg_type) {
2058 case NLMSG_DONE:
2059 tswap_nlmsghdr(nlh);
2060 return 0;
2061 case NLMSG_NOOP:
2062 break;
2063 case NLMSG_ERROR:
2064 {
2065 struct nlmsgerr *e = NLMSG_DATA(nlh);
2066 e->error = tswap32(e->error);
2067 tswap_nlmsghdr(&e->msg);
2068 tswap_nlmsghdr(nlh);
2069 return 0;
2070 }
2071 default:
2072 ret = host_to_target_nlmsg(nlh);
2073 if (ret < 0) {
2074 tswap_nlmsghdr(nlh);
2075 return ret;
2076 }
2077 break;
2078 }
2079 tswap_nlmsghdr(nlh);
2080 len -= NLMSG_ALIGN(nlmsg_len);
2081 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
2082 }
2083 return 0;
2084}
2085
2086static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
2087 size_t len,
2088 abi_long (*target_to_host_nlmsg)
2089 (struct nlmsghdr *))
2090{
2091 int ret;
2092
2093 while (len > sizeof(struct nlmsghdr)) {
2094 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
2095 tswap32(nlh->nlmsg_len) > len) {
2096 break;
2097 }
2098 tswap_nlmsghdr(nlh);
2099 switch (nlh->nlmsg_type) {
2100 case NLMSG_DONE:
2101 return 0;
2102 case NLMSG_NOOP:
2103 break;
2104 case NLMSG_ERROR:
2105 {
2106 struct nlmsgerr *e = NLMSG_DATA(nlh);
2107 e->error = tswap32(e->error);
2108 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02002109 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002110 }
2111 default:
2112 ret = target_to_host_nlmsg(nlh);
2113 if (ret < 0) {
2114 return ret;
2115 }
2116 }
2117 len -= NLMSG_ALIGN(nlh->nlmsg_len);
2118 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
2119 }
2120 return 0;
2121}
2122
Laurent Vivier575b22b2016-06-02 22:14:15 +02002123#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02002124static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
2125 size_t len, void *context,
2126 abi_long (*host_to_target_nlattr)
2127 (struct nlattr *,
2128 void *context))
2129{
2130 unsigned short nla_len;
2131 abi_long ret;
2132
2133 while (len > sizeof(struct nlattr)) {
2134 nla_len = nlattr->nla_len;
2135 if (nla_len < sizeof(struct nlattr) ||
2136 nla_len > len) {
2137 break;
2138 }
2139 ret = host_to_target_nlattr(nlattr, context);
2140 nlattr->nla_len = tswap16(nlattr->nla_len);
2141 nlattr->nla_type = tswap16(nlattr->nla_type);
2142 if (ret < 0) {
2143 return ret;
2144 }
2145 len -= NLA_ALIGN(nla_len);
2146 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
2147 }
2148 return 0;
2149}
2150
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002151static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
2152 size_t len,
2153 abi_long (*host_to_target_rtattr)
2154 (struct rtattr *))
2155{
2156 unsigned short rta_len;
2157 abi_long ret;
2158
2159 while (len > sizeof(struct rtattr)) {
2160 rta_len = rtattr->rta_len;
2161 if (rta_len < sizeof(struct rtattr) ||
2162 rta_len > len) {
2163 break;
2164 }
2165 ret = host_to_target_rtattr(rtattr);
2166 rtattr->rta_len = tswap16(rtattr->rta_len);
2167 rtattr->rta_type = tswap16(rtattr->rta_type);
2168 if (ret < 0) {
2169 return ret;
2170 }
2171 len -= RTA_ALIGN(rta_len);
2172 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2173 }
2174 return 0;
2175}
2176
Laurent Vivierc5dff282016-06-27 18:54:30 +02002177#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2178
2179static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2180 void *context)
2181{
2182 uint16_t *u16;
2183 uint32_t *u32;
2184 uint64_t *u64;
2185
2186 switch (nlattr->nla_type) {
2187 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002188 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002189 break;
2190 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002191 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002192 break;
2193 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002194 case QEMU_IFLA_BR_VLAN_FILTERING:
2195 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2196 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2197 case QEMU_IFLA_BR_MCAST_ROUTER:
2198 case QEMU_IFLA_BR_MCAST_SNOOPING:
2199 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2200 case QEMU_IFLA_BR_MCAST_QUERIER:
2201 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2202 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2203 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc1e703f2018-05-17 00:12:13 +02002204 case QEMU_IFLA_BR_VLAN_STATS_ENABLED:
2205 case QEMU_IFLA_BR_MCAST_STATS_ENABLED:
2206 case QEMU_IFLA_BR_MCAST_IGMP_VERSION:
2207 case QEMU_IFLA_BR_MCAST_MLD_VERSION:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002208 break;
2209 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002210 case QEMU_IFLA_BR_PRIORITY:
2211 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2212 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2213 case QEMU_IFLA_BR_ROOT_PORT:
2214 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002215 u16 = NLA_DATA(nlattr);
2216 *u16 = tswap16(*u16);
2217 break;
2218 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002219 case QEMU_IFLA_BR_FORWARD_DELAY:
2220 case QEMU_IFLA_BR_HELLO_TIME:
2221 case QEMU_IFLA_BR_MAX_AGE:
2222 case QEMU_IFLA_BR_AGEING_TIME:
2223 case QEMU_IFLA_BR_STP_STATE:
2224 case QEMU_IFLA_BR_ROOT_PATH_COST:
2225 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2226 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2227 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2228 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002229 u32 = NLA_DATA(nlattr);
2230 *u32 = tswap32(*u32);
2231 break;
2232 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002233 case QEMU_IFLA_BR_HELLO_TIMER:
2234 case QEMU_IFLA_BR_TCN_TIMER:
2235 case QEMU_IFLA_BR_GC_TIMER:
2236 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2237 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2238 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2239 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2240 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2241 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2242 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002243 u64 = NLA_DATA(nlattr);
2244 *u64 = tswap64(*u64);
2245 break;
2246 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002247 case QEMU_IFLA_BR_ROOT_ID:
2248 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002249 break;
2250 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002251 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002252 break;
2253 }
2254 return 0;
2255}
2256
2257static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2258 void *context)
2259{
2260 uint16_t *u16;
2261 uint32_t *u32;
2262 uint64_t *u64;
2263
2264 switch (nlattr->nla_type) {
2265 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002266 case QEMU_IFLA_BRPORT_STATE:
2267 case QEMU_IFLA_BRPORT_MODE:
2268 case QEMU_IFLA_BRPORT_GUARD:
2269 case QEMU_IFLA_BRPORT_PROTECT:
2270 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2271 case QEMU_IFLA_BRPORT_LEARNING:
2272 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2273 case QEMU_IFLA_BRPORT_PROXYARP:
2274 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2275 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2276 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2277 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2278 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc1e703f2018-05-17 00:12:13 +02002279 case QEMU_IFLA_BRPORT_MCAST_FLOOD:
2280 case QEMU_IFLA_BRPORT_MCAST_TO_UCAST:
2281 case QEMU_IFLA_BRPORT_VLAN_TUNNEL:
2282 case QEMU_IFLA_BRPORT_BCAST_FLOOD:
2283 case QEMU_IFLA_BRPORT_NEIGH_SUPPRESS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002284 break;
2285 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002286 case QEMU_IFLA_BRPORT_PRIORITY:
2287 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2288 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2289 case QEMU_IFLA_BRPORT_ID:
2290 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc1e703f2018-05-17 00:12:13 +02002291 case QEMU_IFLA_BRPORT_GROUP_FWD_MASK:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002292 u16 = NLA_DATA(nlattr);
2293 *u16 = tswap16(*u16);
2294 break;
2295 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002296 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002297 u32 = NLA_DATA(nlattr);
2298 *u32 = tswap32(*u32);
2299 break;
2300 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002301 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2302 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2303 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002304 u64 = NLA_DATA(nlattr);
2305 *u64 = tswap64(*u64);
2306 break;
2307 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002308 case QEMU_IFLA_BRPORT_ROOT_ID:
2309 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002310 break;
2311 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002312 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002313 break;
2314 }
2315 return 0;
2316}
2317
2318struct linkinfo_context {
2319 int len;
2320 char *name;
2321 int slave_len;
2322 char *slave_name;
2323};
2324
2325static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2326 void *context)
2327{
2328 struct linkinfo_context *li_context = context;
2329
2330 switch (nlattr->nla_type) {
2331 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002332 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002333 li_context->name = NLA_DATA(nlattr);
2334 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2335 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002336 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002337 li_context->slave_name = NLA_DATA(nlattr);
2338 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2339 break;
2340 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002341 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002342 /* FIXME: only used by CAN */
2343 break;
2344 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002345 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002346 if (strncmp(li_context->name, "bridge",
2347 li_context->len) == 0) {
2348 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2349 nlattr->nla_len,
2350 NULL,
2351 host_to_target_data_bridge_nlattr);
2352 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002353 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002354 }
2355 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002356 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002357 if (strncmp(li_context->slave_name, "bridge",
2358 li_context->slave_len) == 0) {
2359 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2360 nlattr->nla_len,
2361 NULL,
2362 host_to_target_slave_data_bridge_nlattr);
2363 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002364 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002365 li_context->slave_name);
2366 }
2367 break;
2368 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002369 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002370 break;
2371 }
2372
2373 return 0;
2374}
2375
2376static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2377 void *context)
2378{
2379 uint32_t *u32;
2380 int i;
2381
2382 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002383 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002384 u32 = NLA_DATA(nlattr);
2385 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2386 i++) {
2387 u32[i] = tswap32(u32[i]);
2388 }
2389 break;
2390 default:
2391 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2392 }
2393 return 0;
2394}
2395
2396static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2397 void *context)
2398{
2399 uint32_t *u32;
2400 uint64_t *u64;
2401 struct ifla_cacheinfo *ci;
2402 int i;
2403
2404 switch (nlattr->nla_type) {
2405 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002406 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002407 break;
2408 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002409 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002410 break;
2411 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002412 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002413 u32 = NLA_DATA(nlattr);
2414 *u32 = tswap32(*u32);
2415 break;
2416 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002417 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002418 u32 = NLA_DATA(nlattr);
2419 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2420 i++) {
2421 u32[i] = tswap32(u32[i]);
2422 }
2423 break;
2424 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002425 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002426 ci = NLA_DATA(nlattr);
2427 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2428 ci->tstamp = tswap32(ci->tstamp);
2429 ci->reachable_time = tswap32(ci->reachable_time);
2430 ci->retrans_time = tswap32(ci->retrans_time);
2431 break;
2432 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002433 case QEMU_IFLA_INET6_STATS:
2434 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002435 u64 = NLA_DATA(nlattr);
2436 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2437 i++) {
2438 u64[i] = tswap64(u64[i]);
2439 }
2440 break;
2441 default:
2442 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2443 }
2444 return 0;
2445}
2446
2447static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2448 void *context)
2449{
2450 switch (nlattr->nla_type) {
2451 case AF_INET:
2452 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2453 NULL,
2454 host_to_target_data_inet_nlattr);
2455 case AF_INET6:
2456 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2457 NULL,
2458 host_to_target_data_inet6_nlattr);
2459 default:
2460 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2461 break;
2462 }
2463 return 0;
2464}
2465
Laurent Vivierc1e703f2018-05-17 00:12:13 +02002466static abi_long host_to_target_data_xdp_nlattr(struct nlattr *nlattr,
2467 void *context)
2468{
2469 uint32_t *u32;
2470
2471 switch (nlattr->nla_type) {
2472 /* uint8_t */
2473 case QEMU_IFLA_XDP_ATTACHED:
2474 break;
2475 /* uint32_t */
2476 case QEMU_IFLA_XDP_PROG_ID:
2477 u32 = NLA_DATA(nlattr);
2478 *u32 = tswap32(*u32);
2479 break;
2480 default:
2481 gemu_log("Unknown host XDP type: %d\n", nlattr->nla_type);
2482 break;
2483 }
2484 return 0;
2485}
2486
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002487static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2488{
2489 uint32_t *u32;
2490 struct rtnl_link_stats *st;
2491 struct rtnl_link_stats64 *st64;
2492 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002493 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002494
2495 switch (rtattr->rta_type) {
2496 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002497 case QEMU_IFLA_ADDRESS:
2498 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002499 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002500 case QEMU_IFLA_IFNAME:
2501 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002502 break;
2503 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002504 case QEMU_IFLA_OPERSTATE:
2505 case QEMU_IFLA_LINKMODE:
2506 case QEMU_IFLA_CARRIER:
2507 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002508 break;
2509 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002510 case QEMU_IFLA_MTU:
2511 case QEMU_IFLA_LINK:
2512 case QEMU_IFLA_WEIGHT:
2513 case QEMU_IFLA_TXQLEN:
2514 case QEMU_IFLA_CARRIER_CHANGES:
2515 case QEMU_IFLA_NUM_RX_QUEUES:
2516 case QEMU_IFLA_NUM_TX_QUEUES:
2517 case QEMU_IFLA_PROMISCUITY:
2518 case QEMU_IFLA_EXT_MASK:
2519 case QEMU_IFLA_LINK_NETNSID:
2520 case QEMU_IFLA_GROUP:
2521 case QEMU_IFLA_MASTER:
2522 case QEMU_IFLA_NUM_VF:
Laurent Viviera1488b82016-10-27 03:00:49 +02002523 case QEMU_IFLA_GSO_MAX_SEGS:
2524 case QEMU_IFLA_GSO_MAX_SIZE:
Laurent Vivierd2ba2462018-06-27 23:21:51 +02002525 case QEMU_IFLA_CARRIER_UP_COUNT:
2526 case QEMU_IFLA_CARRIER_DOWN_COUNT:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002527 u32 = RTA_DATA(rtattr);
2528 *u32 = tswap32(*u32);
2529 break;
2530 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002531 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002532 st = RTA_DATA(rtattr);
2533 st->rx_packets = tswap32(st->rx_packets);
2534 st->tx_packets = tswap32(st->tx_packets);
2535 st->rx_bytes = tswap32(st->rx_bytes);
2536 st->tx_bytes = tswap32(st->tx_bytes);
2537 st->rx_errors = tswap32(st->rx_errors);
2538 st->tx_errors = tswap32(st->tx_errors);
2539 st->rx_dropped = tswap32(st->rx_dropped);
2540 st->tx_dropped = tswap32(st->tx_dropped);
2541 st->multicast = tswap32(st->multicast);
2542 st->collisions = tswap32(st->collisions);
2543
2544 /* detailed rx_errors: */
2545 st->rx_length_errors = tswap32(st->rx_length_errors);
2546 st->rx_over_errors = tswap32(st->rx_over_errors);
2547 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2548 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2549 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2550 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2551
2552 /* detailed tx_errors */
2553 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2554 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2555 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2556 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2557 st->tx_window_errors = tswap32(st->tx_window_errors);
2558
2559 /* for cslip etc */
2560 st->rx_compressed = tswap32(st->rx_compressed);
2561 st->tx_compressed = tswap32(st->tx_compressed);
2562 break;
2563 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002564 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002565 st64 = RTA_DATA(rtattr);
2566 st64->rx_packets = tswap64(st64->rx_packets);
2567 st64->tx_packets = tswap64(st64->tx_packets);
2568 st64->rx_bytes = tswap64(st64->rx_bytes);
2569 st64->tx_bytes = tswap64(st64->tx_bytes);
2570 st64->rx_errors = tswap64(st64->rx_errors);
2571 st64->tx_errors = tswap64(st64->tx_errors);
2572 st64->rx_dropped = tswap64(st64->rx_dropped);
2573 st64->tx_dropped = tswap64(st64->tx_dropped);
2574 st64->multicast = tswap64(st64->multicast);
2575 st64->collisions = tswap64(st64->collisions);
2576
2577 /* detailed rx_errors: */
2578 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2579 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2580 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2581 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2582 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2583 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2584
2585 /* detailed tx_errors */
2586 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2587 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2588 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2589 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2590 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2591
2592 /* for cslip etc */
2593 st64->rx_compressed = tswap64(st64->rx_compressed);
2594 st64->tx_compressed = tswap64(st64->tx_compressed);
2595 break;
2596 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002597 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002598 map = RTA_DATA(rtattr);
2599 map->mem_start = tswap64(map->mem_start);
2600 map->mem_end = tswap64(map->mem_end);
2601 map->base_addr = tswap64(map->base_addr);
2602 map->irq = tswap16(map->irq);
2603 break;
2604 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002605 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002606 memset(&li_context, 0, sizeof(li_context));
2607 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2608 &li_context,
2609 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002610 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002611 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2612 NULL,
2613 host_to_target_data_spec_nlattr);
Laurent Vivierc1e703f2018-05-17 00:12:13 +02002614 case QEMU_IFLA_XDP:
2615 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2616 NULL,
2617 host_to_target_data_xdp_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002618 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002619 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002620 break;
2621 }
2622 return 0;
2623}
2624
2625static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2626{
2627 uint32_t *u32;
2628 struct ifa_cacheinfo *ci;
2629
2630 switch (rtattr->rta_type) {
2631 /* binary: depends on family type */
2632 case IFA_ADDRESS:
2633 case IFA_LOCAL:
2634 break;
2635 /* string */
2636 case IFA_LABEL:
2637 break;
2638 /* u32 */
2639 case IFA_FLAGS:
2640 case IFA_BROADCAST:
2641 u32 = RTA_DATA(rtattr);
2642 *u32 = tswap32(*u32);
2643 break;
2644 /* struct ifa_cacheinfo */
2645 case IFA_CACHEINFO:
2646 ci = RTA_DATA(rtattr);
2647 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2648 ci->ifa_valid = tswap32(ci->ifa_valid);
2649 ci->cstamp = tswap32(ci->cstamp);
2650 ci->tstamp = tswap32(ci->tstamp);
2651 break;
2652 default:
2653 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2654 break;
2655 }
2656 return 0;
2657}
2658
2659static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2660{
2661 uint32_t *u32;
2662 switch (rtattr->rta_type) {
2663 /* binary: depends on family type */
2664 case RTA_GATEWAY:
2665 case RTA_DST:
2666 case RTA_PREFSRC:
2667 break;
2668 /* u32 */
2669 case RTA_PRIORITY:
2670 case RTA_TABLE:
2671 case RTA_OIF:
2672 u32 = RTA_DATA(rtattr);
2673 *u32 = tswap32(*u32);
2674 break;
2675 default:
2676 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2677 break;
2678 }
2679 return 0;
2680}
2681
2682static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2683 uint32_t rtattr_len)
2684{
2685 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2686 host_to_target_data_link_rtattr);
2687}
2688
2689static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2690 uint32_t rtattr_len)
2691{
2692 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2693 host_to_target_data_addr_rtattr);
2694}
2695
2696static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2697 uint32_t rtattr_len)
2698{
2699 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2700 host_to_target_data_route_rtattr);
2701}
2702
2703static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2704{
2705 uint32_t nlmsg_len;
2706 struct ifinfomsg *ifi;
2707 struct ifaddrmsg *ifa;
2708 struct rtmsg *rtm;
2709
2710 nlmsg_len = nlh->nlmsg_len;
2711 switch (nlh->nlmsg_type) {
2712 case RTM_NEWLINK:
2713 case RTM_DELLINK:
2714 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002715 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2716 ifi = NLMSG_DATA(nlh);
2717 ifi->ifi_type = tswap16(ifi->ifi_type);
2718 ifi->ifi_index = tswap32(ifi->ifi_index);
2719 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2720 ifi->ifi_change = tswap32(ifi->ifi_change);
2721 host_to_target_link_rtattr(IFLA_RTA(ifi),
2722 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2723 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002724 break;
2725 case RTM_NEWADDR:
2726 case RTM_DELADDR:
2727 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002728 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2729 ifa = NLMSG_DATA(nlh);
2730 ifa->ifa_index = tswap32(ifa->ifa_index);
2731 host_to_target_addr_rtattr(IFA_RTA(ifa),
2732 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2733 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002734 break;
2735 case RTM_NEWROUTE:
2736 case RTM_DELROUTE:
2737 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002738 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2739 rtm = NLMSG_DATA(nlh);
2740 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2741 host_to_target_route_rtattr(RTM_RTA(rtm),
2742 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2743 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002744 break;
2745 default:
2746 return -TARGET_EINVAL;
2747 }
2748 return 0;
2749}
2750
2751static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2752 size_t len)
2753{
2754 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2755}
2756
2757static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2758 size_t len,
2759 abi_long (*target_to_host_rtattr)
2760 (struct rtattr *))
2761{
2762 abi_long ret;
2763
2764 while (len >= sizeof(struct rtattr)) {
2765 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2766 tswap16(rtattr->rta_len) > len) {
2767 break;
2768 }
2769 rtattr->rta_len = tswap16(rtattr->rta_len);
2770 rtattr->rta_type = tswap16(rtattr->rta_type);
2771 ret = target_to_host_rtattr(rtattr);
2772 if (ret < 0) {
2773 return ret;
2774 }
2775 len -= RTA_ALIGN(rtattr->rta_len);
2776 rtattr = (struct rtattr *)(((char *)rtattr) +
2777 RTA_ALIGN(rtattr->rta_len));
2778 }
2779 return 0;
2780}
2781
2782static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2783{
2784 switch (rtattr->rta_type) {
2785 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002786 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002787 break;
2788 }
2789 return 0;
2790}
2791
2792static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2793{
2794 switch (rtattr->rta_type) {
2795 /* binary: depends on family type */
2796 case IFA_LOCAL:
2797 case IFA_ADDRESS:
2798 break;
2799 default:
2800 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2801 break;
2802 }
2803 return 0;
2804}
2805
2806static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2807{
2808 uint32_t *u32;
2809 switch (rtattr->rta_type) {
2810 /* binary: depends on family type */
2811 case RTA_DST:
2812 case RTA_SRC:
2813 case RTA_GATEWAY:
2814 break;
2815 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002816 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002817 case RTA_OIF:
2818 u32 = RTA_DATA(rtattr);
2819 *u32 = tswap32(*u32);
2820 break;
2821 default:
2822 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2823 break;
2824 }
2825 return 0;
2826}
2827
2828static void target_to_host_link_rtattr(struct rtattr *rtattr,
2829 uint32_t rtattr_len)
2830{
2831 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2832 target_to_host_data_link_rtattr);
2833}
2834
2835static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2836 uint32_t rtattr_len)
2837{
2838 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2839 target_to_host_data_addr_rtattr);
2840}
2841
2842static void target_to_host_route_rtattr(struct rtattr *rtattr,
2843 uint32_t rtattr_len)
2844{
2845 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2846 target_to_host_data_route_rtattr);
2847}
2848
2849static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2850{
2851 struct ifinfomsg *ifi;
2852 struct ifaddrmsg *ifa;
2853 struct rtmsg *rtm;
2854
2855 switch (nlh->nlmsg_type) {
2856 case RTM_GETLINK:
2857 break;
2858 case RTM_NEWLINK:
2859 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002860 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2861 ifi = NLMSG_DATA(nlh);
2862 ifi->ifi_type = tswap16(ifi->ifi_type);
2863 ifi->ifi_index = tswap32(ifi->ifi_index);
2864 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2865 ifi->ifi_change = tswap32(ifi->ifi_change);
2866 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2867 NLMSG_LENGTH(sizeof(*ifi)));
2868 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002869 break;
2870 case RTM_GETADDR:
2871 case RTM_NEWADDR:
2872 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002873 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2874 ifa = NLMSG_DATA(nlh);
2875 ifa->ifa_index = tswap32(ifa->ifa_index);
2876 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2877 NLMSG_LENGTH(sizeof(*ifa)));
2878 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002879 break;
2880 case RTM_GETROUTE:
2881 break;
2882 case RTM_NEWROUTE:
2883 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002884 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2885 rtm = NLMSG_DATA(nlh);
2886 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2887 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2888 NLMSG_LENGTH(sizeof(*rtm)));
2889 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002890 break;
2891 default:
2892 return -TARGET_EOPNOTSUPP;
2893 }
2894 return 0;
2895}
2896
2897static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2898{
2899 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2900}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002901#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002902
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002903static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2904{
2905 switch (nlh->nlmsg_type) {
2906 default:
2907 gemu_log("Unknown host audit message type %d\n",
2908 nlh->nlmsg_type);
2909 return -TARGET_EINVAL;
2910 }
2911 return 0;
2912}
2913
2914static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2915 size_t len)
2916{
2917 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2918}
2919
2920static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2921{
2922 switch (nlh->nlmsg_type) {
2923 case AUDIT_USER:
2924 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2925 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2926 break;
2927 default:
2928 gemu_log("Unknown target audit message type %d\n",
2929 nlh->nlmsg_type);
2930 return -TARGET_EINVAL;
2931 }
2932
2933 return 0;
2934}
2935
2936static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2937{
2938 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2939}
2940
ths0da46a62007-10-20 20:23:07 +00002941/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002942static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002943 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002944{
blueswir1992f48a2007-10-14 16:27:31 +00002945 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002946 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002947 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002948 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002949
bellard8853f862004-02-22 14:57:26 +00002950 switch(level) {
2951 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002952 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002953 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002954 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002955
bellard2f619692007-11-16 10:46:05 +00002956 if (get_user_u32(val, optval_addr))
2957 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002958 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2959 break;
2960 case SOL_IP:
2961 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002962 case IP_TOS:
2963 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002964 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002965 case IP_ROUTER_ALERT:
2966 case IP_RECVOPTS:
2967 case IP_RETOPTS:
2968 case IP_PKTINFO:
2969 case IP_MTU_DISCOVER:
2970 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002971 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002972 case IP_RECVTOS:
2973#ifdef IP_FREEBIND
2974 case IP_FREEBIND:
2975#endif
2976 case IP_MULTICAST_TTL:
2977 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002978 val = 0;
2979 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002980 if (get_user_u32(val, optval_addr))
2981 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002982 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002983 if (get_user_u8(val, optval_addr))
2984 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002985 }
2986 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2987 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002988 case IP_ADD_MEMBERSHIP:
2989 case IP_DROP_MEMBERSHIP:
2990 if (optlen < sizeof (struct target_ip_mreq) ||
2991 optlen > sizeof (struct target_ip_mreqn))
2992 return -TARGET_EINVAL;
2993
2994 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2995 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2996 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2997 break;
2998
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002999 case IP_BLOCK_SOURCE:
3000 case IP_UNBLOCK_SOURCE:
3001 case IP_ADD_SOURCE_MEMBERSHIP:
3002 case IP_DROP_SOURCE_MEMBERSHIP:
3003 if (optlen != sizeof (struct target_ip_mreq_source))
3004 return -TARGET_EINVAL;
3005
3006 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3007 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
3008 unlock_user (ip_mreq_source, optval_addr, 0);
3009 break;
3010
bellard8853f862004-02-22 14:57:26 +00003011 default:
3012 goto unimplemented;
3013 }
3014 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02003015 case SOL_IPV6:
3016 switch (optname) {
3017 case IPV6_MTU_DISCOVER:
3018 case IPV6_MTU:
3019 case IPV6_V6ONLY:
3020 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003021 case IPV6_UNICAST_HOPS:
Laurent Vivier21749c42018-06-27 23:21:52 +02003022 case IPV6_MULTICAST_HOPS:
3023 case IPV6_MULTICAST_LOOP:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003024 case IPV6_RECVERR:
3025 case IPV6_RECVHOPLIMIT:
3026 case IPV6_2292HOPLIMIT:
3027 case IPV6_CHECKSUM:
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02003028 val = 0;
3029 if (optlen < sizeof(uint32_t)) {
3030 return -TARGET_EINVAL;
3031 }
3032 if (get_user_u32(val, optval_addr)) {
3033 return -TARGET_EFAULT;
3034 }
3035 ret = get_errno(setsockopt(sockfd, level, optname,
3036 &val, sizeof(val)));
3037 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01003038 case IPV6_PKTINFO:
3039 {
3040 struct in6_pktinfo pki;
3041
3042 if (optlen < sizeof(pki)) {
3043 return -TARGET_EINVAL;
3044 }
3045
3046 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
3047 return -TARGET_EFAULT;
3048 }
3049
3050 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
3051
3052 ret = get_errno(setsockopt(sockfd, level, optname,
3053 &pki, sizeof(pki)));
3054 break;
3055 }
3056 default:
3057 goto unimplemented;
3058 }
3059 break;
3060 case SOL_ICMPV6:
3061 switch (optname) {
3062 case ICMPV6_FILTER:
3063 {
3064 struct icmp6_filter icmp6f;
3065
3066 if (optlen > sizeof(icmp6f)) {
3067 optlen = sizeof(icmp6f);
3068 }
3069
3070 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
3071 return -TARGET_EFAULT;
3072 }
3073
3074 for (val = 0; val < 8; val++) {
3075 icmp6f.data[val] = tswap32(icmp6f.data[val]);
3076 }
3077
3078 ret = get_errno(setsockopt(sockfd, level, optname,
3079 &icmp6f, optlen));
3080 break;
3081 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02003082 default:
3083 goto unimplemented;
3084 }
3085 break;
Jing Huang920394d2012-07-24 13:59:23 +00003086 case SOL_RAW:
3087 switch (optname) {
3088 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003089 case IPV6_CHECKSUM:
3090 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00003091 if (optlen < sizeof(uint32_t)) {
3092 return -TARGET_EINVAL;
3093 }
3094
3095 if (get_user_u32(val, optval_addr)) {
3096 return -TARGET_EFAULT;
3097 }
3098 ret = get_errno(setsockopt(sockfd, level, optname,
3099 &val, sizeof(val)));
3100 break;
3101
3102 default:
3103 goto unimplemented;
3104 }
3105 break;
bellard3532fa72006-06-24 15:06:03 +00003106 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00003107 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00003108 case TARGET_SO_RCVTIMEO:
3109 {
3110 struct timeval tv;
3111
3112 optname = SO_RCVTIMEO;
3113
3114set_timeout:
3115 if (optlen != sizeof(struct target_timeval)) {
3116 return -TARGET_EINVAL;
3117 }
3118
3119 if (copy_from_user_timeval(&tv, optval_addr)) {
3120 return -TARGET_EFAULT;
3121 }
3122
3123 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3124 &tv, sizeof(tv)));
3125 return ret;
3126 }
3127 case TARGET_SO_SNDTIMEO:
3128 optname = SO_SNDTIMEO;
3129 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02003130 case TARGET_SO_ATTACH_FILTER:
3131 {
3132 struct target_sock_fprog *tfprog;
3133 struct target_sock_filter *tfilter;
3134 struct sock_fprog fprog;
3135 struct sock_filter *filter;
3136 int i;
3137
3138 if (optlen != sizeof(*tfprog)) {
3139 return -TARGET_EINVAL;
3140 }
3141 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
3142 return -TARGET_EFAULT;
3143 }
3144 if (!lock_user_struct(VERIFY_READ, tfilter,
3145 tswapal(tfprog->filter), 0)) {
3146 unlock_user_struct(tfprog, optval_addr, 1);
3147 return -TARGET_EFAULT;
3148 }
3149
3150 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303151 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003152 if (filter == NULL) {
3153 unlock_user_struct(tfilter, tfprog->filter, 1);
3154 unlock_user_struct(tfprog, optval_addr, 1);
3155 return -TARGET_ENOMEM;
3156 }
3157 for (i = 0; i < fprog.len; i++) {
3158 filter[i].code = tswap16(tfilter[i].code);
3159 filter[i].jt = tfilter[i].jt;
3160 filter[i].jf = tfilter[i].jf;
3161 filter[i].k = tswap32(tfilter[i].k);
3162 }
3163 fprog.filter = filter;
3164
3165 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
3166 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303167 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003168
3169 unlock_user_struct(tfilter, tfprog->filter, 1);
3170 unlock_user_struct(tfprog, optval_addr, 1);
3171 return ret;
3172 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003173 case TARGET_SO_BINDTODEVICE:
3174 {
3175 char *dev_ifname, *addr_ifname;
3176
3177 if (optlen > IFNAMSIZ - 1) {
3178 optlen = IFNAMSIZ - 1;
3179 }
3180 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3181 if (!dev_ifname) {
3182 return -TARGET_EFAULT;
3183 }
3184 optname = SO_BINDTODEVICE;
3185 addr_ifname = alloca(IFNAMSIZ);
3186 memcpy(addr_ifname, dev_ifname, optlen);
3187 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08003188 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3189 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003190 unlock_user (dev_ifname, optval_addr, 0);
3191 return ret;
3192 }
bellard8853f862004-02-22 14:57:26 +00003193 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00003194 case TARGET_SO_DEBUG:
3195 optname = SO_DEBUG;
3196 break;
3197 case TARGET_SO_REUSEADDR:
3198 optname = SO_REUSEADDR;
3199 break;
3200 case TARGET_SO_TYPE:
3201 optname = SO_TYPE;
3202 break;
3203 case TARGET_SO_ERROR:
3204 optname = SO_ERROR;
3205 break;
3206 case TARGET_SO_DONTROUTE:
3207 optname = SO_DONTROUTE;
3208 break;
3209 case TARGET_SO_BROADCAST:
3210 optname = SO_BROADCAST;
3211 break;
3212 case TARGET_SO_SNDBUF:
3213 optname = SO_SNDBUF;
3214 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003215 case TARGET_SO_SNDBUFFORCE:
3216 optname = SO_SNDBUFFORCE;
3217 break;
bellard3532fa72006-06-24 15:06:03 +00003218 case TARGET_SO_RCVBUF:
3219 optname = SO_RCVBUF;
3220 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003221 case TARGET_SO_RCVBUFFORCE:
3222 optname = SO_RCVBUFFORCE;
3223 break;
bellard3532fa72006-06-24 15:06:03 +00003224 case TARGET_SO_KEEPALIVE:
3225 optname = SO_KEEPALIVE;
3226 break;
3227 case TARGET_SO_OOBINLINE:
3228 optname = SO_OOBINLINE;
3229 break;
3230 case TARGET_SO_NO_CHECK:
3231 optname = SO_NO_CHECK;
3232 break;
3233 case TARGET_SO_PRIORITY:
3234 optname = SO_PRIORITY;
3235 break;
bellard5e83e8e2005-03-01 22:32:06 +00003236#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00003237 case TARGET_SO_BSDCOMPAT:
3238 optname = SO_BSDCOMPAT;
3239 break;
bellard5e83e8e2005-03-01 22:32:06 +00003240#endif
bellard3532fa72006-06-24 15:06:03 +00003241 case TARGET_SO_PASSCRED:
3242 optname = SO_PASSCRED;
3243 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01003244 case TARGET_SO_PASSSEC:
3245 optname = SO_PASSSEC;
3246 break;
bellard3532fa72006-06-24 15:06:03 +00003247 case TARGET_SO_TIMESTAMP:
3248 optname = SO_TIMESTAMP;
3249 break;
3250 case TARGET_SO_RCVLOWAT:
3251 optname = SO_RCVLOWAT;
3252 break;
bellard8853f862004-02-22 14:57:26 +00003253 default:
3254 goto unimplemented;
3255 }
bellard3532fa72006-06-24 15:06:03 +00003256 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003257 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003258
bellard2f619692007-11-16 10:46:05 +00003259 if (get_user_u32(val, optval_addr))
3260 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003261 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003262 break;
bellard7854b052003-03-29 17:22:23 +00003263 default:
bellard8853f862004-02-22 14:57:26 +00003264 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003265 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003266 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003267 }
bellard8853f862004-02-22 14:57:26 +00003268 return ret;
bellard7854b052003-03-29 17:22:23 +00003269}
3270
ths0da46a62007-10-20 20:23:07 +00003271/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003272static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003273 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003274{
blueswir1992f48a2007-10-14 16:27:31 +00003275 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003276 int len, val;
3277 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003278
3279 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003280 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003281 level = SOL_SOCKET;
3282 switch (optname) {
3283 /* These don't just return a single integer */
3284 case TARGET_SO_LINGER:
3285 case TARGET_SO_RCVTIMEO:
3286 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003287 case TARGET_SO_PEERNAME:
3288 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003289 case TARGET_SO_PEERCRED: {
3290 struct ucred cr;
3291 socklen_t crlen;
3292 struct target_ucred *tcr;
3293
3294 if (get_user_u32(len, optlen)) {
3295 return -TARGET_EFAULT;
3296 }
3297 if (len < 0) {
3298 return -TARGET_EINVAL;
3299 }
3300
3301 crlen = sizeof(cr);
3302 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3303 &cr, &crlen));
3304 if (ret < 0) {
3305 return ret;
3306 }
3307 if (len > crlen) {
3308 len = crlen;
3309 }
3310 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3311 return -TARGET_EFAULT;
3312 }
3313 __put_user(cr.pid, &tcr->pid);
3314 __put_user(cr.uid, &tcr->uid);
3315 __put_user(cr.gid, &tcr->gid);
3316 unlock_user_struct(tcr, optval_addr, 1);
3317 if (put_user_u32(len, optlen)) {
3318 return -TARGET_EFAULT;
3319 }
3320 break;
3321 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003322 /* Options with 'int' argument. */
3323 case TARGET_SO_DEBUG:
3324 optname = SO_DEBUG;
3325 goto int_case;
3326 case TARGET_SO_REUSEADDR:
3327 optname = SO_REUSEADDR;
3328 goto int_case;
3329 case TARGET_SO_TYPE:
3330 optname = SO_TYPE;
3331 goto int_case;
3332 case TARGET_SO_ERROR:
3333 optname = SO_ERROR;
3334 goto int_case;
3335 case TARGET_SO_DONTROUTE:
3336 optname = SO_DONTROUTE;
3337 goto int_case;
3338 case TARGET_SO_BROADCAST:
3339 optname = SO_BROADCAST;
3340 goto int_case;
3341 case TARGET_SO_SNDBUF:
3342 optname = SO_SNDBUF;
3343 goto int_case;
3344 case TARGET_SO_RCVBUF:
3345 optname = SO_RCVBUF;
3346 goto int_case;
3347 case TARGET_SO_KEEPALIVE:
3348 optname = SO_KEEPALIVE;
3349 goto int_case;
3350 case TARGET_SO_OOBINLINE:
3351 optname = SO_OOBINLINE;
3352 goto int_case;
3353 case TARGET_SO_NO_CHECK:
3354 optname = SO_NO_CHECK;
3355 goto int_case;
3356 case TARGET_SO_PRIORITY:
3357 optname = SO_PRIORITY;
3358 goto int_case;
3359#ifdef SO_BSDCOMPAT
3360 case TARGET_SO_BSDCOMPAT:
3361 optname = SO_BSDCOMPAT;
3362 goto int_case;
3363#endif
3364 case TARGET_SO_PASSCRED:
3365 optname = SO_PASSCRED;
3366 goto int_case;
3367 case TARGET_SO_TIMESTAMP:
3368 optname = SO_TIMESTAMP;
3369 goto int_case;
3370 case TARGET_SO_RCVLOWAT:
3371 optname = SO_RCVLOWAT;
3372 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003373 case TARGET_SO_ACCEPTCONN:
3374 optname = SO_ACCEPTCONN;
3375 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003376 default:
bellard2efbe912005-07-23 15:10:20 +00003377 goto int_case;
3378 }
3379 break;
3380 case SOL_TCP:
3381 /* TCP options all take an 'int' value. */
3382 int_case:
bellard2f619692007-11-16 10:46:05 +00003383 if (get_user_u32(len, optlen))
3384 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003385 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003386 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003387 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003388 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3389 if (ret < 0)
3390 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003391 if (optname == SO_TYPE) {
3392 val = host_to_target_sock_type(val);
3393 }
bellard2efbe912005-07-23 15:10:20 +00003394 if (len > lv)
3395 len = lv;
bellard2f619692007-11-16 10:46:05 +00003396 if (len == 4) {
3397 if (put_user_u32(val, optval_addr))
3398 return -TARGET_EFAULT;
3399 } else {
3400 if (put_user_u8(val, optval_addr))
3401 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003402 }
bellard2f619692007-11-16 10:46:05 +00003403 if (put_user_u32(len, optlen))
3404 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003405 break;
3406 case SOL_IP:
3407 switch(optname) {
3408 case IP_TOS:
3409 case IP_TTL:
3410 case IP_HDRINCL:
3411 case IP_ROUTER_ALERT:
3412 case IP_RECVOPTS:
3413 case IP_RETOPTS:
3414 case IP_PKTINFO:
3415 case IP_MTU_DISCOVER:
3416 case IP_RECVERR:
3417 case IP_RECVTOS:
3418#ifdef IP_FREEBIND
3419 case IP_FREEBIND:
3420#endif
3421 case IP_MULTICAST_TTL:
3422 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003423 if (get_user_u32(len, optlen))
3424 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003425 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003426 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003427 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003428 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3429 if (ret < 0)
3430 return ret;
bellard2efbe912005-07-23 15:10:20 +00003431 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003432 len = 1;
bellard2f619692007-11-16 10:46:05 +00003433 if (put_user_u32(len, optlen)
3434 || put_user_u8(val, optval_addr))
3435 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003436 } else {
bellard2efbe912005-07-23 15:10:20 +00003437 if (len > sizeof(int))
3438 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003439 if (put_user_u32(len, optlen)
3440 || put_user_u32(val, optval_addr))
3441 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003442 }
bellard8853f862004-02-22 14:57:26 +00003443 break;
bellard2efbe912005-07-23 15:10:20 +00003444 default:
thsc02f4992007-12-18 02:39:59 +00003445 ret = -TARGET_ENOPROTOOPT;
3446 break;
bellard8853f862004-02-22 14:57:26 +00003447 }
3448 break;
3449 default:
3450 unimplemented:
3451 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3452 level, optname);
thsc02f4992007-12-18 02:39:59 +00003453 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003454 break;
3455 }
3456 return ret;
bellard7854b052003-03-29 17:22:23 +00003457}
3458
Max Filippov9ac22512018-04-04 17:30:41 -07003459/* Convert target low/high pair representing file offset into the host
3460 * low/high pair. This function doesn't handle offsets bigger than 64 bits
3461 * as the kernel doesn't handle them either.
3462 */
3463static void target_to_host_low_high(abi_ulong tlow,
3464 abi_ulong thigh,
3465 unsigned long *hlow,
3466 unsigned long *hhigh)
3467{
3468 uint64_t off = tlow |
3469 ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
3470 TARGET_LONG_BITS / 2;
3471
3472 *hlow = off;
3473 *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
3474}
3475
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003476static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003477 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003478{
3479 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003480 struct iovec *vec;
3481 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003482 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003483 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003484 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003485
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003486 if (count == 0) {
3487 errno = 0;
3488 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003489 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003490 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003491 errno = EINVAL;
3492 return NULL;
3493 }
3494
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303495 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003496 if (vec == NULL) {
3497 errno = ENOMEM;
3498 return NULL;
3499 }
3500
3501 target_vec = lock_user(VERIFY_READ, target_addr,
3502 count * sizeof(struct target_iovec), 1);
3503 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003504 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003505 goto fail2;
3506 }
3507
3508 /* ??? If host page size > target page size, this will result in a
3509 value larger than what we can actually support. */
3510 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3511 total_len = 0;
3512
3513 for (i = 0; i < count; i++) {
3514 abi_ulong base = tswapal(target_vec[i].iov_base);
3515 abi_long len = tswapal(target_vec[i].iov_len);
3516
3517 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003518 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003519 goto fail;
3520 } else if (len == 0) {
3521 /* Zero length pointer is ignored. */
3522 vec[i].iov_base = 0;
3523 } else {
3524 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003525 /* If the first buffer pointer is bad, this is a fault. But
3526 * subsequent bad buffers will result in a partial write; this
3527 * is realized by filling the vector with null pointers and
3528 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003529 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003530 if (i == 0) {
3531 err = EFAULT;
3532 goto fail;
3533 } else {
3534 bad_address = true;
3535 }
3536 }
3537 if (bad_address) {
3538 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003539 }
3540 if (len > max_len - total_len) {
3541 len = max_len - total_len;
3542 }
3543 }
3544 vec[i].iov_len = len;
3545 total_len += len;
3546 }
3547
3548 unlock_user(target_vec, target_addr, 0);
3549 return vec;
3550
3551 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003552 while (--i >= 0) {
3553 if (tswapal(target_vec[i].iov_len) > 0) {
3554 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3555 }
3556 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003557 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003558 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303559 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003560 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003561 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003562}
3563
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003564static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003565 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003566{
3567 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003568 int i;
3569
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003570 target_vec = lock_user(VERIFY_READ, target_addr,
3571 count * sizeof(struct target_iovec), 1);
3572 if (target_vec) {
3573 for (i = 0; i < count; i++) {
3574 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003575 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003576 if (len < 0) {
3577 break;
3578 }
balrogd732dcb2008-10-28 10:21:03 +00003579 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3580 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003581 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003582 }
bellard579a97f2007-11-11 14:26:47 +00003583
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303584 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003585}
3586
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003587static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003588{
3589 int host_type = 0;
3590 int target_type = *type;
3591
3592 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3593 case TARGET_SOCK_DGRAM:
3594 host_type = SOCK_DGRAM;
3595 break;
3596 case TARGET_SOCK_STREAM:
3597 host_type = SOCK_STREAM;
3598 break;
3599 default:
3600 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3601 break;
3602 }
3603 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003604#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003605 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003606#else
3607 return -TARGET_EINVAL;
3608#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003609 }
3610 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003611#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003612 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003613#elif !defined(O_NONBLOCK)
3614 return -TARGET_EINVAL;
3615#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003616 }
3617 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003618 return 0;
3619}
3620
3621/* Try to emulate socket type flags after socket creation. */
3622static int sock_flags_fixup(int fd, int target_type)
3623{
3624#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3625 if (target_type & TARGET_SOCK_NONBLOCK) {
3626 int flags = fcntl(fd, F_GETFL);
3627 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3628 close(fd);
3629 return -TARGET_EINVAL;
3630 }
3631 }
3632#endif
3633 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003634}
3635
Laurent Vivier0cf22722015-10-28 21:40:45 +01003636static abi_long packet_target_to_host_sockaddr(void *host_addr,
3637 abi_ulong target_addr,
3638 socklen_t len)
3639{
3640 struct sockaddr *addr = host_addr;
3641 struct target_sockaddr *target_saddr;
3642
3643 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3644 if (!target_saddr) {
3645 return -TARGET_EFAULT;
3646 }
3647
3648 memcpy(addr, target_saddr, len);
3649 addr->sa_family = tswap16(target_saddr->sa_family);
3650 /* spkt_protocol is big-endian */
3651
3652 unlock_user(target_saddr, target_addr, 0);
3653 return 0;
3654}
3655
3656static TargetFdTrans target_packet_trans = {
3657 .target_to_host_addr = packet_target_to_host_sockaddr,
3658};
3659
Laurent Vivier575b22b2016-06-02 22:14:15 +02003660#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003661static abi_long netlink_route_target_to_host(void *buf, size_t len)
3662{
Laurent Vivieref759f62016-06-21 19:51:13 +02003663 abi_long ret;
3664
3665 ret = target_to_host_nlmsg_route(buf, len);
3666 if (ret < 0) {
3667 return ret;
3668 }
3669
3670 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003671}
3672
3673static abi_long netlink_route_host_to_target(void *buf, size_t len)
3674{
Laurent Vivieref759f62016-06-21 19:51:13 +02003675 abi_long ret;
3676
3677 ret = host_to_target_nlmsg_route(buf, len);
3678 if (ret < 0) {
3679 return ret;
3680 }
3681
3682 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003683}
3684
3685static TargetFdTrans target_netlink_route_trans = {
3686 .target_to_host_data = netlink_route_target_to_host,
3687 .host_to_target_data = netlink_route_host_to_target,
3688};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003689#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003690
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003691static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3692{
Laurent Vivieref759f62016-06-21 19:51:13 +02003693 abi_long ret;
3694
3695 ret = target_to_host_nlmsg_audit(buf, len);
3696 if (ret < 0) {
3697 return ret;
3698 }
3699
3700 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003701}
3702
3703static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3704{
Laurent Vivieref759f62016-06-21 19:51:13 +02003705 abi_long ret;
3706
3707 ret = host_to_target_nlmsg_audit(buf, len);
3708 if (ret < 0) {
3709 return ret;
3710 }
3711
3712 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003713}
3714
3715static TargetFdTrans target_netlink_audit_trans = {
3716 .target_to_host_data = netlink_audit_target_to_host,
3717 .host_to_target_data = netlink_audit_host_to_target,
3718};
3719
ths0da46a62007-10-20 20:23:07 +00003720/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003721static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003722{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003723 int target_type = type;
3724 int ret;
3725
3726 ret = target_to_host_sock_type(&type);
3727 if (ret) {
3728 return ret;
3729 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003730
Laurent Vivier575b22b2016-06-02 22:14:15 +02003731 if (domain == PF_NETLINK && !(
3732#ifdef CONFIG_RTNETLINK
3733 protocol == NETLINK_ROUTE ||
3734#endif
3735 protocol == NETLINK_KOBJECT_UEVENT ||
3736 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003737 return -EPFNOSUPPORT;
3738 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003739
3740 if (domain == AF_PACKET ||
3741 (domain == AF_INET && type == SOCK_PACKET)) {
3742 protocol = tswap16(protocol);
3743 }
3744
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003745 ret = get_errno(socket(domain, type, protocol));
3746 if (ret >= 0) {
3747 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003748 if (type == SOCK_PACKET) {
3749 /* Manage an obsolete case :
3750 * if socket type is SOCK_PACKET, bind by name
3751 */
3752 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003753 } else if (domain == PF_NETLINK) {
3754 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003755#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003756 case NETLINK_ROUTE:
3757 fd_trans_register(ret, &target_netlink_route_trans);
3758 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003759#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003760 case NETLINK_KOBJECT_UEVENT:
3761 /* nothing to do: messages are strings */
3762 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003763 case NETLINK_AUDIT:
3764 fd_trans_register(ret, &target_netlink_audit_trans);
3765 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003766 default:
3767 g_assert_not_reached();
3768 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003769 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003770 }
3771 return ret;
bellard3532fa72006-06-24 15:06:03 +00003772}
3773
ths0da46a62007-10-20 20:23:07 +00003774/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003775static abi_long do_bind(int sockfd, abi_ulong target_addr,
3776 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003777{
aurel328f7aeaf2009-01-30 19:47:57 +00003778 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003779 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003780
Blue Swirl38724252010-09-18 05:53:14 +00003781 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003782 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003783 }
aurel328f7aeaf2009-01-30 19:47:57 +00003784
aurel32607175e2009-04-15 16:11:59 +00003785 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003786
Laurent Vivier7b36f782015-10-28 21:40:44 +01003787 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003788 if (ret)
3789 return ret;
3790
bellard3532fa72006-06-24 15:06:03 +00003791 return get_errno(bind(sockfd, addr, addrlen));
3792}
3793
ths0da46a62007-10-20 20:23:07 +00003794/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003795static abi_long do_connect(int sockfd, abi_ulong target_addr,
3796 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003797{
aurel328f7aeaf2009-01-30 19:47:57 +00003798 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003799 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003800
Blue Swirl38724252010-09-18 05:53:14 +00003801 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003802 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003803 }
aurel328f7aeaf2009-01-30 19:47:57 +00003804
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003805 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003806
Laurent Vivier7b36f782015-10-28 21:40:44 +01003807 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003808 if (ret)
3809 return ret;
3810
Peter Maydell2a3c7612016-06-06 19:58:03 +01003811 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003812}
3813
Alexander Graff19e00d2014-03-02 19:36:42 +00003814/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3815static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3816 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003817{
balrog6de645c2008-10-28 10:26:29 +00003818 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003819 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003820 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003821 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003822 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003823
bellard3532fa72006-06-24 15:06:03 +00003824 if (msgp->msg_name) {
3825 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003826 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003827 ret = target_to_host_sockaddr(fd, msg.msg_name,
3828 tswapal(msgp->msg_name),
3829 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003830 if (ret == -TARGET_EFAULT) {
3831 /* For connected sockets msg_name and msg_namelen must
3832 * be ignored, so returning EFAULT immediately is wrong.
3833 * Instead, pass a bad msg_name to the host kernel, and
3834 * let it decide whether to return EFAULT or not.
3835 */
3836 msg.msg_name = (void *)-1;
3837 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003838 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003839 }
bellard3532fa72006-06-24 15:06:03 +00003840 } else {
3841 msg.msg_name = NULL;
3842 msg.msg_namelen = 0;
3843 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003844 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003845 msg.msg_control = alloca(msg.msg_controllen);
Jonas Schievink1d3d1b22018-07-12 00:12:44 +02003846 memset(msg.msg_control, 0, msg.msg_controllen);
3847
bellard3532fa72006-06-24 15:06:03 +00003848 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003849
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003850 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003851 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003852
3853 if (count > IOV_MAX) {
3854 /* sendrcvmsg returns a different errno for this condition than
3855 * readv/writev, so we must catch it here before lock_iovec() does.
3856 */
3857 ret = -TARGET_EMSGSIZE;
3858 goto out2;
3859 }
3860
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003861 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3862 target_vec, count, send);
3863 if (vec == NULL) {
3864 ret = -host_to_target_errno(errno);
3865 goto out2;
3866 }
bellard3532fa72006-06-24 15:06:03 +00003867 msg.msg_iovlen = count;
3868 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003869
bellard3532fa72006-06-24 15:06:03 +00003870 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003871 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003872 void *host_msg;
3873
3874 host_msg = g_malloc(msg.msg_iov->iov_len);
3875 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3876 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003877 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003878 if (ret >= 0) {
3879 msg.msg_iov->iov_base = host_msg;
3880 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3881 }
3882 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003883 } else {
3884 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003885 if (ret == 0) {
3886 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3887 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003888 }
bellard3532fa72006-06-24 15:06:03 +00003889 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003890 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003891 if (!is_error(ret)) {
3892 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003893 if (fd_trans_host_to_target_data(fd)) {
3894 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003895 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003896 } else {
3897 ret = host_to_target_cmsg(msgp, &msg);
3898 }
Jing Huangca619062012-07-24 13:58:02 +00003899 if (!is_error(ret)) {
3900 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003901 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003902 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3903 msg.msg_name, msg.msg_namelen);
3904 if (ret) {
3905 goto out;
3906 }
3907 }
3908
balrog6de645c2008-10-28 10:26:29 +00003909 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003910 }
balrog6de645c2008-10-28 10:26:29 +00003911 }
bellard3532fa72006-06-24 15:06:03 +00003912 }
Jing Huangca619062012-07-24 13:58:02 +00003913
3914out:
bellard3532fa72006-06-24 15:06:03 +00003915 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003916out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003917 return ret;
3918}
3919
3920static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3921 int flags, int send)
3922{
3923 abi_long ret;
3924 struct target_msghdr *msgp;
3925
3926 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3927 msgp,
3928 target_msg,
3929 send ? 1 : 0)) {
3930 return -TARGET_EFAULT;
3931 }
3932 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003933 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003934 return ret;
3935}
3936
Alexander Graff19e00d2014-03-02 19:36:42 +00003937/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3938 * so it might not have this *mmsg-specific flag either.
3939 */
3940#ifndef MSG_WAITFORONE
3941#define MSG_WAITFORONE 0x10000
3942#endif
3943
3944static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3945 unsigned int vlen, unsigned int flags,
3946 int send)
3947{
3948 struct target_mmsghdr *mmsgp;
3949 abi_long ret = 0;
3950 int i;
3951
3952 if (vlen > UIO_MAXIOV) {
3953 vlen = UIO_MAXIOV;
3954 }
3955
3956 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3957 if (!mmsgp) {
3958 return -TARGET_EFAULT;
3959 }
3960
3961 for (i = 0; i < vlen; i++) {
3962 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3963 if (is_error(ret)) {
3964 break;
3965 }
3966 mmsgp[i].msg_len = tswap32(ret);
3967 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3968 if (flags & MSG_WAITFORONE) {
3969 flags |= MSG_DONTWAIT;
3970 }
3971 }
3972
3973 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3974
3975 /* Return number of datagrams sent if we sent any at all;
3976 * otherwise return the error.
3977 */
3978 if (i) {
3979 return i;
3980 }
3981 return ret;
3982}
Alexander Graff19e00d2014-03-02 19:36:42 +00003983
Peter Maydella94b4982013-02-08 04:35:04 +00003984/* do_accept4() Must return target values and target errnos. */
3985static abi_long do_accept4(int fd, abi_ulong target_addr,
3986 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003987{
bellard2f619692007-11-16 10:46:05 +00003988 socklen_t addrlen;
3989 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003990 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003991 int host_flags;
3992
3993 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003994
Peter Maydella94b4982013-02-08 04:35:04 +00003995 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003996 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003997 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003998
3999 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00004000 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03004001 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00004002
Blue Swirl38724252010-09-18 05:53:14 +00004003 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004004 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004005 }
aurel328f7aeaf2009-01-30 19:47:57 +00004006
Arnaud Patard917507b2009-06-19 10:44:45 +03004007 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4008 return -TARGET_EINVAL;
4009
bellard2f619692007-11-16 10:46:05 +00004010 addr = alloca(addrlen);
4011
Peter Maydellff6dc132016-06-06 19:58:13 +01004012 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00004013 if (!is_error(ret)) {
4014 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004015 if (put_user_u32(addrlen, target_addrlen_addr))
4016 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004017 }
4018 return ret;
4019}
4020
ths0da46a62007-10-20 20:23:07 +00004021/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004022static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00004023 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004024{
bellard2f619692007-11-16 10:46:05 +00004025 socklen_t addrlen;
4026 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00004027 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004028
bellard2f619692007-11-16 10:46:05 +00004029 if (get_user_u32(addrlen, target_addrlen_addr))
4030 return -TARGET_EFAULT;
4031
Blue Swirl38724252010-09-18 05:53:14 +00004032 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004033 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004034 }
aurel328f7aeaf2009-01-30 19:47:57 +00004035
Arnaud Patard917507b2009-06-19 10:44:45 +03004036 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4037 return -TARGET_EFAULT;
4038
bellard2f619692007-11-16 10:46:05 +00004039 addr = alloca(addrlen);
4040
pbrook1be9e1d2006-11-19 15:26:04 +00004041 ret = get_errno(getpeername(fd, addr, &addrlen));
4042 if (!is_error(ret)) {
4043 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004044 if (put_user_u32(addrlen, target_addrlen_addr))
4045 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004046 }
4047 return ret;
4048}
4049
ths0da46a62007-10-20 20:23:07 +00004050/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004051static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00004052 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004053{
bellard2f619692007-11-16 10:46:05 +00004054 socklen_t addrlen;
4055 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00004056 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004057
bellard2f619692007-11-16 10:46:05 +00004058 if (get_user_u32(addrlen, target_addrlen_addr))
4059 return -TARGET_EFAULT;
4060
Blue Swirl38724252010-09-18 05:53:14 +00004061 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004062 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004063 }
aurel328f7aeaf2009-01-30 19:47:57 +00004064
Arnaud Patard917507b2009-06-19 10:44:45 +03004065 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4066 return -TARGET_EFAULT;
4067
bellard2f619692007-11-16 10:46:05 +00004068 addr = alloca(addrlen);
4069
pbrook1be9e1d2006-11-19 15:26:04 +00004070 ret = get_errno(getsockname(fd, addr, &addrlen));
4071 if (!is_error(ret)) {
4072 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004073 if (put_user_u32(addrlen, target_addrlen_addr))
4074 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004075 }
4076 return ret;
4077}
4078
ths0da46a62007-10-20 20:23:07 +00004079/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004080static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00004081 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004082{
4083 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00004084 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004085
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02004086 target_to_host_sock_type(&type);
4087
pbrook1be9e1d2006-11-19 15:26:04 +00004088 ret = get_errno(socketpair(domain, type, protocol, tab));
4089 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00004090 if (put_user_s32(tab[0], target_tab_addr)
4091 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
4092 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004093 }
4094 return ret;
4095}
4096
ths0da46a62007-10-20 20:23:07 +00004097/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004098static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
4099 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004100{
4101 void *addr;
4102 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02004103 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00004104 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004105
Blue Swirl38724252010-09-18 05:53:14 +00004106 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004107 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004108 }
aurel328f7aeaf2009-01-30 19:47:57 +00004109
bellard579a97f2007-11-11 14:26:47 +00004110 host_msg = lock_user(VERIFY_READ, msg, len, 1);
4111 if (!host_msg)
4112 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004113 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004114 copy_msg = host_msg;
4115 host_msg = g_malloc(len);
4116 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004117 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
4118 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004119 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004120 }
4121 }
pbrook1be9e1d2006-11-19 15:26:04 +00004122 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02004123 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01004124 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03004125 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004126 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03004127 }
Peter Maydell66687532016-06-06 19:58:04 +01004128 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004129 } else {
Peter Maydell66687532016-06-06 19:58:04 +01004130 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004131 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02004132fail:
4133 if (copy_msg) {
4134 g_free(host_msg);
4135 host_msg = copy_msg;
4136 }
pbrook1be9e1d2006-11-19 15:26:04 +00004137 unlock_user(host_msg, msg, 0);
4138 return ret;
4139}
4140
ths0da46a62007-10-20 20:23:07 +00004141/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004142static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4143 abi_ulong target_addr,
4144 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004145{
4146 socklen_t addrlen;
4147 void *addr;
4148 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004149 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004150
bellard579a97f2007-11-11 14:26:47 +00004151 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4152 if (!host_msg)
4153 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004154 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004155 if (get_user_u32(addrlen, target_addrlen)) {
4156 ret = -TARGET_EFAULT;
4157 goto fail;
4158 }
Blue Swirl38724252010-09-18 05:53:14 +00004159 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004160 ret = -TARGET_EINVAL;
4161 goto fail;
4162 }
pbrook1be9e1d2006-11-19 15:26:04 +00004163 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004164 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4165 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004166 } else {
4167 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004168 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004169 }
4170 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004171 if (fd_trans_host_to_target_data(fd)) {
4172 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4173 }
pbrook1be9e1d2006-11-19 15:26:04 +00004174 if (target_addr) {
4175 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004176 if (put_user_u32(addrlen, target_addrlen)) {
4177 ret = -TARGET_EFAULT;
4178 goto fail;
4179 }
pbrook1be9e1d2006-11-19 15:26:04 +00004180 }
4181 unlock_user(host_msg, msg, len);
4182 } else {
bellard2f619692007-11-16 10:46:05 +00004183fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004184 unlock_user(host_msg, msg, 0);
4185 }
4186 return ret;
4187}
4188
j_mayer32407102007-09-26 23:01:49 +00004189#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004190/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004191static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004192{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004193 static const unsigned nargs[] = { /* number of arguments per operation */
4194 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4195 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4196 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4197 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4198 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4199 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4200 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4201 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4202 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4203 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4204 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4205 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4206 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4207 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4208 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4209 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4210 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4211 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4212 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4213 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004214 };
4215 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004216 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004217
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004218 /* check the range of the first argument num */
4219 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4220 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4221 return -TARGET_EINVAL;
4222 }
4223 /* ensure we have space for args */
4224 if (nargs[num] > ARRAY_SIZE(a)) {
4225 return -TARGET_EINVAL;
4226 }
4227 /* collect the arguments in a[] according to nargs[] */
4228 for (i = 0; i < nargs[num]; ++i) {
4229 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4230 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004231 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004232 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004233 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004234 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004235 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004236 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004237 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004238 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004239 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004240 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004241 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004242 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004243 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004244 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004245 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004246 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004247 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004248 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004249 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004250 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004251 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004252 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004253 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004254 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004255 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004256 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004257 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004258 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004259 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004260 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004261 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004262 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004263 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004264 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004265 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4266 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4267 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4268 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4269 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4270 return do_accept4(a[0], a[1], a[2], a[3]);
4271 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4272 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4273 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4274 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004275 default:
4276 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004277 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004278 }
bellard31e31b82003-02-18 22:55:36 +00004279}
j_mayer32407102007-09-26 23:01:49 +00004280#endif
bellard31e31b82003-02-18 22:55:36 +00004281
bellard8853f862004-02-22 14:57:26 +00004282#define N_SHM_REGIONS 32
4283
4284static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004285 abi_ulong start;
4286 abi_ulong size;
4287 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004288} shm_regions[N_SHM_REGIONS];
4289
Peter Maydell005eb2a2016-07-15 16:50:47 +01004290#ifndef TARGET_SEMID64_DS
4291/* asm-generic version of this struct */
4292struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004293{
4294 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004295 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004296#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004297 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004298#endif
blueswir1992f48a2007-10-14 16:27:31 +00004299 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004300#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004301 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004302#endif
blueswir1992f48a2007-10-14 16:27:31 +00004303 abi_ulong sem_nsems;
4304 abi_ulong __unused3;
4305 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004306};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004307#endif
ths3eb6b042007-06-03 14:26:27 +00004308
bellard579a97f2007-11-11 14:26:47 +00004309static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4310 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004311{
4312 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004313 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004314
bellard579a97f2007-11-11 14:26:47 +00004315 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4316 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004317 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004318 host_ip->__key = tswap32(target_ip->__key);
4319 host_ip->uid = tswap32(target_ip->uid);
4320 host_ip->gid = tswap32(target_ip->gid);
4321 host_ip->cuid = tswap32(target_ip->cuid);
4322 host_ip->cgid = tswap32(target_ip->cgid);
4323#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4324 host_ip->mode = tswap32(target_ip->mode);
4325#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004326 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004327#endif
4328#if defined(TARGET_PPC)
4329 host_ip->__seq = tswap32(target_ip->__seq);
4330#else
4331 host_ip->__seq = tswap16(target_ip->__seq);
4332#endif
ths3eb6b042007-06-03 14:26:27 +00004333 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004334 return 0;
ths3eb6b042007-06-03 14:26:27 +00004335}
4336
bellard579a97f2007-11-11 14:26:47 +00004337static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4338 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004339{
4340 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004341 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004342
bellard579a97f2007-11-11 14:26:47 +00004343 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4344 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004345 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004346 target_ip->__key = tswap32(host_ip->__key);
4347 target_ip->uid = tswap32(host_ip->uid);
4348 target_ip->gid = tswap32(host_ip->gid);
4349 target_ip->cuid = tswap32(host_ip->cuid);
4350 target_ip->cgid = tswap32(host_ip->cgid);
4351#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4352 target_ip->mode = tswap32(host_ip->mode);
4353#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004354 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004355#endif
4356#if defined(TARGET_PPC)
4357 target_ip->__seq = tswap32(host_ip->__seq);
4358#else
4359 target_ip->__seq = tswap16(host_ip->__seq);
4360#endif
ths3eb6b042007-06-03 14:26:27 +00004361 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004362 return 0;
ths3eb6b042007-06-03 14:26:27 +00004363}
4364
bellard579a97f2007-11-11 14:26:47 +00004365static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4366 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004367{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004368 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004369
bellard579a97f2007-11-11 14:26:47 +00004370 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4371 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004372 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4373 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004374 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4375 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4376 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004377 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004378 return 0;
ths3eb6b042007-06-03 14:26:27 +00004379}
4380
bellard579a97f2007-11-11 14:26:47 +00004381static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4382 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004383{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004384 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004385
bellard579a97f2007-11-11 14:26:47 +00004386 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4387 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004388 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004389 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004390 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4391 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4392 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004393 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004394 return 0;
ths3eb6b042007-06-03 14:26:27 +00004395}
4396
aurel32e5289082009-04-18 16:16:12 +00004397struct target_seminfo {
4398 int semmap;
4399 int semmni;
4400 int semmns;
4401 int semmnu;
4402 int semmsl;
4403 int semopm;
4404 int semume;
4405 int semusz;
4406 int semvmx;
4407 int semaem;
4408};
4409
4410static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4411 struct seminfo *host_seminfo)
4412{
4413 struct target_seminfo *target_seminfo;
4414 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4415 return -TARGET_EFAULT;
4416 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4417 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4418 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4419 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4420 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4421 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4422 __put_user(host_seminfo->semume, &target_seminfo->semume);
4423 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4424 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4425 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4426 unlock_user_struct(target_seminfo, target_addr, 1);
4427 return 0;
4428}
4429
thsfa294812007-02-02 22:05:00 +00004430union semun {
4431 int val;
ths3eb6b042007-06-03 14:26:27 +00004432 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004433 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004434 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004435};
4436
ths3eb6b042007-06-03 14:26:27 +00004437union target_semun {
4438 int val;
aurel32e5289082009-04-18 16:16:12 +00004439 abi_ulong buf;
4440 abi_ulong array;
4441 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004442};
4443
aurel32e5289082009-04-18 16:16:12 +00004444static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4445 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004446{
aurel32e5289082009-04-18 16:16:12 +00004447 int nsems;
4448 unsigned short *array;
4449 union semun semun;
4450 struct semid_ds semid_ds;
4451 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004452
aurel32e5289082009-04-18 16:16:12 +00004453 semun.buf = &semid_ds;
4454
4455 ret = semctl(semid, 0, IPC_STAT, semun);
4456 if (ret == -1)
4457 return get_errno(ret);
4458
4459 nsems = semid_ds.sem_nsems;
4460
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304461 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004462 if (!*host_array) {
4463 return -TARGET_ENOMEM;
4464 }
aurel32e5289082009-04-18 16:16:12 +00004465 array = lock_user(VERIFY_READ, target_addr,
4466 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004467 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304468 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004469 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004470 }
aurel32e5289082009-04-18 16:16:12 +00004471
4472 for(i=0; i<nsems; i++) {
4473 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004474 }
aurel32e5289082009-04-18 16:16:12 +00004475 unlock_user(array, target_addr, 0);
4476
bellard579a97f2007-11-11 14:26:47 +00004477 return 0;
ths3eb6b042007-06-03 14:26:27 +00004478}
4479
aurel32e5289082009-04-18 16:16:12 +00004480static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4481 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004482{
aurel32e5289082009-04-18 16:16:12 +00004483 int nsems;
4484 unsigned short *array;
4485 union semun semun;
4486 struct semid_ds semid_ds;
4487 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004488
aurel32e5289082009-04-18 16:16:12 +00004489 semun.buf = &semid_ds;
4490
4491 ret = semctl(semid, 0, IPC_STAT, semun);
4492 if (ret == -1)
4493 return get_errno(ret);
4494
4495 nsems = semid_ds.sem_nsems;
4496
4497 array = lock_user(VERIFY_WRITE, target_addr,
4498 nsems*sizeof(unsigned short), 0);
4499 if (!array)
4500 return -TARGET_EFAULT;
4501
4502 for(i=0; i<nsems; i++) {
4503 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004504 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304505 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004506 unlock_user(array, target_addr, 1);
4507
bellard579a97f2007-11-11 14:26:47 +00004508 return 0;
ths3eb6b042007-06-03 14:26:27 +00004509}
4510
aurel32e5289082009-04-18 16:16:12 +00004511static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004512 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004513{
Stefan Weild1c002b2015-02-08 15:40:58 +01004514 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004515 union semun arg;
4516 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304517 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004518 struct seminfo seminfo;
4519 abi_long ret = -TARGET_EINVAL;
4520 abi_long err;
4521 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004522
4523 switch( cmd ) {
4524 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004525 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004526 /* In 64 bit cross-endian situations, we will erroneously pick up
4527 * the wrong half of the union for the "val" element. To rectify
4528 * this, the entire 8-byte structure is byteswapped, followed by
4529 * a swap of the 4 byte val field. In other cases, the data is
4530 * already in proper host byte order. */
4531 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4532 target_su.buf = tswapal(target_su.buf);
4533 arg.val = tswap32(target_su.val);
4534 } else {
4535 arg.val = target_su.val;
4536 }
aurel32e5289082009-04-18 16:16:12 +00004537 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004538 break;
4539 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004540 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004541 err = target_to_host_semarray(semid, &array, target_su.array);
4542 if (err)
4543 return err;
4544 arg.array = array;
4545 ret = get_errno(semctl(semid, semnum, cmd, arg));
4546 err = host_to_target_semarray(semid, target_su.array, &array);
4547 if (err)
4548 return err;
ths3eb6b042007-06-03 14:26:27 +00004549 break;
4550 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004551 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004552 case SEM_STAT:
4553 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4554 if (err)
4555 return err;
4556 arg.buf = &dsarg;
4557 ret = get_errno(semctl(semid, semnum, cmd, arg));
4558 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4559 if (err)
4560 return err;
ths3eb6b042007-06-03 14:26:27 +00004561 break;
aurel32e5289082009-04-18 16:16:12 +00004562 case IPC_INFO:
4563 case SEM_INFO:
4564 arg.__buf = &seminfo;
4565 ret = get_errno(semctl(semid, semnum, cmd, arg));
4566 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4567 if (err)
4568 return err;
4569 break;
4570 case IPC_RMID:
4571 case GETPID:
4572 case GETNCNT:
4573 case GETZCNT:
4574 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4575 break;
ths3eb6b042007-06-03 14:26:27 +00004576 }
4577
4578 return ret;
4579}
4580
aurel32e5289082009-04-18 16:16:12 +00004581struct target_sembuf {
4582 unsigned short sem_num;
4583 short sem_op;
4584 short sem_flg;
4585};
4586
4587static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4588 abi_ulong target_addr,
4589 unsigned nsops)
4590{
4591 struct target_sembuf *target_sembuf;
4592 int i;
4593
4594 target_sembuf = lock_user(VERIFY_READ, target_addr,
4595 nsops*sizeof(struct target_sembuf), 1);
4596 if (!target_sembuf)
4597 return -TARGET_EFAULT;
4598
4599 for(i=0; i<nsops; i++) {
4600 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4601 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4602 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4603 }
4604
4605 unlock_user(target_sembuf, target_addr, 0);
4606
4607 return 0;
4608}
4609
4610static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4611{
4612 struct sembuf sops[nsops];
4613
4614 if (target_to_host_sembuf(sops, ptr, nsops))
4615 return -TARGET_EFAULT;
4616
Peter Maydellffb7ee72016-06-06 19:58:12 +01004617 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004618}
4619
ths1bc012f2007-06-03 14:27:49 +00004620struct target_msqid_ds
4621{
aurel321c54ff92008-10-13 21:08:44 +00004622 struct target_ipc_perm msg_perm;
4623 abi_ulong msg_stime;
4624#if TARGET_ABI_BITS == 32
4625 abi_ulong __unused1;
4626#endif
4627 abi_ulong msg_rtime;
4628#if TARGET_ABI_BITS == 32
4629 abi_ulong __unused2;
4630#endif
4631 abi_ulong msg_ctime;
4632#if TARGET_ABI_BITS == 32
4633 abi_ulong __unused3;
4634#endif
4635 abi_ulong __msg_cbytes;
4636 abi_ulong msg_qnum;
4637 abi_ulong msg_qbytes;
4638 abi_ulong msg_lspid;
4639 abi_ulong msg_lrpid;
4640 abi_ulong __unused4;
4641 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004642};
4643
bellard579a97f2007-11-11 14:26:47 +00004644static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4645 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004646{
4647 struct target_msqid_ds *target_md;
4648
bellard579a97f2007-11-11 14:26:47 +00004649 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4650 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004651 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4652 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004653 host_md->msg_stime = tswapal(target_md->msg_stime);
4654 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4655 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4656 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4657 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4658 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4659 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4660 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004661 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004662 return 0;
ths1bc012f2007-06-03 14:27:49 +00004663}
4664
bellard579a97f2007-11-11 14:26:47 +00004665static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4666 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004667{
4668 struct target_msqid_ds *target_md;
4669
bellard579a97f2007-11-11 14:26:47 +00004670 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4671 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004672 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4673 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004674 target_md->msg_stime = tswapal(host_md->msg_stime);
4675 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4676 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4677 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4678 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4679 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4680 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4681 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004682 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004683 return 0;
ths1bc012f2007-06-03 14:27:49 +00004684}
4685
aurel321c54ff92008-10-13 21:08:44 +00004686struct target_msginfo {
4687 int msgpool;
4688 int msgmap;
4689 int msgmax;
4690 int msgmnb;
4691 int msgmni;
4692 int msgssz;
4693 int msgtql;
4694 unsigned short int msgseg;
4695};
4696
4697static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4698 struct msginfo *host_msginfo)
4699{
4700 struct target_msginfo *target_msginfo;
4701 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4702 return -TARGET_EFAULT;
4703 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4704 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4705 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4706 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4707 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4708 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4709 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4710 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4711 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004712 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004713}
4714
4715static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004716{
4717 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004718 struct msginfo msginfo;
4719 abi_long ret = -TARGET_EINVAL;
4720
4721 cmd &= 0xff;
4722
4723 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004724 case IPC_STAT:
4725 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004726 case MSG_STAT:
4727 if (target_to_host_msqid_ds(&dsarg,ptr))
4728 return -TARGET_EFAULT;
4729 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4730 if (host_to_target_msqid_ds(ptr,&dsarg))
4731 return -TARGET_EFAULT;
4732 break;
4733 case IPC_RMID:
4734 ret = get_errno(msgctl(msgid, cmd, NULL));
4735 break;
4736 case IPC_INFO:
4737 case MSG_INFO:
4738 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4739 if (host_to_target_msginfo(ptr, &msginfo))
4740 return -TARGET_EFAULT;
4741 break;
ths1bc012f2007-06-03 14:27:49 +00004742 }
aurel321c54ff92008-10-13 21:08:44 +00004743
ths1bc012f2007-06-03 14:27:49 +00004744 return ret;
4745}
4746
4747struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004748 abi_long mtype;
4749 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004750};
4751
blueswir1992f48a2007-10-14 16:27:31 +00004752static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004753 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004754{
4755 struct target_msgbuf *target_mb;
4756 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004757 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004758
Tom Mustaedcc5f92014-08-12 13:53:37 -05004759 if (msgsz < 0) {
4760 return -TARGET_EINVAL;
4761 }
4762
bellard579a97f2007-11-11 14:26:47 +00004763 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4764 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304765 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004766 if (!host_mb) {
4767 unlock_user_struct(target_mb, msgp, 0);
4768 return -TARGET_ENOMEM;
4769 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004770 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004771 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004772 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304773 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004774 unlock_user_struct(target_mb, msgp, 0);
4775
4776 return ret;
4777}
4778
blueswir1992f48a2007-10-14 16:27:31 +00004779static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004780 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004781 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004782{
4783 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004784 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004785 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004786 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004787
Peter Maydell99874f62016-05-20 19:00:56 +01004788 if (msgsz < 0) {
4789 return -TARGET_EINVAL;
4790 }
4791
bellard579a97f2007-11-11 14:26:47 +00004792 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4793 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004794
Peter Maydell415d8472016-05-20 19:00:57 +01004795 host_mb = g_try_malloc(msgsz + sizeof(long));
4796 if (!host_mb) {
4797 ret = -TARGET_ENOMEM;
4798 goto end;
4799 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004800 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004801
bellard579a97f2007-11-11 14:26:47 +00004802 if (ret > 0) {
4803 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4804 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4805 if (!target_mtext) {
4806 ret = -TARGET_EFAULT;
4807 goto end;
4808 }
aurel321c54ff92008-10-13 21:08:44 +00004809 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004810 unlock_user(target_mtext, target_mtext_addr, ret);
4811 }
aurel321c54ff92008-10-13 21:08:44 +00004812
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004813 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004814
bellard579a97f2007-11-11 14:26:47 +00004815end:
4816 if (target_mb)
4817 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004818 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004819 return ret;
4820}
4821
Riku Voipio88a8c982009-04-03 10:42:00 +03004822static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4823 abi_ulong target_addr)
4824{
4825 struct target_shmid_ds *target_sd;
4826
4827 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4828 return -TARGET_EFAULT;
4829 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4830 return -TARGET_EFAULT;
4831 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4832 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4833 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4834 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4835 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4836 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4837 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4838 unlock_user_struct(target_sd, target_addr, 0);
4839 return 0;
4840}
4841
4842static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4843 struct shmid_ds *host_sd)
4844{
4845 struct target_shmid_ds *target_sd;
4846
4847 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4848 return -TARGET_EFAULT;
4849 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4850 return -TARGET_EFAULT;
4851 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4852 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4853 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4854 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4855 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4856 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4857 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4858 unlock_user_struct(target_sd, target_addr, 1);
4859 return 0;
4860}
4861
4862struct target_shminfo {
4863 abi_ulong shmmax;
4864 abi_ulong shmmin;
4865 abi_ulong shmmni;
4866 abi_ulong shmseg;
4867 abi_ulong shmall;
4868};
4869
4870static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4871 struct shminfo *host_shminfo)
4872{
4873 struct target_shminfo *target_shminfo;
4874 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4875 return -TARGET_EFAULT;
4876 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4877 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4878 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4879 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4880 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4881 unlock_user_struct(target_shminfo, target_addr, 1);
4882 return 0;
4883}
4884
4885struct target_shm_info {
4886 int used_ids;
4887 abi_ulong shm_tot;
4888 abi_ulong shm_rss;
4889 abi_ulong shm_swp;
4890 abi_ulong swap_attempts;
4891 abi_ulong swap_successes;
4892};
4893
4894static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4895 struct shm_info *host_shm_info)
4896{
4897 struct target_shm_info *target_shm_info;
4898 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4899 return -TARGET_EFAULT;
4900 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4901 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4902 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4903 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4904 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4905 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4906 unlock_user_struct(target_shm_info, target_addr, 1);
4907 return 0;
4908}
4909
4910static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4911{
4912 struct shmid_ds dsarg;
4913 struct shminfo shminfo;
4914 struct shm_info shm_info;
4915 abi_long ret = -TARGET_EINVAL;
4916
4917 cmd &= 0xff;
4918
4919 switch(cmd) {
4920 case IPC_STAT:
4921 case IPC_SET:
4922 case SHM_STAT:
4923 if (target_to_host_shmid_ds(&dsarg, buf))
4924 return -TARGET_EFAULT;
4925 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4926 if (host_to_target_shmid_ds(buf, &dsarg))
4927 return -TARGET_EFAULT;
4928 break;
4929 case IPC_INFO:
4930 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4931 if (host_to_target_shminfo(buf, &shminfo))
4932 return -TARGET_EFAULT;
4933 break;
4934 case SHM_INFO:
4935 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4936 if (host_to_target_shm_info(buf, &shm_info))
4937 return -TARGET_EFAULT;
4938 break;
4939 case IPC_RMID:
4940 case SHM_LOCK:
4941 case SHM_UNLOCK:
4942 ret = get_errno(shmctl(shmid, cmd, NULL));
4943 break;
4944 }
4945
4946 return ret;
4947}
4948
Peter Maydellee8e7612016-07-11 16:48:11 +01004949#ifndef TARGET_FORCE_SHMLBA
4950/* For most architectures, SHMLBA is the same as the page size;
4951 * some architectures have larger values, in which case they should
4952 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4953 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4954 * and defining its own value for SHMLBA.
4955 *
4956 * The kernel also permits SHMLBA to be set by the architecture to a
4957 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4958 * this means that addresses are rounded to the large size if
4959 * SHM_RND is set but addresses not aligned to that size are not rejected
4960 * as long as they are at least page-aligned. Since the only architecture
4961 * which uses this is ia64 this code doesn't provide for that oddity.
4962 */
4963static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4964{
4965 return TARGET_PAGE_SIZE;
4966}
4967#endif
4968
4969static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4970 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004971{
4972 abi_long raddr;
4973 void *host_raddr;
4974 struct shmid_ds shm_info;
4975 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004976 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004977
4978 /* find out the length of the shared memory segment */
4979 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4980 if (is_error(ret)) {
4981 /* can't get length, bail out */
4982 return ret;
4983 }
4984
Peter Maydellee8e7612016-07-11 16:48:11 +01004985 shmlba = target_shmlba(cpu_env);
4986
4987 if (shmaddr & (shmlba - 1)) {
4988 if (shmflg & SHM_RND) {
4989 shmaddr &= ~(shmlba - 1);
4990 } else {
4991 return -TARGET_EINVAL;
4992 }
4993 }
Max Filippovebf9a362018-03-07 13:50:10 -08004994 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
4995 return -TARGET_EINVAL;
4996 }
Peter Maydellee8e7612016-07-11 16:48:11 +01004997
Riku Voipio88a8c982009-04-03 10:42:00 +03004998 mmap_lock();
4999
5000 if (shmaddr)
5001 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
5002 else {
5003 abi_ulong mmap_start;
5004
5005 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
5006
5007 if (mmap_start == -1) {
5008 errno = ENOMEM;
5009 host_raddr = (void *)-1;
5010 } else
5011 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
5012 }
5013
5014 if (host_raddr == (void *)-1) {
5015 mmap_unlock();
5016 return get_errno((long)host_raddr);
5017 }
5018 raddr=h2g((unsigned long)host_raddr);
5019
5020 page_set_flags(raddr, raddr + shm_info.shm_segsz,
5021 PAGE_VALID | PAGE_READ |
5022 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
5023
5024 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00005025 if (!shm_regions[i].in_use) {
5026 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03005027 shm_regions[i].start = raddr;
5028 shm_regions[i].size = shm_info.shm_segsz;
5029 break;
5030 }
5031 }
5032
5033 mmap_unlock();
5034 return raddr;
5035
5036}
5037
5038static inline abi_long do_shmdt(abi_ulong shmaddr)
5039{
5040 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08005041 abi_long rv;
5042
5043 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03005044
5045 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00005046 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
5047 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09005048 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03005049 break;
5050 }
5051 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08005052 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03005053
Max Filippov3c5f6a52018-02-28 14:16:04 -08005054 mmap_unlock();
5055
5056 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03005057}
5058
aurel321c54ff92008-10-13 21:08:44 +00005059#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00005060/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00005061/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01005062static abi_long do_ipc(CPUArchState *cpu_env,
5063 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05005064 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00005065 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00005066{
5067 int version;
blueswir1992f48a2007-10-14 16:27:31 +00005068 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00005069
5070 version = call >> 16;
5071 call &= 0xffff;
5072
5073 switch (call) {
thsfa294812007-02-02 22:05:00 +00005074 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00005075 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00005076 break;
5077
5078 case IPCOP_semget:
5079 ret = get_errno(semget(first, second, third));
5080 break;
5081
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005082 case IPCOP_semctl: {
5083 /* The semun argument to semctl is passed by value, so dereference the
5084 * ptr argument. */
5085 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05005086 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01005087 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00005088 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005089 }
thsd96372e2007-02-02 22:05:44 +00005090
aurel321c54ff92008-10-13 21:08:44 +00005091 case IPCOP_msgget:
5092 ret = get_errno(msgget(first, second));
5093 break;
thsd96372e2007-02-02 22:05:44 +00005094
aurel321c54ff92008-10-13 21:08:44 +00005095 case IPCOP_msgsnd:
5096 ret = do_msgsnd(first, ptr, second, third);
5097 break;
thsd96372e2007-02-02 22:05:44 +00005098
aurel321c54ff92008-10-13 21:08:44 +00005099 case IPCOP_msgctl:
5100 ret = do_msgctl(first, second, ptr);
5101 break;
thsd96372e2007-02-02 22:05:44 +00005102
aurel321c54ff92008-10-13 21:08:44 +00005103 case IPCOP_msgrcv:
5104 switch (version) {
5105 case 0:
5106 {
5107 struct target_ipc_kludge {
5108 abi_long msgp;
5109 abi_long msgtyp;
5110 } *tmp;
thsd96372e2007-02-02 22:05:44 +00005111
aurel321c54ff92008-10-13 21:08:44 +00005112 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
5113 ret = -TARGET_EFAULT;
5114 break;
ths1bc012f2007-06-03 14:27:49 +00005115 }
aurel321c54ff92008-10-13 21:08:44 +00005116
Laurent Vivier79dd77d2012-12-20 11:00:11 +00005117 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00005118
5119 unlock_user_struct(tmp, ptr, 0);
5120 break;
5121 }
5122 default:
5123 ret = do_msgrcv(first, ptr, second, fifth, third);
5124 }
5125 break;
thsd96372e2007-02-02 22:05:44 +00005126
bellard8853f862004-02-22 14:57:26 +00005127 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03005128 switch (version) {
5129 default:
bellard5a4a8982007-11-11 17:39:18 +00005130 {
5131 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01005132 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03005133 if (is_error(raddr))
5134 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00005135 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00005136 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03005137 break;
5138 }
5139 case 1:
5140 ret = -TARGET_EINVAL;
5141 break;
bellard5a4a8982007-11-11 17:39:18 +00005142 }
bellard8853f862004-02-22 14:57:26 +00005143 break;
5144 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03005145 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00005146 break;
5147
5148 case IPCOP_shmget:
5149 /* IPC_* flag values are the same on all linux platforms */
5150 ret = get_errno(shmget(first, second, third));
5151 break;
5152
5153 /* IPC_* and SHM_* command values are the same on all linux platforms */
5154 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005155 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005156 break;
5157 default:
j_mayer32407102007-09-26 23:01:49 +00005158 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005159 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005160 break;
5161 }
5162 return ret;
5163}
j_mayer32407102007-09-26 23:01:49 +00005164#endif
bellard8853f862004-02-22 14:57:26 +00005165
bellard31e31b82003-02-18 22:55:36 +00005166/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005167
Blue Swirl001faf32009-05-13 17:53:17 +00005168#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005169#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5170enum {
5171#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005172STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005173};
5174#undef STRUCT
5175#undef STRUCT_SPECIAL
5176
Blue Swirl001faf32009-05-13 17:53:17 +00005177#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005178#define STRUCT_SPECIAL(name)
5179#include "syscall_types.h"
5180#undef STRUCT
5181#undef STRUCT_SPECIAL
5182
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005183typedef struct IOCTLEntry IOCTLEntry;
5184
5185typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005186 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005187
5188struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005189 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005190 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005191 const char *name;
5192 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005193 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005194 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005195};
bellard31e31b82003-02-18 22:55:36 +00005196
5197#define IOC_R 0x0001
5198#define IOC_W 0x0002
5199#define IOC_RW (IOC_R | IOC_W)
5200
5201#define MAX_STRUCT_SIZE 4096
5202
Peter Maydelldace20d2011-01-10 13:11:24 +00005203#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005204/* So fiemap access checks don't overflow on 32 bit systems.
5205 * This is very slightly smaller than the limit imposed by
5206 * the underlying kernel.
5207 */
5208#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5209 / sizeof(struct fiemap_extent))
5210
5211static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005212 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005213{
5214 /* The parameter for this ioctl is a struct fiemap followed
5215 * by an array of struct fiemap_extent whose size is set
5216 * in fiemap->fm_extent_count. The array is filled in by the
5217 * ioctl.
5218 */
5219 int target_size_in, target_size_out;
5220 struct fiemap *fm;
5221 const argtype *arg_type = ie->arg_type;
5222 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5223 void *argptr, *p;
5224 abi_long ret;
5225 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5226 uint32_t outbufsz;
5227 int free_fm = 0;
5228
5229 assert(arg_type[0] == TYPE_PTR);
5230 assert(ie->access == IOC_RW);
5231 arg_type++;
5232 target_size_in = thunk_type_size(arg_type, 0);
5233 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5234 if (!argptr) {
5235 return -TARGET_EFAULT;
5236 }
5237 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5238 unlock_user(argptr, arg, 0);
5239 fm = (struct fiemap *)buf_temp;
5240 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5241 return -TARGET_EINVAL;
5242 }
5243
5244 outbufsz = sizeof (*fm) +
5245 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5246
5247 if (outbufsz > MAX_STRUCT_SIZE) {
5248 /* We can't fit all the extents into the fixed size buffer.
5249 * Allocate one that is large enough and use it instead.
5250 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305251 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005252 if (!fm) {
5253 return -TARGET_ENOMEM;
5254 }
5255 memcpy(fm, buf_temp, sizeof(struct fiemap));
5256 free_fm = 1;
5257 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005258 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005259 if (!is_error(ret)) {
5260 target_size_out = target_size_in;
5261 /* An extent_count of 0 means we were only counting the extents
5262 * so there are no structs to copy
5263 */
5264 if (fm->fm_extent_count != 0) {
5265 target_size_out += fm->fm_mapped_extents * extent_size;
5266 }
5267 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5268 if (!argptr) {
5269 ret = -TARGET_EFAULT;
5270 } else {
5271 /* Convert the struct fiemap */
5272 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5273 if (fm->fm_extent_count != 0) {
5274 p = argptr + target_size_in;
5275 /* ...and then all the struct fiemap_extents */
5276 for (i = 0; i < fm->fm_mapped_extents; i++) {
5277 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5278 THUNK_TARGET);
5279 p += extent_size;
5280 }
5281 }
5282 unlock_user(argptr, arg, target_size_out);
5283 }
5284 }
5285 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305286 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005287 }
5288 return ret;
5289}
Peter Maydelldace20d2011-01-10 13:11:24 +00005290#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005291
Laurent Vivier059c2f22011-03-30 00:12:12 +02005292static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005293 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005294{
5295 const argtype *arg_type = ie->arg_type;
5296 int target_size;
5297 void *argptr;
5298 int ret;
5299 struct ifconf *host_ifconf;
5300 uint32_t outbufsz;
5301 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5302 int target_ifreq_size;
5303 int nb_ifreq;
5304 int free_buf = 0;
5305 int i;
5306 int target_ifc_len;
5307 abi_long target_ifc_buf;
5308 int host_ifc_len;
5309 char *host_ifc_buf;
5310
5311 assert(arg_type[0] == TYPE_PTR);
5312 assert(ie->access == IOC_RW);
5313
5314 arg_type++;
5315 target_size = thunk_type_size(arg_type, 0);
5316
5317 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5318 if (!argptr)
5319 return -TARGET_EFAULT;
5320 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5321 unlock_user(argptr, arg, 0);
5322
5323 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5324 target_ifc_len = host_ifconf->ifc_len;
5325 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5326
5327 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5328 nb_ifreq = target_ifc_len / target_ifreq_size;
5329 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5330
5331 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5332 if (outbufsz > MAX_STRUCT_SIZE) {
5333 /* We can't fit all the extents into the fixed size buffer.
5334 * Allocate one that is large enough and use it instead.
5335 */
5336 host_ifconf = malloc(outbufsz);
5337 if (!host_ifconf) {
5338 return -TARGET_ENOMEM;
5339 }
5340 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5341 free_buf = 1;
5342 }
5343 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5344
5345 host_ifconf->ifc_len = host_ifc_len;
5346 host_ifconf->ifc_buf = host_ifc_buf;
5347
Peter Maydell49ca6f32016-06-06 19:58:14 +01005348 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005349 if (!is_error(ret)) {
5350 /* convert host ifc_len to target ifc_len */
5351
5352 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5353 target_ifc_len = nb_ifreq * target_ifreq_size;
5354 host_ifconf->ifc_len = target_ifc_len;
5355
5356 /* restore target ifc_buf */
5357
5358 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5359
5360 /* copy struct ifconf to target user */
5361
5362 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5363 if (!argptr)
5364 return -TARGET_EFAULT;
5365 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5366 unlock_user(argptr, arg, target_size);
5367
5368 /* copy ifreq[] to target user */
5369
5370 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5371 for (i = 0; i < nb_ifreq ; i++) {
5372 thunk_convert(argptr + i * target_ifreq_size,
5373 host_ifc_buf + i * sizeof(struct ifreq),
5374 ifreq_arg_type, THUNK_TARGET);
5375 }
5376 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5377 }
5378
5379 if (free_buf) {
5380 free(host_ifconf);
5381 }
5382
5383 return ret;
5384}
5385
Alexander Graf56e904e2012-01-31 18:42:06 +01005386static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005387 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005388{
5389 void *argptr;
5390 struct dm_ioctl *host_dm;
5391 abi_long guest_data;
5392 uint32_t guest_data_size;
5393 int target_size;
5394 const argtype *arg_type = ie->arg_type;
5395 abi_long ret;
5396 void *big_buf = NULL;
5397 char *host_data;
5398
5399 arg_type++;
5400 target_size = thunk_type_size(arg_type, 0);
5401 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5402 if (!argptr) {
5403 ret = -TARGET_EFAULT;
5404 goto out;
5405 }
5406 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5407 unlock_user(argptr, arg, 0);
5408
5409 /* buf_temp is too small, so fetch things into a bigger buffer */
5410 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5411 memcpy(big_buf, buf_temp, target_size);
5412 buf_temp = big_buf;
5413 host_dm = big_buf;
5414
5415 guest_data = arg + host_dm->data_start;
5416 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005417 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005418 goto out;
5419 }
5420 guest_data_size = host_dm->data_size - host_dm->data_start;
5421 host_data = (char*)host_dm + host_dm->data_start;
5422
5423 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005424 if (!argptr) {
5425 ret = -TARGET_EFAULT;
5426 goto out;
5427 }
5428
Alexander Graf56e904e2012-01-31 18:42:06 +01005429 switch (ie->host_cmd) {
5430 case DM_REMOVE_ALL:
5431 case DM_LIST_DEVICES:
5432 case DM_DEV_CREATE:
5433 case DM_DEV_REMOVE:
5434 case DM_DEV_SUSPEND:
5435 case DM_DEV_STATUS:
5436 case DM_DEV_WAIT:
5437 case DM_TABLE_STATUS:
5438 case DM_TABLE_CLEAR:
5439 case DM_TABLE_DEPS:
5440 case DM_LIST_VERSIONS:
5441 /* no input data */
5442 break;
5443 case DM_DEV_RENAME:
5444 case DM_DEV_SET_GEOMETRY:
5445 /* data contains only strings */
5446 memcpy(host_data, argptr, guest_data_size);
5447 break;
5448 case DM_TARGET_MSG:
5449 memcpy(host_data, argptr, guest_data_size);
5450 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5451 break;
5452 case DM_TABLE_LOAD:
5453 {
5454 void *gspec = argptr;
5455 void *cur_data = host_data;
5456 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5457 int spec_size = thunk_type_size(arg_type, 0);
5458 int i;
5459
5460 for (i = 0; i < host_dm->target_count; i++) {
5461 struct dm_target_spec *spec = cur_data;
5462 uint32_t next;
5463 int slen;
5464
5465 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5466 slen = strlen((char*)gspec + spec_size) + 1;
5467 next = spec->next;
5468 spec->next = sizeof(*spec) + slen;
5469 strcpy((char*)&spec[1], gspec + spec_size);
5470 gspec += next;
5471 cur_data += spec->next;
5472 }
5473 break;
5474 }
5475 default:
5476 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005477 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005478 goto out;
5479 }
5480 unlock_user(argptr, guest_data, 0);
5481
Peter Maydell49ca6f32016-06-06 19:58:14 +01005482 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005483 if (!is_error(ret)) {
5484 guest_data = arg + host_dm->data_start;
5485 guest_data_size = host_dm->data_size - host_dm->data_start;
5486 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5487 switch (ie->host_cmd) {
5488 case DM_REMOVE_ALL:
5489 case DM_DEV_CREATE:
5490 case DM_DEV_REMOVE:
5491 case DM_DEV_RENAME:
5492 case DM_DEV_SUSPEND:
5493 case DM_DEV_STATUS:
5494 case DM_TABLE_LOAD:
5495 case DM_TABLE_CLEAR:
5496 case DM_TARGET_MSG:
5497 case DM_DEV_SET_GEOMETRY:
5498 /* no return data */
5499 break;
5500 case DM_LIST_DEVICES:
5501 {
5502 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5503 uint32_t remaining_data = guest_data_size;
5504 void *cur_data = argptr;
5505 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5506 int nl_size = 12; /* can't use thunk_size due to alignment */
5507
5508 while (1) {
5509 uint32_t next = nl->next;
5510 if (next) {
5511 nl->next = nl_size + (strlen(nl->name) + 1);
5512 }
5513 if (remaining_data < nl->next) {
5514 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5515 break;
5516 }
5517 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5518 strcpy(cur_data + nl_size, nl->name);
5519 cur_data += nl->next;
5520 remaining_data -= nl->next;
5521 if (!next) {
5522 break;
5523 }
5524 nl = (void*)nl + next;
5525 }
5526 break;
5527 }
5528 case DM_DEV_WAIT:
5529 case DM_TABLE_STATUS:
5530 {
5531 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5532 void *cur_data = argptr;
5533 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5534 int spec_size = thunk_type_size(arg_type, 0);
5535 int i;
5536
5537 for (i = 0; i < host_dm->target_count; i++) {
5538 uint32_t next = spec->next;
5539 int slen = strlen((char*)&spec[1]) + 1;
5540 spec->next = (cur_data - argptr) + spec_size + slen;
5541 if (guest_data_size < spec->next) {
5542 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5543 break;
5544 }
5545 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5546 strcpy(cur_data + spec_size, (char*)&spec[1]);
5547 cur_data = argptr + spec->next;
5548 spec = (void*)host_dm + host_dm->data_start + next;
5549 }
5550 break;
5551 }
5552 case DM_TABLE_DEPS:
5553 {
5554 void *hdata = (void*)host_dm + host_dm->data_start;
5555 int count = *(uint32_t*)hdata;
5556 uint64_t *hdev = hdata + 8;
5557 uint64_t *gdev = argptr + 8;
5558 int i;
5559
5560 *(uint32_t*)argptr = tswap32(count);
5561 for (i = 0; i < count; i++) {
5562 *gdev = tswap64(*hdev);
5563 gdev++;
5564 hdev++;
5565 }
5566 break;
5567 }
5568 case DM_LIST_VERSIONS:
5569 {
5570 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5571 uint32_t remaining_data = guest_data_size;
5572 void *cur_data = argptr;
5573 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5574 int vers_size = thunk_type_size(arg_type, 0);
5575
5576 while (1) {
5577 uint32_t next = vers->next;
5578 if (next) {
5579 vers->next = vers_size + (strlen(vers->name) + 1);
5580 }
5581 if (remaining_data < vers->next) {
5582 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5583 break;
5584 }
5585 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5586 strcpy(cur_data + vers_size, vers->name);
5587 cur_data += vers->next;
5588 remaining_data -= vers->next;
5589 if (!next) {
5590 break;
5591 }
5592 vers = (void*)vers + next;
5593 }
5594 break;
5595 }
5596 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005597 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005598 ret = -TARGET_EINVAL;
5599 goto out;
5600 }
5601 unlock_user(argptr, guest_data, guest_data_size);
5602
5603 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5604 if (!argptr) {
5605 ret = -TARGET_EFAULT;
5606 goto out;
5607 }
5608 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5609 unlock_user(argptr, arg, target_size);
5610 }
5611out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005612 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005613 return ret;
5614}
5615
Alexander Grafa59b5e32014-08-22 13:15:50 +02005616static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005617 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005618{
5619 void *argptr;
5620 int target_size;
5621 const argtype *arg_type = ie->arg_type;
5622 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5623 abi_long ret;
5624
5625 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5626 struct blkpg_partition host_part;
5627
5628 /* Read and convert blkpg */
5629 arg_type++;
5630 target_size = thunk_type_size(arg_type, 0);
5631 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5632 if (!argptr) {
5633 ret = -TARGET_EFAULT;
5634 goto out;
5635 }
5636 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5637 unlock_user(argptr, arg, 0);
5638
5639 switch (host_blkpg->op) {
5640 case BLKPG_ADD_PARTITION:
5641 case BLKPG_DEL_PARTITION:
5642 /* payload is struct blkpg_partition */
5643 break;
5644 default:
5645 /* Unknown opcode */
5646 ret = -TARGET_EINVAL;
5647 goto out;
5648 }
5649
5650 /* Read and convert blkpg->data */
5651 arg = (abi_long)(uintptr_t)host_blkpg->data;
5652 target_size = thunk_type_size(part_arg_type, 0);
5653 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5654 if (!argptr) {
5655 ret = -TARGET_EFAULT;
5656 goto out;
5657 }
5658 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5659 unlock_user(argptr, arg, 0);
5660
5661 /* Swizzle the data pointer to our local copy and call! */
5662 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005663 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005664
5665out:
5666 return ret;
5667}
5668
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005669static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005670 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005671{
5672 const argtype *arg_type = ie->arg_type;
5673 const StructEntry *se;
5674 const argtype *field_types;
5675 const int *dst_offsets, *src_offsets;
5676 int target_size;
5677 void *argptr;
5678 abi_ulong *target_rt_dev_ptr;
5679 unsigned long *host_rt_dev_ptr;
5680 abi_long ret;
5681 int i;
5682
5683 assert(ie->access == IOC_W);
5684 assert(*arg_type == TYPE_PTR);
5685 arg_type++;
5686 assert(*arg_type == TYPE_STRUCT);
5687 target_size = thunk_type_size(arg_type, 0);
5688 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5689 if (!argptr) {
5690 return -TARGET_EFAULT;
5691 }
5692 arg_type++;
5693 assert(*arg_type == (int)STRUCT_rtentry);
5694 se = struct_entries + *arg_type++;
5695 assert(se->convert[0] == NULL);
5696 /* convert struct here to be able to catch rt_dev string */
5697 field_types = se->field_types;
5698 dst_offsets = se->field_offsets[THUNK_HOST];
5699 src_offsets = se->field_offsets[THUNK_TARGET];
5700 for (i = 0; i < se->nb_fields; i++) {
5701 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5702 assert(*field_types == TYPE_PTRVOID);
5703 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5704 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5705 if (*target_rt_dev_ptr != 0) {
5706 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5707 tswapal(*target_rt_dev_ptr));
5708 if (!*host_rt_dev_ptr) {
5709 unlock_user(argptr, arg, 0);
5710 return -TARGET_EFAULT;
5711 }
5712 } else {
5713 *host_rt_dev_ptr = 0;
5714 }
5715 field_types++;
5716 continue;
5717 }
5718 field_types = thunk_convert(buf_temp + dst_offsets[i],
5719 argptr + src_offsets[i],
5720 field_types, THUNK_HOST);
5721 }
5722 unlock_user(argptr, arg, 0);
5723
Peter Maydell49ca6f32016-06-06 19:58:14 +01005724 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005725 if (*host_rt_dev_ptr != 0) {
5726 unlock_user((void *)*host_rt_dev_ptr,
5727 *target_rt_dev_ptr, 0);
5728 }
5729 return ret;
5730}
5731
Paul Burtonca56f5b2014-06-22 11:25:47 +01005732static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005733 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005734{
5735 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005736 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005737}
5738
Andreas Schwab2b74f622018-01-29 11:47:06 +01005739#ifdef TIOCGPTPEER
5740static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5741 int fd, int cmd, abi_long arg)
5742{
5743 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5744 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5745}
5746#endif
5747
blueswir19f106a72008-10-05 10:52:52 +00005748static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005749#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005750 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5751#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5752 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005753#define IOCTL_IGNORE(cmd) \
5754 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005755#include "ioctls.h"
5756 { 0, 0, },
5757};
5758
pbrook53a59602006-03-25 19:31:22 +00005759/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005760/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005761static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005762{
5763 const IOCTLEntry *ie;
5764 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005765 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005766 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005767 int target_size;
5768 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005769
5770 ie = ioctl_entries;
5771 for(;;) {
5772 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005773 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005774 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005775 }
5776 if (ie->target_cmd == cmd)
5777 break;
5778 ie++;
5779 }
5780 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005781#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005782 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005783#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005784 if (ie->do_ioctl) {
5785 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005786 } else if (!ie->host_cmd) {
5787 /* Some architectures define BSD ioctls in their headers
5788 that are not implemented in Linux. */
5789 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005790 }
5791
bellard31e31b82003-02-18 22:55:36 +00005792 switch(arg_type[0]) {
5793 case TYPE_NULL:
5794 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005795 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005796 break;
5797 case TYPE_PTRVOID:
5798 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005799 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005800 break;
5801 case TYPE_PTR:
5802 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005803 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005804 switch(ie->access) {
5805 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005806 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005807 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005808 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5809 if (!argptr)
5810 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005811 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5812 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005813 }
5814 break;
5815 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005816 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5817 if (!argptr)
5818 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005819 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5820 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005821 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005822 break;
5823 default:
5824 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005825 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5826 if (!argptr)
5827 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005828 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5829 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005830 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005831 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005832 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5833 if (!argptr)
5834 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005835 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5836 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005837 }
5838 break;
5839 }
5840 break;
5841 default:
j_mayer32407102007-09-26 23:01:49 +00005842 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5843 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005844 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005845 break;
5846 }
5847 return ret;
5848}
5849
blueswir1b39bc502008-10-05 10:51:10 +00005850static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005851 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5852 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5853 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5854 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5855 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5856 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5857 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5858 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5859 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5860 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5861 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5862 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5863 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5864 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5865 { 0, 0, 0, 0 }
5866};
5867
blueswir1b39bc502008-10-05 10:51:10 +00005868static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005869 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5870 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5871 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5872 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5873 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5874 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5875 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5876 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5877 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5878 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5879 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5880 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5881 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5882 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5883 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5884 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5885 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5886 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5887 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5888 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5889 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5890 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5891 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5892 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5893 { 0, 0, 0, 0 }
5894};
5895
blueswir1b39bc502008-10-05 10:51:10 +00005896static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005897 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5898 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5899 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5900 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5901 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5902 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5903 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5904 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5905 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5906 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5907 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5908 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5909 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5910 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5911 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5912 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5913 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5914 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5915 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5916 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5917 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5918 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5919 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5920 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5921 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5922 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5923 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5924 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5925 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5926 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5927 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5928 { 0, 0, 0, 0 }
5929};
5930
blueswir1b39bc502008-10-05 10:51:10 +00005931static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005932 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5933 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5934 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5935 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5936 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5937 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5938 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5939 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5940 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5941 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5942 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5943 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5944 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5945 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5946 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5947 { 0, 0, 0, 0 }
5948};
5949
5950static void target_to_host_termios (void *dst, const void *src)
5951{
5952 struct host_termios *host = dst;
5953 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005954
ths5fafdf22007-09-16 21:08:06 +00005955 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005956 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005957 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005958 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005959 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005960 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005961 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005962 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5963 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005964
Arnaud Patard44607122009-04-21 17:39:08 +03005965 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005966 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5967 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005968 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005969 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005970 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005971 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005972 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005973 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005974 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005975 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5976 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005977 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5978 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5979 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5980 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5981 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005982 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005983}
ths3b46e622007-09-17 08:09:54 +00005984
bellard31e31b82003-02-18 22:55:36 +00005985static void host_to_target_termios (void *dst, const void *src)
5986{
5987 struct target_termios *target = dst;
5988 const struct host_termios *host = src;
5989
ths5fafdf22007-09-16 21:08:06 +00005990 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005991 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005992 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005993 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005994 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005995 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005996 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005997 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5998 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005999
Arnaud Patard44607122009-04-21 17:39:08 +03006000 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00006001 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
6002 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
6003 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
6004 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
6005 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
6006 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
6007 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
6008 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
6009 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
6010 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
6011 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
6012 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
6013 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
6014 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
6015 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
6016 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
6017 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
6018}
6019
blueswir18e853dc2008-10-05 10:49:32 +00006020static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00006021 .convert = { host_to_target_termios, target_to_host_termios },
6022 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
6023 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
6024};
6025
bellard5286db72003-06-05 00:57:30 +00006026static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01006027 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
6028 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
6029 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
6030 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
6031 MAP_ANONYMOUS, MAP_ANONYMOUS },
6032 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
6033 MAP_GROWSDOWN, MAP_GROWSDOWN },
6034 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
6035 MAP_DENYWRITE, MAP_DENYWRITE },
6036 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
6037 MAP_EXECUTABLE, MAP_EXECUTABLE },
6038 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
6039 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
6040 MAP_NORESERVE, MAP_NORESERVE },
6041 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
6042 /* MAP_STACK had been ignored by the kernel for quite some time.
6043 Recognize it for the target insofar as we do not want to pass
6044 it through to the host. */
6045 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
6046 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00006047};
6048
bellard2ab83ea2003-06-15 19:56:46 +00006049#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00006050
6051/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00006052static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00006053
bellard03acab62007-11-11 14:57:14 +00006054static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006055{
6056 int size;
pbrook53a59602006-03-25 19:31:22 +00006057 void *p;
bellard6dbad632003-03-16 18:05:05 +00006058
6059 if (!ldt_table)
6060 return 0;
6061 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
6062 if (size > bytecount)
6063 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00006064 p = lock_user(VERIFY_WRITE, ptr, size, 0);
6065 if (!p)
bellard03acab62007-11-11 14:57:14 +00006066 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00006067 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00006068 memcpy(p, ldt_table, size);
6069 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00006070 return size;
6071}
6072
6073/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00006074static abi_long write_ldt(CPUX86State *env,
6075 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00006076{
6077 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00006078 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00006079 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00006080 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00006081 uint32_t *lp, entry_1, entry_2;
6082
6083 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00006084 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00006085 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00006086 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00006087 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006088 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00006089 ldt_info.limit = tswap32(target_ldt_info->limit);
6090 ldt_info.flags = tswap32(target_ldt_info->flags);
6091 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00006092
bellard6dbad632003-03-16 18:05:05 +00006093 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00006094 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006095 seg_32bit = ldt_info.flags & 1;
6096 contents = (ldt_info.flags >> 1) & 3;
6097 read_exec_only = (ldt_info.flags >> 3) & 1;
6098 limit_in_pages = (ldt_info.flags >> 4) & 1;
6099 seg_not_present = (ldt_info.flags >> 5) & 1;
6100 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00006101#ifdef TARGET_ABI32
6102 lm = 0;
6103#else
6104 lm = (ldt_info.flags >> 7) & 1;
6105#endif
bellard6dbad632003-03-16 18:05:05 +00006106 if (contents == 3) {
6107 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00006108 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006109 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00006110 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006111 }
6112 /* allocate the LDT */
6113 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006114 env->ldt.base = target_mmap(0,
6115 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6116 PROT_READ|PROT_WRITE,
6117 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6118 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006119 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00006120 memset(g2h(env->ldt.base), 0,
6121 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006122 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006123 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006124 }
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 (oldmode ||
6130 (contents == 0 &&
6131 read_exec_only == 1 &&
6132 seg_32bit == 0 &&
6133 limit_in_pages == 0 &&
6134 seg_not_present == 1 &&
6135 useable == 0 )) {
6136 entry_1 = 0;
6137 entry_2 = 0;
6138 goto install;
6139 }
6140 }
ths3b46e622007-09-17 08:09:54 +00006141
bellard6dbad632003-03-16 18:05:05 +00006142 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6143 (ldt_info.limit & 0x0ffff);
6144 entry_2 = (ldt_info.base_addr & 0xff000000) |
6145 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6146 (ldt_info.limit & 0xf0000) |
6147 ((read_exec_only ^ 1) << 9) |
6148 (contents << 10) |
6149 ((seg_not_present ^ 1) << 15) |
6150 (seg_32bit << 22) |
6151 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006152 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006153 0x7000;
6154 if (!oldmode)
6155 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006156
bellard6dbad632003-03-16 18:05:05 +00006157 /* Install the new entry ... */
6158install:
6159 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6160 lp[0] = tswap32(entry_1);
6161 lp[1] = tswap32(entry_2);
6162 return 0;
6163}
6164
6165/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006166static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6167 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006168{
bellard03acab62007-11-11 14:57:14 +00006169 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006170
bellard6dbad632003-03-16 18:05:05 +00006171 switch (func) {
6172 case 0:
6173 ret = read_ldt(ptr, bytecount);
6174 break;
6175 case 1:
6176 ret = write_ldt(env, ptr, bytecount, 1);
6177 break;
6178 case 0x11:
6179 ret = write_ldt(env, ptr, bytecount, 0);
6180 break;
bellard03acab62007-11-11 14:57:14 +00006181 default:
6182 ret = -TARGET_ENOSYS;
6183 break;
bellard6dbad632003-03-16 18:05:05 +00006184 }
6185 return ret;
6186}
bellard1b6b0292003-03-22 17:31:38 +00006187
blueswir14583f582008-08-24 10:35:55 +00006188#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006189abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006190{
6191 uint64_t *gdt_table = g2h(env->gdt.base);
6192 struct target_modify_ldt_ldt_s ldt_info;
6193 struct target_modify_ldt_ldt_s *target_ldt_info;
6194 int seg_32bit, contents, read_exec_only, limit_in_pages;
6195 int seg_not_present, useable, lm;
6196 uint32_t *lp, entry_1, entry_2;
6197 int i;
6198
6199 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6200 if (!target_ldt_info)
6201 return -TARGET_EFAULT;
6202 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006203 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006204 ldt_info.limit = tswap32(target_ldt_info->limit);
6205 ldt_info.flags = tswap32(target_ldt_info->flags);
6206 if (ldt_info.entry_number == -1) {
6207 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6208 if (gdt_table[i] == 0) {
6209 ldt_info.entry_number = i;
6210 target_ldt_info->entry_number = tswap32(i);
6211 break;
6212 }
6213 }
6214 }
6215 unlock_user_struct(target_ldt_info, ptr, 1);
6216
6217 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6218 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6219 return -TARGET_EINVAL;
6220 seg_32bit = ldt_info.flags & 1;
6221 contents = (ldt_info.flags >> 1) & 3;
6222 read_exec_only = (ldt_info.flags >> 3) & 1;
6223 limit_in_pages = (ldt_info.flags >> 4) & 1;
6224 seg_not_present = (ldt_info.flags >> 5) & 1;
6225 useable = (ldt_info.flags >> 6) & 1;
6226#ifdef TARGET_ABI32
6227 lm = 0;
6228#else
6229 lm = (ldt_info.flags >> 7) & 1;
6230#endif
6231
6232 if (contents == 3) {
6233 if (seg_not_present == 0)
6234 return -TARGET_EINVAL;
6235 }
6236
6237 /* NOTE: same code as Linux kernel */
6238 /* Allow LDTs to be cleared by the user. */
6239 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6240 if ((contents == 0 &&
6241 read_exec_only == 1 &&
6242 seg_32bit == 0 &&
6243 limit_in_pages == 0 &&
6244 seg_not_present == 1 &&
6245 useable == 0 )) {
6246 entry_1 = 0;
6247 entry_2 = 0;
6248 goto install;
6249 }
6250 }
6251
6252 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6253 (ldt_info.limit & 0x0ffff);
6254 entry_2 = (ldt_info.base_addr & 0xff000000) |
6255 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6256 (ldt_info.limit & 0xf0000) |
6257 ((read_exec_only ^ 1) << 9) |
6258 (contents << 10) |
6259 ((seg_not_present ^ 1) << 15) |
6260 (seg_32bit << 22) |
6261 (limit_in_pages << 23) |
6262 (useable << 20) |
6263 (lm << 21) |
6264 0x7000;
6265
6266 /* Install the new entry ... */
6267install:
6268 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6269 lp[0] = tswap32(entry_1);
6270 lp[1] = tswap32(entry_2);
6271 return 0;
6272}
6273
blueswir18fcd3692008-08-17 20:26:25 +00006274static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006275{
6276 struct target_modify_ldt_ldt_s *target_ldt_info;
6277 uint64_t *gdt_table = g2h(env->gdt.base);
6278 uint32_t base_addr, limit, flags;
6279 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6280 int seg_not_present, useable, lm;
6281 uint32_t *lp, entry_1, entry_2;
6282
6283 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6284 if (!target_ldt_info)
6285 return -TARGET_EFAULT;
6286 idx = tswap32(target_ldt_info->entry_number);
6287 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6288 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6289 unlock_user_struct(target_ldt_info, ptr, 1);
6290 return -TARGET_EINVAL;
6291 }
6292 lp = (uint32_t *)(gdt_table + idx);
6293 entry_1 = tswap32(lp[0]);
6294 entry_2 = tswap32(lp[1]);
6295
6296 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6297 contents = (entry_2 >> 10) & 3;
6298 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6299 seg_32bit = (entry_2 >> 22) & 1;
6300 limit_in_pages = (entry_2 >> 23) & 1;
6301 useable = (entry_2 >> 20) & 1;
6302#ifdef TARGET_ABI32
6303 lm = 0;
6304#else
6305 lm = (entry_2 >> 21) & 1;
6306#endif
6307 flags = (seg_32bit << 0) | (contents << 1) |
6308 (read_exec_only << 3) | (limit_in_pages << 4) |
6309 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6310 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6311 base_addr = (entry_1 >> 16) |
6312 (entry_2 & 0xff000000) |
6313 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006314 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006315 target_ldt_info->limit = tswap32(limit);
6316 target_ldt_info->flags = tswap32(flags);
6317 unlock_user_struct(target_ldt_info, ptr, 1);
6318 return 0;
6319}
blueswir14583f582008-08-24 10:35:55 +00006320#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006321
bellardd2fd1af2007-11-14 18:08:56 +00006322#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006323abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006324{
Juan Quintela1add8692011-06-16 17:37:09 +01006325 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006326 abi_ulong val;
6327 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006328
bellardd2fd1af2007-11-14 18:08:56 +00006329 switch(code) {
6330 case TARGET_ARCH_SET_GS:
6331 case TARGET_ARCH_SET_FS:
6332 if (code == TARGET_ARCH_SET_GS)
6333 idx = R_GS;
6334 else
6335 idx = R_FS;
6336 cpu_x86_load_seg(env, idx, 0);
6337 env->segs[idx].base = addr;
6338 break;
6339 case TARGET_ARCH_GET_GS:
6340 case TARGET_ARCH_GET_FS:
6341 if (code == TARGET_ARCH_GET_GS)
6342 idx = R_GS;
6343 else
6344 idx = R_FS;
6345 val = env->segs[idx].base;
6346 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006347 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006348 break;
6349 default:
6350 ret = -TARGET_EINVAL;
6351 break;
6352 }
Juan Quintela1add8692011-06-16 17:37:09 +01006353 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006354}
6355#endif
6356
bellard2ab83ea2003-06-15 19:56:46 +00006357#endif /* defined(TARGET_I386) */
6358
Riku Voipio05098a92011-03-04 15:27:29 +02006359#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006360
pbrookd865bab2008-06-07 22:12:17 +00006361
6362static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6363typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006364 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006365 pthread_mutex_t mutex;
6366 pthread_cond_t cond;
6367 pthread_t thread;
6368 uint32_t tid;
6369 abi_ulong child_tidptr;
6370 abi_ulong parent_tidptr;
6371 sigset_t sigmask;
6372} new_thread_info;
6373
6374static void *clone_func(void *arg)
6375{
6376 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006377 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006378 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006379 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006380
Emilio G. Cota70903762015-08-23 20:23:41 -04006381 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006382 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006383 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006384 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006385 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006386 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006387 info->tid = gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006388 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006389 if (info->child_tidptr)
6390 put_user_u32(info->tid, info->child_tidptr);
6391 if (info->parent_tidptr)
6392 put_user_u32(info->tid, info->parent_tidptr);
6393 /* Enable signals. */
6394 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6395 /* Signal to the parent that we're ready. */
6396 pthread_mutex_lock(&info->mutex);
6397 pthread_cond_broadcast(&info->cond);
6398 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006399 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006400 pthread_mutex_lock(&clone_lock);
6401 pthread_mutex_unlock(&clone_lock);
6402 cpu_loop(env);
6403 /* never exits */
6404 return NULL;
6405}
bellard1b6b0292003-03-22 17:31:38 +00006406
ths0da46a62007-10-20 20:23:07 +00006407/* do_fork() Must return host values and target errnos (unlike most
6408 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006409static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006410 abi_ulong parent_tidptr, target_ulong newtls,
6411 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006412{
Andreas Färber0429a972013-08-26 18:14:44 +02006413 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006414 int ret;
bellard5cd43932003-03-29 16:54:36 +00006415 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006416 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006417 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006418 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006419
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006420 flags &= ~CLONE_IGNORED_FLAGS;
6421
balrog436d1242008-09-21 02:39:45 +00006422 /* Emulate vfork() with fork() */
6423 if (flags & CLONE_VFORK)
6424 flags &= ~(CLONE_VFORK | CLONE_VM);
6425
bellard1b6b0292003-03-22 17:31:38 +00006426 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006427 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006428 new_thread_info info;
6429 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006430
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006431 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6432 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6433 return -TARGET_EINVAL;
6434 }
6435
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006436 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006437 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006438
6439 /* Grab a mutex so that thread setup appears atomic. */
6440 pthread_mutex_lock(&clone_lock);
6441
bellard1b6b0292003-03-22 17:31:38 +00006442 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006443 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006444 /* Init regs that differ from the parent. */
6445 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006446 new_cpu = ENV_GET_CPU(new_env);
6447 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006448 ts->bprm = parent_ts->bprm;
6449 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006450 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006451
Peter Maydell7cfbd382016-08-02 18:41:26 +01006452 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006453 ts->child_tidptr = child_tidptr;
6454 }
6455
Peter Maydell7cfbd382016-08-02 18:41:26 +01006456 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006457 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006458 }
pbrookd865bab2008-06-07 22:12:17 +00006459
pbrookd865bab2008-06-07 22:12:17 +00006460 memset(&info, 0, sizeof(info));
6461 pthread_mutex_init(&info.mutex, NULL);
6462 pthread_mutex_lock(&info.mutex);
6463 pthread_cond_init(&info.cond, NULL);
6464 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006465 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006466 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006467 }
6468 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006469 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006470 }
pbrookd865bab2008-06-07 22:12:17 +00006471
6472 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006473 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6474 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006475 /* It is not safe to deliver signals until the child has finished
6476 initializing, so temporarily block all signals. */
6477 sigfillset(&sigmask);
6478 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6479
Alex Bennéeb67cb682016-10-05 11:13:04 -07006480 /* If this is our first additional thread, we need to ensure we
6481 * generate code for parallel execution and flush old translations.
6482 */
6483 if (!parallel_cpus) {
6484 parallel_cpus = true;
6485 tb_flush(cpu);
6486 }
6487
pbrookd865bab2008-06-07 22:12:17 +00006488 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006489 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006490
6491 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6492 pthread_attr_destroy(&attr);
6493 if (ret == 0) {
6494 /* Wait for the child to initialize. */
6495 pthread_cond_wait(&info.cond, &info.mutex);
6496 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006497 } else {
6498 ret = -1;
6499 }
6500 pthread_mutex_unlock(&info.mutex);
6501 pthread_cond_destroy(&info.cond);
6502 pthread_mutex_destroy(&info.mutex);
6503 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006504 } else {
6505 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006506 if (flags & CLONE_INVALID_FORK_FLAGS) {
6507 return -TARGET_EINVAL;
6508 }
6509
6510 /* We can't support custom termination signals */
6511 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006512 return -TARGET_EINVAL;
6513 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006514
6515 if (block_signals()) {
6516 return -TARGET_ERESTARTSYS;
6517 }
6518
pbrookd865bab2008-06-07 22:12:17 +00006519 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006520 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006521 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006522 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00006523 cpu_clone_regs(env, newsp);
6524 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006525 /* There is a race condition here. The parent process could
6526 theoretically read the TID in the child process before the child
6527 tid is set. This would require using either ptrace
6528 (not implemented) or having *_tidptr to point at a shared memory
6529 mapping. We can't repeat the spinlock hack used above because
6530 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006531 if (flags & CLONE_CHILD_SETTID)
6532 put_user_u32(gettid(), child_tidptr);
6533 if (flags & CLONE_PARENT_SETTID)
6534 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006535 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006536 if (flags & CLONE_SETTLS)
6537 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006538 if (flags & CLONE_CHILD_CLEARTID)
6539 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006540 } else {
6541 fork_end(0);
6542 }
bellard1b6b0292003-03-22 17:31:38 +00006543 }
6544 return ret;
6545}
6546
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006547/* warning : doesn't handle linux specific flags... */
6548static int target_to_host_fcntl_cmd(int cmd)
6549{
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006550 int ret;
6551
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006552 switch(cmd) {
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006553 case TARGET_F_DUPFD:
6554 case TARGET_F_GETFD:
6555 case TARGET_F_SETFD:
6556 case TARGET_F_GETFL:
6557 case TARGET_F_SETFL:
6558 ret = cmd;
6559 break;
6560 case TARGET_F_GETLK:
6561 ret = F_GETLK64;
6562 break;
6563 case TARGET_F_SETLK:
6564 ret = F_SETLK64;
6565 break;
6566 case TARGET_F_SETLKW:
6567 ret = F_SETLKW64;
6568 break;
6569 case TARGET_F_GETOWN:
6570 ret = F_GETOWN;
6571 break;
6572 case TARGET_F_SETOWN:
6573 ret = F_SETOWN;
6574 break;
6575 case TARGET_F_GETSIG:
6576 ret = F_GETSIG;
6577 break;
6578 case TARGET_F_SETSIG:
6579 ret = F_SETSIG;
6580 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006581#if TARGET_ABI_BITS == 32
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006582 case TARGET_F_GETLK64:
6583 ret = F_GETLK64;
6584 break;
6585 case TARGET_F_SETLK64:
6586 ret = F_SETLK64;
6587 break;
6588 case TARGET_F_SETLKW64:
6589 ret = F_SETLKW64;
6590 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006591#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006592 case TARGET_F_SETLEASE:
6593 ret = F_SETLEASE;
6594 break;
6595 case TARGET_F_GETLEASE:
6596 ret = F_GETLEASE;
6597 break;
malcfbd5de92009-09-06 06:31:59 +04006598#ifdef F_DUPFD_CLOEXEC
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006599 case TARGET_F_DUPFD_CLOEXEC:
6600 ret = F_DUPFD_CLOEXEC;
6601 break;
malcfbd5de92009-09-06 06:31:59 +04006602#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006603 case TARGET_F_NOTIFY:
6604 ret = F_NOTIFY;
6605 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006606#ifdef F_GETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006607 case TARGET_F_GETOWN_EX:
6608 ret = F_GETOWN_EX;
6609 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006610#endif
6611#ifdef F_SETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006612 case TARGET_F_SETOWN_EX:
6613 ret = F_SETOWN_EX;
6614 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006615#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006616#ifdef F_SETPIPE_SZ
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006617 case TARGET_F_SETPIPE_SZ:
6618 ret = F_SETPIPE_SZ;
6619 break;
6620 case TARGET_F_GETPIPE_SZ:
6621 ret = F_GETPIPE_SZ;
6622 break;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006623#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006624 default:
6625 ret = -TARGET_EINVAL;
6626 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006627 }
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006628
6629#if defined(__powerpc64__)
6630 /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
6631 * is not supported by kernel. The glibc fcntl call actually adjusts
6632 * them to 5, 6 and 7 before making the syscall(). Since we make the
6633 * syscall directly, adjust to what is supported by the kernel.
6634 */
6635 if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
6636 ret -= F_GETLK64 - 5;
6637 }
6638#endif
6639
6640 return ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006641}
6642
Laurent Vivierae68ad92018-05-10 01:11:21 +02006643#define FLOCK_TRANSTBL \
6644 switch (type) { \
6645 TRANSTBL_CONVERT(F_RDLCK); \
6646 TRANSTBL_CONVERT(F_WRLCK); \
6647 TRANSTBL_CONVERT(F_UNLCK); \
6648 TRANSTBL_CONVERT(F_EXLCK); \
6649 TRANSTBL_CONVERT(F_SHLCK); \
6650 }
6651
6652static int target_to_host_flock(int type)
6653{
6654#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
6655 FLOCK_TRANSTBL
6656#undef TRANSTBL_CONVERT
6657 return -TARGET_EINVAL;
6658}
6659
6660static int host_to_target_flock(int type)
6661{
6662#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
6663 FLOCK_TRANSTBL
6664#undef TRANSTBL_CONVERT
6665 /* if we don't know how to convert the value coming
6666 * from the host we copy to the target field as-is
6667 */
6668 return type;
6669}
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006670
Peter Maydell213d3e92016-06-13 11:22:05 +01006671static inline abi_long copy_from_user_flock(struct flock64 *fl,
6672 abi_ulong target_flock_addr)
6673{
6674 struct target_flock *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006675 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006676
6677 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6678 return -TARGET_EFAULT;
6679 }
6680
6681 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006682 l_type = target_to_host_flock(l_type);
6683 if (l_type < 0) {
6684 return l_type;
6685 }
6686 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006687 __get_user(fl->l_whence, &target_fl->l_whence);
6688 __get_user(fl->l_start, &target_fl->l_start);
6689 __get_user(fl->l_len, &target_fl->l_len);
6690 __get_user(fl->l_pid, &target_fl->l_pid);
6691 unlock_user_struct(target_fl, target_flock_addr, 0);
6692 return 0;
6693}
6694
6695static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6696 const struct flock64 *fl)
6697{
6698 struct target_flock *target_fl;
6699 short l_type;
6700
6701 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6702 return -TARGET_EFAULT;
6703 }
6704
Laurent Vivierae68ad92018-05-10 01:11:21 +02006705 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006706 __put_user(l_type, &target_fl->l_type);
6707 __put_user(fl->l_whence, &target_fl->l_whence);
6708 __put_user(fl->l_start, &target_fl->l_start);
6709 __put_user(fl->l_len, &target_fl->l_len);
6710 __put_user(fl->l_pid, &target_fl->l_pid);
6711 unlock_user_struct(target_fl, target_flock_addr, 1);
6712 return 0;
6713}
6714
6715typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6716typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6717
6718#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
Laurent Vivier7f254c52018-05-02 23:57:30 +02006719static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006720 abi_ulong target_flock_addr)
6721{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006722 struct target_oabi_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006723 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006724
6725 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6726 return -TARGET_EFAULT;
6727 }
6728
6729 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006730 l_type = target_to_host_flock(l_type);
6731 if (l_type < 0) {
6732 return l_type;
6733 }
6734 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006735 __get_user(fl->l_whence, &target_fl->l_whence);
6736 __get_user(fl->l_start, &target_fl->l_start);
6737 __get_user(fl->l_len, &target_fl->l_len);
6738 __get_user(fl->l_pid, &target_fl->l_pid);
6739 unlock_user_struct(target_fl, target_flock_addr, 0);
6740 return 0;
6741}
6742
Laurent Vivier7f254c52018-05-02 23:57:30 +02006743static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
Peter Maydell213d3e92016-06-13 11:22:05 +01006744 const struct flock64 *fl)
6745{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006746 struct target_oabi_flock64 *target_fl;
Peter Maydell213d3e92016-06-13 11:22:05 +01006747 short l_type;
6748
6749 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6750 return -TARGET_EFAULT;
6751 }
6752
Laurent Vivierae68ad92018-05-10 01:11:21 +02006753 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006754 __put_user(l_type, &target_fl->l_type);
6755 __put_user(fl->l_whence, &target_fl->l_whence);
6756 __put_user(fl->l_start, &target_fl->l_start);
6757 __put_user(fl->l_len, &target_fl->l_len);
6758 __put_user(fl->l_pid, &target_fl->l_pid);
6759 unlock_user_struct(target_fl, target_flock_addr, 1);
6760 return 0;
6761}
6762#endif
6763
6764static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6765 abi_ulong target_flock_addr)
6766{
6767 struct target_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006768 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006769
6770 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6771 return -TARGET_EFAULT;
6772 }
6773
6774 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006775 l_type = target_to_host_flock(l_type);
6776 if (l_type < 0) {
6777 return l_type;
6778 }
6779 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006780 __get_user(fl->l_whence, &target_fl->l_whence);
6781 __get_user(fl->l_start, &target_fl->l_start);
6782 __get_user(fl->l_len, &target_fl->l_len);
6783 __get_user(fl->l_pid, &target_fl->l_pid);
6784 unlock_user_struct(target_fl, target_flock_addr, 0);
6785 return 0;
6786}
6787
6788static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6789 const struct flock64 *fl)
6790{
6791 struct target_flock64 *target_fl;
6792 short l_type;
6793
6794 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6795 return -TARGET_EFAULT;
6796 }
6797
Laurent Vivierae68ad92018-05-10 01:11:21 +02006798 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006799 __put_user(l_type, &target_fl->l_type);
6800 __put_user(fl->l_whence, &target_fl->l_whence);
6801 __put_user(fl->l_start, &target_fl->l_start);
6802 __put_user(fl->l_len, &target_fl->l_len);
6803 __put_user(fl->l_pid, &target_fl->l_pid);
6804 unlock_user_struct(target_fl, target_flock_addr, 1);
6805 return 0;
6806}
6807
blueswir1992f48a2007-10-14 16:27:31 +00006808static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006809{
ths43f238d2007-01-05 20:55:49 +00006810 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006811#ifdef F_GETOWN_EX
6812 struct f_owner_ex fox;
6813 struct target_f_owner_ex *target_fox;
6814#endif
blueswir1992f48a2007-10-14 16:27:31 +00006815 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006816 int host_cmd = target_to_host_fcntl_cmd(cmd);
6817
6818 if (host_cmd == -TARGET_EINVAL)
6819 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006820
bellard7775e9e2003-05-14 22:46:48 +00006821 switch(cmd) {
6822 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006823 ret = copy_from_user_flock(&fl64, arg);
6824 if (ret) {
6825 return ret;
6826 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006827 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006828 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006829 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006830 }
6831 break;
ths3b46e622007-09-17 08:09:54 +00006832
bellard7775e9e2003-05-14 22:46:48 +00006833 case TARGET_F_SETLK:
6834 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006835 ret = copy_from_user_flock(&fl64, arg);
6836 if (ret) {
6837 return ret;
6838 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006839 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006840 break;
ths3b46e622007-09-17 08:09:54 +00006841
bellard7775e9e2003-05-14 22:46:48 +00006842 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006843 ret = copy_from_user_flock64(&fl64, arg);
6844 if (ret) {
6845 return ret;
6846 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006847 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006848 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006849 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006850 }
bellard9ee1fa22007-11-11 15:11:19 +00006851 break;
bellard7775e9e2003-05-14 22:46:48 +00006852 case TARGET_F_SETLK64:
6853 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006854 ret = copy_from_user_flock64(&fl64, arg);
6855 if (ret) {
6856 return ret;
6857 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006858 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006859 break;
6860
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006861 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006862 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006863 if (ret >= 0) {
6864 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6865 }
bellardffa65c32004-01-04 23:57:22 +00006866 break;
6867
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006868 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006869 ret = get_errno(safe_fcntl(fd, host_cmd,
6870 target_to_host_bitmask(arg,
6871 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006872 break;
6873
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006874#ifdef F_GETOWN_EX
6875 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006876 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006877 if (ret >= 0) {
6878 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6879 return -TARGET_EFAULT;
6880 target_fox->type = tswap32(fox.type);
6881 target_fox->pid = tswap32(fox.pid);
6882 unlock_user_struct(target_fox, arg, 1);
6883 }
6884 break;
6885#endif
6886
6887#ifdef F_SETOWN_EX
6888 case TARGET_F_SETOWN_EX:
6889 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6890 return -TARGET_EFAULT;
6891 fox.type = tswap32(target_fox->type);
6892 fox.pid = tswap32(target_fox->pid);
6893 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006894 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006895 break;
6896#endif
6897
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006898 case TARGET_F_SETOWN:
6899 case TARGET_F_GETOWN:
6900 case TARGET_F_SETSIG:
6901 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006902 case TARGET_F_SETLEASE:
6903 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006904 case TARGET_F_SETPIPE_SZ:
6905 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006906 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006907 break;
6908
bellard7775e9e2003-05-14 22:46:48 +00006909 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006910 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006911 break;
6912 }
6913 return ret;
6914}
6915
bellard67867302003-11-23 17:05:30 +00006916#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006917
bellard67867302003-11-23 17:05:30 +00006918static inline int high2lowuid(int uid)
6919{
6920 if (uid > 65535)
6921 return 65534;
6922 else
6923 return uid;
6924}
6925
6926static inline int high2lowgid(int gid)
6927{
6928 if (gid > 65535)
6929 return 65534;
6930 else
6931 return gid;
6932}
6933
6934static inline int low2highuid(int uid)
6935{
6936 if ((int16_t)uid == -1)
6937 return -1;
6938 else
6939 return uid;
6940}
6941
6942static inline int low2highgid(int gid)
6943{
6944 if ((int16_t)gid == -1)
6945 return -1;
6946 else
6947 return gid;
6948}
Riku Voipio0c866a72011-04-18 15:23:06 +03006949static inline int tswapid(int id)
6950{
6951 return tswap16(id);
6952}
Peter Maydell76ca3102014-03-02 19:36:41 +00006953
6954#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6955
Riku Voipio0c866a72011-04-18 15:23:06 +03006956#else /* !USE_UID16 */
6957static inline int high2lowuid(int uid)
6958{
6959 return uid;
6960}
6961static inline int high2lowgid(int gid)
6962{
6963 return gid;
6964}
6965static inline int low2highuid(int uid)
6966{
6967 return uid;
6968}
6969static inline int low2highgid(int gid)
6970{
6971 return gid;
6972}
6973static inline int tswapid(int id)
6974{
6975 return tswap32(id);
6976}
Peter Maydell76ca3102014-03-02 19:36:41 +00006977
6978#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6979
bellard67867302003-11-23 17:05:30 +00006980#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006981
Peter Maydellfd6f7792016-03-01 16:33:02 +00006982/* We must do direct syscalls for setting UID/GID, because we want to
6983 * implement the Linux system call semantics of "change only for this thread",
6984 * not the libc/POSIX semantics of "change for all threads in process".
6985 * (See http://ewontfix.com/17/ for more details.)
6986 * We use the 32-bit version of the syscalls if present; if it is not
6987 * then either the host architecture supports 32-bit UIDs natively with
6988 * the standard syscall, or the 16-bit UID is the best we can do.
6989 */
6990#ifdef __NR_setuid32
6991#define __NR_sys_setuid __NR_setuid32
6992#else
6993#define __NR_sys_setuid __NR_setuid
6994#endif
6995#ifdef __NR_setgid32
6996#define __NR_sys_setgid __NR_setgid32
6997#else
6998#define __NR_sys_setgid __NR_setgid
6999#endif
7000#ifdef __NR_setresuid32
7001#define __NR_sys_setresuid __NR_setresuid32
7002#else
7003#define __NR_sys_setresuid __NR_setresuid
7004#endif
7005#ifdef __NR_setresgid32
7006#define __NR_sys_setresgid __NR_setresgid32
7007#else
7008#define __NR_sys_setresgid __NR_setresgid
7009#endif
7010
7011_syscall1(int, sys_setuid, uid_t, uid)
7012_syscall1(int, sys_setgid, gid_t, gid)
7013_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
7014_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
7015
bellard31e31b82003-02-18 22:55:36 +00007016void syscall_init(void)
7017{
bellard2ab83ea2003-06-15 19:56:46 +00007018 IOCTLEntry *ie;
7019 const argtype *arg_type;
7020 int size;
thsb92c47c2007-11-01 00:07:38 +00007021 int i;
bellard2ab83ea2003-06-15 19:56:46 +00007022
Alexander Graf8be656b2015-05-06 23:47:32 +02007023 thunk_init(STRUCT_MAX);
7024
Blue Swirl001faf32009-05-13 17:53:17 +00007025#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00007026#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00007027#include "syscall_types.h"
7028#undef STRUCT
7029#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00007030
Peter Maydelldd6e9572012-07-23 08:07:22 +00007031 /* Build target_to_host_errno_table[] table from
7032 * host_to_target_errno_table[]. */
7033 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
7034 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
7035 }
7036
bellard2ab83ea2003-06-15 19:56:46 +00007037 /* we patch the ioctl size if necessary. We rely on the fact that
7038 no ioctl has all the bits at '1' in the size field */
7039 ie = ioctl_entries;
7040 while (ie->target_cmd != 0) {
7041 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
7042 TARGET_IOC_SIZEMASK) {
7043 arg_type = ie->arg_type;
7044 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00007045 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00007046 ie->target_cmd);
7047 exit(1);
7048 }
7049 arg_type++;
7050 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00007051 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00007052 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
7053 (size << TARGET_IOC_SIZESHIFT);
7054 }
thsb92c47c2007-11-01 00:07:38 +00007055
bellard2ab83ea2003-06-15 19:56:46 +00007056 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00007057#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7058 (defined(__x86_64__) && defined(TARGET_X86_64))
7059 if (unlikely(ie->target_cmd != ie->host_cmd)) {
7060 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
7061 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00007062 }
7063#endif
7064 ie++;
7065 }
bellard31e31b82003-02-18 22:55:36 +00007066}
bellardc573ff62004-01-04 15:51:36 +00007067
blueswir1992f48a2007-10-14 16:27:31 +00007068#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00007069static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
7070{
thsaf325d32008-06-10 15:29:15 +00007071#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00007072 return ((uint64_t)word0 << 32) | word1;
7073#else
7074 return ((uint64_t)word1 << 32) | word0;
7075#endif
7076}
blueswir1992f48a2007-10-14 16:27:31 +00007077#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00007078static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
7079{
7080 return word0;
7081}
blueswir1992f48a2007-10-14 16:27:31 +00007082#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00007083
7084#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00007085static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
7086 abi_long arg2,
7087 abi_long arg3,
7088 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007089{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007090 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007091 arg2 = arg3;
7092 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007093 }
pbrookce4defa2006-02-09 16:49:55 +00007094 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
7095}
7096#endif
7097
7098#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00007099static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
7100 abi_long arg2,
7101 abi_long arg3,
7102 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007103{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007104 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007105 arg2 = arg3;
7106 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007107 }
pbrookce4defa2006-02-09 16:49:55 +00007108 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
7109}
7110#endif
7111
bellard579a97f2007-11-11 14:26:47 +00007112static inline abi_long target_to_host_timespec(struct timespec *host_ts,
7113 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00007114{
7115 struct target_timespec *target_ts;
7116
bellard579a97f2007-11-11 14:26:47 +00007117 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
7118 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01007119 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
7120 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00007121 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00007122 return 0;
pbrook53a59602006-03-25 19:31:22 +00007123}
7124
bellard579a97f2007-11-11 14:26:47 +00007125static inline abi_long host_to_target_timespec(abi_ulong target_addr,
7126 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00007127{
7128 struct target_timespec *target_ts;
7129
bellard579a97f2007-11-11 14:26:47 +00007130 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
7131 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01007132 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
7133 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00007134 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00007135 return 0;
pbrook53a59602006-03-25 19:31:22 +00007136}
7137
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007138static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
7139 abi_ulong target_addr)
7140{
7141 struct target_itimerspec *target_itspec;
7142
7143 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
7144 return -TARGET_EFAULT;
7145 }
7146
7147 host_itspec->it_interval.tv_sec =
7148 tswapal(target_itspec->it_interval.tv_sec);
7149 host_itspec->it_interval.tv_nsec =
7150 tswapal(target_itspec->it_interval.tv_nsec);
7151 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
7152 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
7153
7154 unlock_user_struct(target_itspec, target_addr, 1);
7155 return 0;
7156}
7157
7158static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
7159 struct itimerspec *host_its)
7160{
7161 struct target_itimerspec *target_itspec;
7162
7163 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
7164 return -TARGET_EFAULT;
7165 }
7166
7167 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
7168 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
7169
7170 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
7171 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
7172
7173 unlock_user_struct(target_itspec, target_addr, 0);
7174 return 0;
7175}
7176
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007177static inline abi_long target_to_host_timex(struct timex *host_tx,
7178 abi_long target_addr)
7179{
7180 struct target_timex *target_tx;
7181
7182 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7183 return -TARGET_EFAULT;
7184 }
7185
7186 __get_user(host_tx->modes, &target_tx->modes);
7187 __get_user(host_tx->offset, &target_tx->offset);
7188 __get_user(host_tx->freq, &target_tx->freq);
7189 __get_user(host_tx->maxerror, &target_tx->maxerror);
7190 __get_user(host_tx->esterror, &target_tx->esterror);
7191 __get_user(host_tx->status, &target_tx->status);
7192 __get_user(host_tx->constant, &target_tx->constant);
7193 __get_user(host_tx->precision, &target_tx->precision);
7194 __get_user(host_tx->tolerance, &target_tx->tolerance);
7195 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7196 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7197 __get_user(host_tx->tick, &target_tx->tick);
7198 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7199 __get_user(host_tx->jitter, &target_tx->jitter);
7200 __get_user(host_tx->shift, &target_tx->shift);
7201 __get_user(host_tx->stabil, &target_tx->stabil);
7202 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7203 __get_user(host_tx->calcnt, &target_tx->calcnt);
7204 __get_user(host_tx->errcnt, &target_tx->errcnt);
7205 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7206 __get_user(host_tx->tai, &target_tx->tai);
7207
7208 unlock_user_struct(target_tx, target_addr, 0);
7209 return 0;
7210}
7211
7212static inline abi_long host_to_target_timex(abi_long target_addr,
7213 struct timex *host_tx)
7214{
7215 struct target_timex *target_tx;
7216
7217 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7218 return -TARGET_EFAULT;
7219 }
7220
7221 __put_user(host_tx->modes, &target_tx->modes);
7222 __put_user(host_tx->offset, &target_tx->offset);
7223 __put_user(host_tx->freq, &target_tx->freq);
7224 __put_user(host_tx->maxerror, &target_tx->maxerror);
7225 __put_user(host_tx->esterror, &target_tx->esterror);
7226 __put_user(host_tx->status, &target_tx->status);
7227 __put_user(host_tx->constant, &target_tx->constant);
7228 __put_user(host_tx->precision, &target_tx->precision);
7229 __put_user(host_tx->tolerance, &target_tx->tolerance);
7230 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7231 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7232 __put_user(host_tx->tick, &target_tx->tick);
7233 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7234 __put_user(host_tx->jitter, &target_tx->jitter);
7235 __put_user(host_tx->shift, &target_tx->shift);
7236 __put_user(host_tx->stabil, &target_tx->stabil);
7237 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7238 __put_user(host_tx->calcnt, &target_tx->calcnt);
7239 __put_user(host_tx->errcnt, &target_tx->errcnt);
7240 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7241 __put_user(host_tx->tai, &target_tx->tai);
7242
7243 unlock_user_struct(target_tx, target_addr, 1);
7244 return 0;
7245}
7246
7247
Peter Maydellc0659762014-08-09 15:42:32 +01007248static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7249 abi_ulong target_addr)
7250{
7251 struct target_sigevent *target_sevp;
7252
7253 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7254 return -TARGET_EFAULT;
7255 }
7256
7257 /* This union is awkward on 64 bit systems because it has a 32 bit
7258 * integer and a pointer in it; we follow the conversion approach
7259 * used for handling sigval types in signal.c so the guest should get
7260 * the correct value back even if we did a 64 bit byteswap and it's
7261 * using the 32 bit integer.
7262 */
7263 host_sevp->sigev_value.sival_ptr =
7264 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7265 host_sevp->sigev_signo =
7266 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7267 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7268 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7269
7270 unlock_user_struct(target_sevp, target_addr, 1);
7271 return 0;
7272}
7273
Tom Musta6f6a4032014-08-12 13:53:42 -05007274#if defined(TARGET_NR_mlockall)
7275static inline int target_to_host_mlockall_arg(int arg)
7276{
7277 int result = 0;
7278
7279 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7280 result |= MCL_CURRENT;
7281 }
7282 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7283 result |= MCL_FUTURE;
7284 }
7285 return result;
7286}
7287#endif
7288
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007289#if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \
7290 defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \
7291 defined(TARGET_NR_newfstatat))
balrog6a24a772008-09-20 02:23:36 +00007292static inline abi_long host_to_target_stat64(void *cpu_env,
7293 abi_ulong target_addr,
7294 struct stat *host_st)
7295{
Alexander Graf09701192013-09-03 20:12:15 +01007296#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007297 if (((CPUARMState *)cpu_env)->eabi) {
7298 struct target_eabi_stat64 *target_st;
7299
7300 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7301 return -TARGET_EFAULT;
7302 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7303 __put_user(host_st->st_dev, &target_st->st_dev);
7304 __put_user(host_st->st_ino, &target_st->st_ino);
7305#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7306 __put_user(host_st->st_ino, &target_st->__st_ino);
7307#endif
7308 __put_user(host_st->st_mode, &target_st->st_mode);
7309 __put_user(host_st->st_nlink, &target_st->st_nlink);
7310 __put_user(host_st->st_uid, &target_st->st_uid);
7311 __put_user(host_st->st_gid, &target_st->st_gid);
7312 __put_user(host_st->st_rdev, &target_st->st_rdev);
7313 __put_user(host_st->st_size, &target_st->st_size);
7314 __put_user(host_st->st_blksize, &target_st->st_blksize);
7315 __put_user(host_st->st_blocks, &target_st->st_blocks);
7316 __put_user(host_st->st_atime, &target_st->target_st_atime);
7317 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7318 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7319 unlock_user_struct(target_st, target_addr, 1);
7320 } else
7321#endif
7322 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007323#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007324 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007325#else
7326 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007327#endif
balrog6a24a772008-09-20 02:23:36 +00007328
7329 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7330 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007331 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007332 __put_user(host_st->st_dev, &target_st->st_dev);
7333 __put_user(host_st->st_ino, &target_st->st_ino);
7334#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7335 __put_user(host_st->st_ino, &target_st->__st_ino);
7336#endif
7337 __put_user(host_st->st_mode, &target_st->st_mode);
7338 __put_user(host_st->st_nlink, &target_st->st_nlink);
7339 __put_user(host_st->st_uid, &target_st->st_uid);
7340 __put_user(host_st->st_gid, &target_st->st_gid);
7341 __put_user(host_st->st_rdev, &target_st->st_rdev);
7342 /* XXX: better use of kernel struct */
7343 __put_user(host_st->st_size, &target_st->st_size);
7344 __put_user(host_st->st_blksize, &target_st->st_blksize);
7345 __put_user(host_st->st_blocks, &target_st->st_blocks);
7346 __put_user(host_st->st_atime, &target_st->target_st_atime);
7347 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7348 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7349 unlock_user_struct(target_st, target_addr, 1);
7350 }
7351
7352 return 0;
7353}
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02007354#endif
balrog6a24a772008-09-20 02:23:36 +00007355
pbrookbd0c5662008-05-29 14:34:11 +00007356/* ??? Using host futex calls even when target atomic operations
7357 are not really atomic probably breaks things. However implementing
7358 futexes locally would make futexes shared between multiple processes
7359 tricky. However they're probably useless because guest atomic
7360 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007361static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7362 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007363{
7364 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007365 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007366
7367 /* ??? We assume FUTEX_* constants are the same on both host
7368 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007369#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007370 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007371#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007372 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007373#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007374 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007375 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007376 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007377 if (timeout) {
7378 pts = &ts;
7379 target_to_host_timespec(pts, timeout);
7380 } else {
7381 pts = NULL;
7382 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007383 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007384 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007385 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007386 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007387 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007388 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007389 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007390 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007391 case FUTEX_WAKE_OP:
7392 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7393 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7394 But the prototype takes a `struct timespec *'; insert casts
7395 to satisfy the compiler. We do not need to tswap TIMEOUT
7396 since it's not compared to guest memory. */
7397 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007398 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7399 g2h(uaddr2),
7400 (base_op == FUTEX_CMP_REQUEUE
7401 ? tswap32(val3)
7402 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007403 default:
7404 return -TARGET_ENOSYS;
7405 }
7406}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007407#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7408static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7409 abi_long handle, abi_long mount_id,
7410 abi_long flags)
7411{
7412 struct file_handle *target_fh;
7413 struct file_handle *fh;
7414 int mid = 0;
7415 abi_long ret;
7416 char *name;
7417 unsigned int size, total_size;
7418
7419 if (get_user_s32(size, handle)) {
7420 return -TARGET_EFAULT;
7421 }
7422
7423 name = lock_user_string(pathname);
7424 if (!name) {
7425 return -TARGET_EFAULT;
7426 }
7427
7428 total_size = sizeof(struct file_handle) + size;
7429 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7430 if (!target_fh) {
7431 unlock_user(name, pathname, 0);
7432 return -TARGET_EFAULT;
7433 }
7434
7435 fh = g_malloc0(total_size);
7436 fh->handle_bytes = size;
7437
7438 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7439 unlock_user(name, pathname, 0);
7440
7441 /* man name_to_handle_at(2):
7442 * Other than the use of the handle_bytes field, the caller should treat
7443 * the file_handle structure as an opaque data type
7444 */
7445
7446 memcpy(target_fh, fh, total_size);
7447 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7448 target_fh->handle_type = tswap32(fh->handle_type);
7449 g_free(fh);
7450 unlock_user(target_fh, handle, total_size);
7451
7452 if (put_user_s32(mid, mount_id)) {
7453 return -TARGET_EFAULT;
7454 }
7455
7456 return ret;
7457
7458}
7459#endif
7460
7461#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7462static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7463 abi_long flags)
7464{
7465 struct file_handle *target_fh;
7466 struct file_handle *fh;
7467 unsigned int size, total_size;
7468 abi_long ret;
7469
7470 if (get_user_s32(size, handle)) {
7471 return -TARGET_EFAULT;
7472 }
7473
7474 total_size = sizeof(struct file_handle) + size;
7475 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7476 if (!target_fh) {
7477 return -TARGET_EFAULT;
7478 }
7479
Thomas Huthe9d49d52015-10-09 17:56:38 +02007480 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007481 fh->handle_bytes = size;
7482 fh->handle_type = tswap32(target_fh->handle_type);
7483
7484 ret = get_errno(open_by_handle_at(mount_fd, fh,
7485 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7486
7487 g_free(fh);
7488
7489 unlock_user(target_fh, handle, total_size);
7490
7491 return ret;
7492}
7493#endif
pbrookbd0c5662008-05-29 14:34:11 +00007494
Laurent Viviere36800c2015-10-02 14:48:09 +02007495#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7496
7497/* signalfd siginfo conversion */
7498
7499static void
7500host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7501 const struct signalfd_siginfo *info)
7502{
7503 int sig = host_to_target_signal(info->ssi_signo);
7504
7505 /* linux/signalfd.h defines a ssi_addr_lsb
7506 * not defined in sys/signalfd.h but used by some kernels
7507 */
7508
7509#ifdef BUS_MCEERR_AO
7510 if (tinfo->ssi_signo == SIGBUS &&
7511 (tinfo->ssi_code == BUS_MCEERR_AR ||
7512 tinfo->ssi_code == BUS_MCEERR_AO)) {
7513 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7514 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7515 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7516 }
7517#endif
7518
7519 tinfo->ssi_signo = tswap32(sig);
7520 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7521 tinfo->ssi_code = tswap32(info->ssi_code);
7522 tinfo->ssi_pid = tswap32(info->ssi_pid);
7523 tinfo->ssi_uid = tswap32(info->ssi_uid);
7524 tinfo->ssi_fd = tswap32(info->ssi_fd);
7525 tinfo->ssi_tid = tswap32(info->ssi_tid);
7526 tinfo->ssi_band = tswap32(info->ssi_band);
7527 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7528 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7529 tinfo->ssi_status = tswap32(info->ssi_status);
7530 tinfo->ssi_int = tswap32(info->ssi_int);
7531 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7532 tinfo->ssi_utime = tswap64(info->ssi_utime);
7533 tinfo->ssi_stime = tswap64(info->ssi_stime);
7534 tinfo->ssi_addr = tswap64(info->ssi_addr);
7535}
7536
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007537static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007538{
7539 int i;
7540
7541 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7542 host_to_target_signalfd_siginfo(buf + i, buf + i);
7543 }
7544
7545 return len;
7546}
7547
7548static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007549 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007550};
7551
7552static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7553{
7554 int host_flags;
7555 target_sigset_t *target_mask;
7556 sigset_t host_mask;
7557 abi_long ret;
7558
7559 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7560 return -TARGET_EINVAL;
7561 }
7562 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7563 return -TARGET_EFAULT;
7564 }
7565
7566 target_to_host_sigset(&host_mask, target_mask);
7567
7568 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7569
7570 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7571 if (ret >= 0) {
7572 fd_trans_register(ret, &target_signalfd_trans);
7573 }
7574
7575 unlock_user_struct(target_mask, mask, 0);
7576
7577 return ret;
7578}
7579#endif
7580
pbrook1d9d8b52009-04-16 15:17:02 +00007581/* Map host to target signal numbers for the wait family of syscalls.
7582 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007583int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007584{
7585 if (WIFSIGNALED(status)) {
7586 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7587 }
7588 if (WIFSTOPPED(status)) {
7589 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7590 | (status & 0xff);
7591 }
7592 return status;
7593}
7594
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007595static int open_self_cmdline(void *cpu_env, int fd)
7596{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007597 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7598 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7599 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007600
Andreas Schwab58de8b92017-03-20 12:31:55 +01007601 for (i = 0; i < bprm->argc; i++) {
7602 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007603
Andreas Schwab58de8b92017-03-20 12:31:55 +01007604 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007605 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007606 }
7607 }
7608
Andreas Schwab58de8b92017-03-20 12:31:55 +01007609 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007610}
7611
Alexander Graf36c08d42011-11-02 20:23:24 +01007612static int open_self_maps(void *cpu_env, int fd)
7613{
Andreas Färber0429a972013-08-26 18:14:44 +02007614 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7615 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007616 FILE *fp;
7617 char *line = NULL;
7618 size_t len = 0;
7619 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007620
Alexander Graf1a49ef22012-05-01 16:30:28 +01007621 fp = fopen("/proc/self/maps", "r");
7622 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007623 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007624 }
7625
7626 while ((read = getline(&line, &len, fp)) != -1) {
7627 int fields, dev_maj, dev_min, inode;
7628 uint64_t min, max, offset;
7629 char flag_r, flag_w, flag_x, flag_p;
7630 char path[512] = "";
7631 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7632 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7633 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7634
7635 if ((fields < 10) || (fields > 11)) {
7636 continue;
7637 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007638 if (h2g_valid(min)) {
7639 int flags = page_get_flags(h2g(min));
Max Filippovebf9a362018-03-07 13:50:10 -08007640 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007641 if (page_check_range(h2g(min), max - min, flags) == -1) {
7642 continue;
7643 }
7644 if (h2g(min) == ts->info->stack_limit) {
7645 pstrcpy(path, sizeof(path), " [stack]");
7646 }
Laurent Vivier3e23de12018-08-14 19:12:17 +02007647 dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
Christophe Lyone24fed42013-04-02 14:03:38 +02007648 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007649 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007650 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007651 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007652 }
7653 }
7654
7655 free(line);
7656 fclose(fp);
7657
Alexander Graf36c08d42011-11-02 20:23:24 +01007658 return 0;
7659}
7660
Alexander Graf480b8e72011-11-02 20:23:25 +01007661static int open_self_stat(void *cpu_env, int fd)
7662{
Andreas Färber0429a972013-08-26 18:14:44 +02007663 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7664 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007665 abi_ulong start_stack = ts->info->start_stack;
7666 int i;
7667
7668 for (i = 0; i < 44; i++) {
7669 char buf[128];
7670 int len;
7671 uint64_t val = 0;
7672
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007673 if (i == 0) {
7674 /* pid */
7675 val = getpid();
7676 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7677 } else if (i == 1) {
7678 /* app name */
7679 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7680 } else if (i == 27) {
7681 /* stack bottom */
7682 val = start_stack;
7683 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7684 } else {
7685 /* for the rest, there is MasterCard */
7686 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007687 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007688
Alexander Graf480b8e72011-11-02 20:23:25 +01007689 len = strlen(buf);
7690 if (write(fd, buf, len) != len) {
7691 return -1;
7692 }
7693 }
7694
7695 return 0;
7696}
7697
Alexander Graf257450e2011-11-02 20:23:26 +01007698static int open_self_auxv(void *cpu_env, int fd)
7699{
Andreas Färber0429a972013-08-26 18:14:44 +02007700 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7701 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007702 abi_ulong auxv = ts->info->saved_auxv;
7703 abi_ulong len = ts->info->auxv_len;
7704 char *ptr;
7705
7706 /*
7707 * Auxiliary vector is stored in target process stack.
7708 * read in whole auxv vector and copy it to file
7709 */
7710 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7711 if (ptr != NULL) {
7712 while (len > 0) {
7713 ssize_t r;
7714 r = write(fd, ptr, len);
7715 if (r <= 0) {
7716 break;
7717 }
7718 len -= r;
7719 ptr += r;
7720 }
7721 lseek(fd, 0, SEEK_SET);
7722 unlock_user(ptr, auxv, len);
7723 }
7724
7725 return 0;
7726}
7727
Andreas Schwab463d8e72013-07-02 14:04:12 +01007728static int is_proc_myself(const char *filename, const char *entry)
7729{
7730 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7731 filename += strlen("/proc/");
7732 if (!strncmp(filename, "self/", strlen("self/"))) {
7733 filename += strlen("self/");
7734 } else if (*filename >= '1' && *filename <= '9') {
7735 char myself[80];
7736 snprintf(myself, sizeof(myself), "%d/", getpid());
7737 if (!strncmp(filename, myself, strlen(myself))) {
7738 filename += strlen(myself);
7739 } else {
7740 return 0;
7741 }
7742 } else {
7743 return 0;
7744 }
7745 if (!strcmp(filename, entry)) {
7746 return 1;
7747 }
7748 }
7749 return 0;
7750}
7751
Laurent Vivierde6b9932013-08-30 01:46:40 +02007752#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7753static int is_proc(const char *filename, const char *entry)
7754{
7755 return strcmp(filename, entry) == 0;
7756}
7757
7758static int open_net_route(void *cpu_env, int fd)
7759{
7760 FILE *fp;
7761 char *line = NULL;
7762 size_t len = 0;
7763 ssize_t read;
7764
7765 fp = fopen("/proc/net/route", "r");
7766 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007767 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007768 }
7769
7770 /* read header */
7771
7772 read = getline(&line, &len, fp);
7773 dprintf(fd, "%s", line);
7774
7775 /* read routes */
7776
7777 while ((read = getline(&line, &len, fp)) != -1) {
7778 char iface[16];
7779 uint32_t dest, gw, mask;
7780 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7781 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7782 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7783 &mask, &mtu, &window, &irtt);
7784 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7785 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7786 metric, tswap32(mask), mtu, window, irtt);
7787 }
7788
7789 free(line);
7790 fclose(fp);
7791
7792 return 0;
7793}
7794#endif
7795
Riku Voipio0b2effd2014-08-06 10:36:37 +03007796static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007797{
7798 struct fake_open {
7799 const char *filename;
7800 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007801 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007802 };
7803 const struct fake_open *fake_open;
7804 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007805 { "maps", open_self_maps, is_proc_myself },
7806 { "stat", open_self_stat, is_proc_myself },
7807 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007808 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007809#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7810 { "/proc/net/route", open_net_route, is_proc },
7811#endif
7812 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007813 };
7814
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007815 if (is_proc_myself(pathname, "exe")) {
7816 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007817 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007818 }
7819
Alexander Graf3be14d02011-11-02 20:23:23 +01007820 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007821 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007822 break;
7823 }
7824 }
7825
7826 if (fake_open->filename) {
7827 const char *tmpdir;
7828 char filename[PATH_MAX];
7829 int fd, r;
7830
7831 /* create temporary file to map stat to */
7832 tmpdir = getenv("TMPDIR");
7833 if (!tmpdir)
7834 tmpdir = "/tmp";
7835 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7836 fd = mkstemp(filename);
7837 if (fd < 0) {
7838 return fd;
7839 }
7840 unlink(filename);
7841
7842 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007843 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007844 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007845 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007846 return r;
7847 }
7848 lseek(fd, 0, SEEK_SET);
7849
7850 return fd;
7851 }
7852
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007853 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007854}
7855
Alexander Grafaecc8862014-11-10 21:33:03 +01007856#define TIMER_MAGIC 0x0caf0000
7857#define TIMER_MAGIC_MASK 0xffff0000
7858
7859/* Convert QEMU provided timer ID back to internal 16bit index format */
7860static target_timer_t get_timer_id(abi_long arg)
7861{
7862 target_timer_t timerid = arg;
7863
7864 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7865 return -TARGET_EINVAL;
7866 }
7867
7868 timerid &= 0xffff;
7869
7870 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7871 return -TARGET_EINVAL;
7872 }
7873
7874 return timerid;
7875}
7876
Laurent Vivier562a20b2017-03-01 10:37:48 +01007877static abi_long swap_data_eventfd(void *buf, size_t len)
7878{
7879 uint64_t *counter = buf;
7880 int i;
7881
7882 if (len < sizeof(uint64_t)) {
7883 return -EINVAL;
7884 }
7885
7886 for (i = 0; i < len; i += sizeof(uint64_t)) {
7887 *counter = tswap64(*counter);
7888 counter++;
7889 }
7890
7891 return len;
7892}
7893
7894static TargetFdTrans target_eventfd_trans = {
7895 .host_to_target_data = swap_data_eventfd,
7896 .target_to_host_data = swap_data_eventfd,
7897};
7898
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007899#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7900 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7901 defined(__NR_inotify_init1))
7902static abi_long host_to_target_data_inotify(void *buf, size_t len)
7903{
7904 struct inotify_event *ev;
7905 int i;
7906 uint32_t name_len;
7907
7908 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7909 ev = (struct inotify_event *)((char *)buf + i);
7910 name_len = ev->len;
7911
7912 ev->wd = tswap32(ev->wd);
7913 ev->mask = tswap32(ev->mask);
7914 ev->cookie = tswap32(ev->cookie);
7915 ev->len = tswap32(name_len);
7916 }
7917
7918 return len;
7919}
7920
7921static TargetFdTrans target_inotify_trans = {
7922 .host_to_target_data = host_to_target_data_inotify,
7923};
7924#endif
7925
Samuel Thibault2e0a8712018-01-09 21:16:43 +01007926static int target_to_host_cpu_mask(unsigned long *host_mask,
7927 size_t host_size,
7928 abi_ulong target_addr,
7929 size_t target_size)
7930{
7931 unsigned target_bits = sizeof(abi_ulong) * 8;
7932 unsigned host_bits = sizeof(*host_mask) * 8;
7933 abi_ulong *target_mask;
7934 unsigned i, j;
7935
7936 assert(host_size >= target_size);
7937
7938 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7939 if (!target_mask) {
7940 return -TARGET_EFAULT;
7941 }
7942 memset(host_mask, 0, host_size);
7943
7944 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7945 unsigned bit = i * target_bits;
7946 abi_ulong val;
7947
7948 __get_user(val, &target_mask[i]);
7949 for (j = 0; j < target_bits; j++, bit++) {
7950 if (val & (1UL << j)) {
7951 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7952 }
7953 }
7954 }
7955
7956 unlock_user(target_mask, target_addr, 0);
7957 return 0;
7958}
7959
7960static int host_to_target_cpu_mask(const unsigned long *host_mask,
7961 size_t host_size,
7962 abi_ulong target_addr,
7963 size_t target_size)
7964{
7965 unsigned target_bits = sizeof(abi_ulong) * 8;
7966 unsigned host_bits = sizeof(*host_mask) * 8;
7967 abi_ulong *target_mask;
7968 unsigned i, j;
7969
7970 assert(host_size >= target_size);
7971
7972 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7973 if (!target_mask) {
7974 return -TARGET_EFAULT;
7975 }
7976
7977 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7978 unsigned bit = i * target_bits;
7979 abi_ulong val = 0;
7980
7981 for (j = 0; j < target_bits; j++, bit++) {
7982 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7983 val |= 1UL << j;
7984 }
7985 }
7986 __put_user(val, &target_mask[i]);
7987 }
7988
7989 unlock_user(target_mask, target_addr, target_size);
7990 return 0;
7991}
7992
ths0da46a62007-10-20 20:23:07 +00007993/* do_syscall() should always have a single exit point at the end so
7994 that actions, such as logging of syscall results, can be performed.
7995 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007996abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7997 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007998 abi_long arg5, abi_long arg6, abi_long arg7,
7999 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00008000{
Andreas Färber182735e2013-05-29 22:29:20 +02008001 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00008002 abi_long ret;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008003#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
8004 || defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
8005 || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
bellard31e31b82003-02-18 22:55:36 +00008006 struct stat st;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008007#endif
8008#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
8009 || defined(TARGET_NR_fstatfs)
bellard56c8f682005-11-28 22:28:41 +00008010 struct statfs stfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008011#endif
pbrook53a59602006-03-25 19:31:22 +00008012 void *p;
ths3b46e622007-09-17 08:09:54 +00008013
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01008014#if defined(DEBUG_ERESTARTSYS)
8015 /* Debug-only code for exercising the syscall-restart code paths
8016 * in the per-architecture cpu main loops: restart every syscall
8017 * the guest makes once before letting it through.
8018 */
8019 {
8020 static int flag;
8021
8022 flag = !flag;
8023 if (flag) {
8024 return -TARGET_ERESTARTSYS;
8025 }
8026 }
8027#endif
8028
bellard72f03902003-02-18 23:33:18 +00008029#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00008030 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00008031#endif
Lluís Vilanova9c15e702016-06-21 15:52:04 +02008032 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00008033 if(do_strace)
8034 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
8035
bellard31e31b82003-02-18 22:55:36 +00008036 switch(num) {
8037 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02008038 /* In old applications this may be used to implement _exit(2).
8039 However in threaded applictions it is used for thread termination,
8040 and _exit_group is used for application termination.
8041 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01008042
8043 if (block_signals()) {
8044 ret = -TARGET_ERESTARTSYS;
8045 break;
8046 }
8047
Alex Bennéedd1f6342016-09-30 22:31:01 +01008048 cpu_list_lock();
8049
Andreas Färberbdc44642013-06-24 23:50:24 +02008050 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02008051 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00008052
Andreas Färber9b056fc2013-06-24 23:53:10 +02008053 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02008054 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01008055
Andreas Färber9b056fc2013-06-24 23:53:10 +02008056 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01008057
Andreas Färber0429a972013-08-26 18:14:44 +02008058 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02008059 if (ts->child_tidptr) {
8060 put_user_u32(0, ts->child_tidptr);
8061 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
8062 NULL, NULL, 0);
8063 }
Andreas Färbera2247f82013-06-09 19:47:04 +02008064 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02008065 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02008066 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04008067 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02008068 pthread_exit(NULL);
8069 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01008070
8071 cpu_list_unlock();
Alex Bennée708b6a62018-06-22 17:09:10 +01008072 preexit_cleanup(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00008073 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00008074 ret = 0; /* avoid warning */
8075 break;
8076 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00008077 if (arg3 == 0)
8078 ret = 0;
8079 else {
8080 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8081 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01008082 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008083 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01008084 fd_trans_host_to_target_data(arg1)) {
8085 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02008086 }
aurel3238d840e2009-01-30 19:48:17 +00008087 unlock_user(p, arg2, ret);
8088 }
bellard31e31b82003-02-18 22:55:36 +00008089 break;
8090 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00008091 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8092 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01008093 if (fd_trans_target_to_host_data(arg1)) {
8094 void *copy = g_malloc(arg3);
8095 memcpy(copy, p, arg3);
8096 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
8097 if (ret >= 0) {
8098 ret = get_errno(safe_write(arg1, copy, ret));
8099 }
8100 g_free(copy);
8101 } else {
8102 ret = get_errno(safe_write(arg1, p, arg3));
8103 }
pbrook53a59602006-03-25 19:31:22 +00008104 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00008105 break;
Chen Gang704eff62015-08-21 05:37:33 +08008106#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00008107 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00008108 if (!(p = lock_user_string(arg1)))
8109 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008110 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
8111 target_to_host_bitmask(arg2, fcntl_flags_tbl),
8112 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008113 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008114 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008115 break;
Chen Gang704eff62015-08-21 05:37:33 +08008116#endif
ths82424832007-09-24 09:21:55 +00008117 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00008118 if (!(p = lock_user_string(arg2)))
8119 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008120 ret = get_errno(do_openat(cpu_env, arg1, p,
8121 target_to_host_bitmask(arg3, fcntl_flags_tbl),
8122 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02008123 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00008124 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00008125 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008126#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8127 case TARGET_NR_name_to_handle_at:
8128 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
8129 break;
8130#endif
8131#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8132 case TARGET_NR_open_by_handle_at:
8133 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008134 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008135 break;
8136#endif
bellard31e31b82003-02-18 22:55:36 +00008137 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02008138 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00008139 ret = get_errno(close(arg1));
8140 break;
8141 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00008142 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00008143 break;
Chen Gang704eff62015-08-21 05:37:33 +08008144#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00008145 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01008146 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008147 break;
Chen Gang704eff62015-08-21 05:37:33 +08008148#endif
thse5febef2007-04-01 18:31:35 +00008149#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00008150 case TARGET_NR_waitpid:
8151 {
pbrook53a59602006-03-25 19:31:22 +00008152 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008153 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01008154 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00008155 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00008156 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008157 }
8158 break;
thse5febef2007-04-01 18:31:35 +00008159#endif
pbrookf0cbb612008-05-30 18:20:05 +00008160#ifdef TARGET_NR_waitid
8161 case TARGET_NR_waitid:
8162 {
8163 siginfo_t info;
8164 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008165 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00008166 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008167 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00008168 goto efault;
8169 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05008170 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00008171 }
8172 }
8173 break;
8174#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008175#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008176 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00008177 if (!(p = lock_user_string(arg1)))
8178 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008179 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008180 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008181 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008182 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008183#endif
Chen Gang704eff62015-08-21 05:37:33 +08008184#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00008185 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00008186 {
8187 void * p2;
8188 p = lock_user_string(arg1);
8189 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008190 if (!p || !p2)
8191 ret = -TARGET_EFAULT;
8192 else
8193 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008194 unlock_user(p2, arg2, 0);
8195 unlock_user(p, arg1, 0);
8196 }
bellard31e31b82003-02-18 22:55:36 +00008197 break;
Chen Gang704eff62015-08-21 05:37:33 +08008198#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008199#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008200 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008201 {
8202 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008203 if (!arg2 || !arg4)
8204 goto efault;
ths64f0ce42007-09-24 09:25:06 +00008205 p = lock_user_string(arg2);
8206 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008207 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008208 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008209 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008210 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008211 unlock_user(p, arg2, 0);
8212 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008213 }
8214 break;
8215#endif
Chen Gang704eff62015-08-21 05:37:33 +08008216#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008217 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008218 if (!(p = lock_user_string(arg1)))
8219 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008220 ret = get_errno(unlink(p));
8221 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008222 break;
Chen Gang704eff62015-08-21 05:37:33 +08008223#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008224#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008225 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008226 if (!(p = lock_user_string(arg2)))
8227 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008228 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008229 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00008230 break;
balrogb7d35e62007-12-12 00:40:24 +00008231#endif
bellard31e31b82003-02-18 22:55:36 +00008232 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008233 {
8234 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008235 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008236 abi_ulong gp;
8237 abi_ulong guest_argp;
8238 abi_ulong guest_envp;
8239 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008240 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008241 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008242
bellardf7341ff2003-03-30 21:00:25 +00008243 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008244 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008245 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008246 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008247 goto efault;
ths03aa1972007-12-02 06:28:08 +00008248 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008249 break;
bellard7854b052003-03-29 17:22:23 +00008250 argc++;
bellard2f619692007-11-16 10:46:05 +00008251 }
bellardf7341ff2003-03-30 21:00:25 +00008252 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008253 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008254 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008255 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008256 goto efault;
ths03aa1972007-12-02 06:28:08 +00008257 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008258 break;
bellard7854b052003-03-29 17:22:23 +00008259 envc++;
bellard2f619692007-11-16 10:46:05 +00008260 }
bellard7854b052003-03-29 17:22:23 +00008261
Prasad J Panditb936cb52017-03-07 12:51:47 +05308262 argp = g_new0(char *, argc + 1);
8263 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008264
pbrookda94d262008-05-30 18:24:00 +00008265 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008266 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008267 if (get_user_ual(addr, gp))
8268 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008269 if (!addr)
8270 break;
bellard2f619692007-11-16 10:46:05 +00008271 if (!(*q = lock_user_string(addr)))
8272 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008273 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008274 }
bellardf7341ff2003-03-30 21:00:25 +00008275 *q = NULL;
8276
pbrookda94d262008-05-30 18:24:00 +00008277 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008278 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008279 if (get_user_ual(addr, gp))
8280 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008281 if (!addr)
8282 break;
bellard2f619692007-11-16 10:46:05 +00008283 if (!(*q = lock_user_string(addr)))
8284 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008285 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008286 }
bellardf7341ff2003-03-30 21:00:25 +00008287 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008288
bellard2f619692007-11-16 10:46:05 +00008289 if (!(p = lock_user_string(arg1)))
8290 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008291 /* Although execve() is not an interruptible syscall it is
8292 * a special case where we must use the safe_syscall wrapper:
8293 * if we allow a signal to happen before we make the host
8294 * syscall then we will 'lose' it, because at the point of
8295 * execve the process leaves QEMU's control. So we use the
8296 * safe syscall wrapper to ensure that we either take the
8297 * signal as a guest signal, or else it does not happen
8298 * before the execve completes and makes it the other
8299 * program's problem.
8300 */
8301 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008302 unlock_user(p, arg1, 0);
8303
bellard2f619692007-11-16 10:46:05 +00008304 goto execve_end;
8305
8306 execve_efault:
8307 ret = -TARGET_EFAULT;
8308
8309 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008310 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008311 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008312 if (get_user_ual(addr, gp)
8313 || !addr)
8314 break;
pbrook53a59602006-03-25 19:31:22 +00008315 unlock_user(*q, addr, 0);
8316 }
8317 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008318 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008319 if (get_user_ual(addr, gp)
8320 || !addr)
8321 break;
pbrook53a59602006-03-25 19:31:22 +00008322 unlock_user(*q, addr, 0);
8323 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308324
8325 g_free(argp);
8326 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008327 }
bellard31e31b82003-02-18 22:55:36 +00008328 break;
8329 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008330 if (!(p = lock_user_string(arg1)))
8331 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008332 ret = get_errno(chdir(p));
8333 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008334 break;
bellarda315a142005-01-30 22:59:18 +00008335#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008336 case TARGET_NR_time:
8337 {
pbrook53a59602006-03-25 19:31:22 +00008338 time_t host_time;
8339 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008340 if (!is_error(ret)
8341 && arg1
8342 && put_user_sal(host_time, arg1))
8343 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008344 }
8345 break;
bellarda315a142005-01-30 22:59:18 +00008346#endif
Chen Gang704eff62015-08-21 05:37:33 +08008347#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008348 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008349 if (!(p = lock_user_string(arg1)))
8350 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008351 ret = get_errno(mknod(p, arg2, arg3));
8352 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008353 break;
Chen Gang704eff62015-08-21 05:37:33 +08008354#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008355#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008356 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008357 if (!(p = lock_user_string(arg2)))
8358 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008359 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008360 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008361 break;
8362#endif
Chen Gang704eff62015-08-21 05:37:33 +08008363#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008364 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008365 if (!(p = lock_user_string(arg1)))
8366 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008367 ret = get_errno(chmod(p, arg2));
8368 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008369 break;
Chen Gang704eff62015-08-21 05:37:33 +08008370#endif
bellardebc05482003-09-30 21:08:41 +00008371#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008372 case TARGET_NR_break:
8373 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008374#endif
8375#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008376 case TARGET_NR_oldstat:
8377 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008378#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008379#ifdef TARGET_NR_lseek
bellard31e31b82003-02-18 22:55:36 +00008380 case TARGET_NR_lseek:
8381 ret = get_errno(lseek(arg1, arg2, arg3));
8382 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02008383#endif
Richard Henderson92317332010-05-03 10:07:53 -07008384#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8385 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008386 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008387 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008388 ret = get_errno(getpid());
8389 break;
Richard Henderson92317332010-05-03 10:07:53 -07008390#endif
8391#ifdef TARGET_NR_getpid
8392 case TARGET_NR_getpid:
8393 ret = get_errno(getpid());
8394 break;
8395#endif
bellard31e31b82003-02-18 22:55:36 +00008396 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008397 {
8398 /* need to look at the data field */
8399 void *p2, *p3;
8400
8401 if (arg1) {
8402 p = lock_user_string(arg1);
8403 if (!p) {
8404 goto efault;
8405 }
8406 } else {
8407 p = NULL;
8408 }
8409
8410 p2 = lock_user_string(arg2);
8411 if (!p2) {
8412 if (arg1) {
8413 unlock_user(p, arg1, 0);
8414 }
8415 goto efault;
8416 }
8417
8418 if (arg3) {
8419 p3 = lock_user_string(arg3);
8420 if (!p3) {
8421 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008422 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008423 }
8424 unlock_user(p2, arg2, 0);
8425 goto efault;
8426 }
8427 } else {
8428 p3 = NULL;
8429 }
8430
8431 /* FIXME - arg5 should be locked, but it isn't clear how to
8432 * do that since it's not guaranteed to be a NULL-terminated
8433 * string.
8434 */
8435 if (!arg5) {
8436 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8437 } else {
8438 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8439 }
8440 ret = get_errno(ret);
8441
8442 if (arg1) {
8443 unlock_user(p, arg1, 0);
8444 }
8445 unlock_user(p2, arg2, 0);
8446 if (arg3) {
8447 unlock_user(p3, arg3, 0);
8448 }
8449 }
8450 break;
thse5febef2007-04-01 18:31:35 +00008451#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008452 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008453 if (!(p = lock_user_string(arg1)))
8454 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008455 ret = get_errno(umount(p));
8456 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008457 break;
thse5febef2007-04-01 18:31:35 +00008458#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008459#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008460 case TARGET_NR_stime:
8461 {
pbrook53a59602006-03-25 19:31:22 +00008462 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008463 if (get_user_sal(host_time, arg1))
8464 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008465 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008466 }
8467 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008468#endif
bellard31e31b82003-02-18 22:55:36 +00008469 case TARGET_NR_ptrace:
8470 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008471#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008472 case TARGET_NR_alarm:
8473 ret = alarm(arg1);
8474 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008475#endif
bellardebc05482003-09-30 21:08:41 +00008476#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008477 case TARGET_NR_oldfstat:
8478 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008479#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008480#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008481 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008482 if (!block_signals()) {
8483 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8484 }
8485 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008486 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008487#endif
thse5febef2007-04-01 18:31:35 +00008488#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008489 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008490 {
pbrook53a59602006-03-25 19:31:22 +00008491 struct utimbuf tbuf, *host_tbuf;
8492 struct target_utimbuf *target_tbuf;
8493 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008494 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8495 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008496 tbuf.actime = tswapal(target_tbuf->actime);
8497 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008498 unlock_user_struct(target_tbuf, arg2, 0);
8499 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008500 } else {
pbrook53a59602006-03-25 19:31:22 +00008501 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008502 }
bellard579a97f2007-11-11 14:26:47 +00008503 if (!(p = lock_user_string(arg1)))
8504 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008505 ret = get_errno(utime(p, host_tbuf));
8506 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008507 }
8508 break;
thse5febef2007-04-01 18:31:35 +00008509#endif
Chen Gang704eff62015-08-21 05:37:33 +08008510#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008511 case TARGET_NR_utimes:
8512 {
bellard978a66f2004-12-06 22:58:05 +00008513 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008514 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008515 if (copy_from_user_timeval(&tv[0], arg2)
8516 || copy_from_user_timeval(&tv[1],
8517 arg2 + sizeof(struct target_timeval)))
8518 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008519 tvp = tv;
8520 } else {
8521 tvp = NULL;
8522 }
bellard579a97f2007-11-11 14:26:47 +00008523 if (!(p = lock_user_string(arg1)))
8524 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008525 ret = get_errno(utimes(p, tvp));
8526 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008527 }
8528 break;
Chen Gang704eff62015-08-21 05:37:33 +08008529#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008530#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008531 case TARGET_NR_futimesat:
8532 {
8533 struct timeval *tvp, tv[2];
8534 if (arg3) {
8535 if (copy_from_user_timeval(&tv[0], arg3)
8536 || copy_from_user_timeval(&tv[1],
8537 arg3 + sizeof(struct target_timeval)))
8538 goto efault;
8539 tvp = tv;
8540 } else {
8541 tvp = NULL;
8542 }
8543 if (!(p = lock_user_string(arg2)))
8544 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008545 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008546 unlock_user(p, arg2, 0);
8547 }
8548 break;
8549#endif
bellardebc05482003-09-30 21:08:41 +00008550#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008551 case TARGET_NR_stty:
8552 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008553#endif
8554#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008555 case TARGET_NR_gtty:
8556 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008557#endif
Chen Gang704eff62015-08-21 05:37:33 +08008558#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008559 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008560 if (!(p = lock_user_string(arg1)))
8561 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008562 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008563 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008564 break;
Chen Gang704eff62015-08-21 05:37:33 +08008565#endif
ths92a34c12007-09-24 09:27:49 +00008566#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8567 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008568 if (!(p = lock_user_string(arg2)))
8569 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008570 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008571 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008572 break;
8573#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008574#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008575 case TARGET_NR_nice:
8576 ret = get_errno(nice(arg1));
8577 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008578#endif
bellardebc05482003-09-30 21:08:41 +00008579#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008580 case TARGET_NR_ftime:
8581 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008582#endif
bellard31e31b82003-02-18 22:55:36 +00008583 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008584 sync();
8585 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008586 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008587#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8588 case TARGET_NR_syncfs:
8589 ret = get_errno(syncfs(arg1));
8590 break;
8591#endif
bellard31e31b82003-02-18 22:55:36 +00008592 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008593 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008594 break;
Chen Gang704eff62015-08-21 05:37:33 +08008595#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008596 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008597 {
8598 void *p2;
8599 p = lock_user_string(arg1);
8600 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008601 if (!p || !p2)
8602 ret = -TARGET_EFAULT;
8603 else
8604 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008605 unlock_user(p2, arg2, 0);
8606 unlock_user(p, arg1, 0);
8607 }
bellard31e31b82003-02-18 22:55:36 +00008608 break;
Chen Gang704eff62015-08-21 05:37:33 +08008609#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008610#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008611 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008612 {
bellard579a97f2007-11-11 14:26:47 +00008613 void *p2;
ths722183f2007-09-24 09:24:37 +00008614 p = lock_user_string(arg2);
8615 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008616 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008617 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008618 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008619 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008620 unlock_user(p2, arg4, 0);
8621 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008622 }
8623 break;
8624#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01008625#if defined(TARGET_NR_renameat2)
8626 case TARGET_NR_renameat2:
8627 {
8628 void *p2;
8629 p = lock_user_string(arg2);
8630 p2 = lock_user_string(arg4);
8631 if (!p || !p2) {
8632 ret = -TARGET_EFAULT;
8633 } else {
8634 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
8635 }
8636 unlock_user(p2, arg4, 0);
8637 unlock_user(p, arg2, 0);
8638 }
8639 break;
8640#endif
Chen Gang704eff62015-08-21 05:37:33 +08008641#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008642 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008643 if (!(p = lock_user_string(arg1)))
8644 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008645 ret = get_errno(mkdir(p, arg2));
8646 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008647 break;
Chen Gang704eff62015-08-21 05:37:33 +08008648#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008649#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008650 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008651 if (!(p = lock_user_string(arg2)))
8652 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008653 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008654 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008655 break;
8656#endif
Chen Gang704eff62015-08-21 05:37:33 +08008657#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008658 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008659 if (!(p = lock_user_string(arg1)))
8660 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008661 ret = get_errno(rmdir(p));
8662 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008663 break;
Chen Gang704eff62015-08-21 05:37:33 +08008664#endif
bellard31e31b82003-02-18 22:55:36 +00008665 case TARGET_NR_dup:
8666 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008667 if (ret >= 0) {
8668 fd_trans_dup(arg1, ret);
8669 }
bellard31e31b82003-02-18 22:55:36 +00008670 break;
Chen Gang704eff62015-08-21 05:37:33 +08008671#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008672 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008673 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008674 break;
Chen Gang704eff62015-08-21 05:37:33 +08008675#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008676#ifdef TARGET_NR_pipe2
8677 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008678 ret = do_pipe(cpu_env, arg1,
8679 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008680 break;
8681#endif
bellard31e31b82003-02-18 22:55:36 +00008682 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008683 {
pbrook53a59602006-03-25 19:31:22 +00008684 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008685 struct tms tms;
8686 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008687 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008688 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8689 if (!tmsp)
8690 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008691 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8692 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8693 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8694 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008695 }
bellardc596ed12003-07-13 17:32:31 +00008696 if (!is_error(ret))
8697 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008698 }
8699 break;
bellardebc05482003-09-30 21:08:41 +00008700#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008701 case TARGET_NR_prof:
8702 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008703#endif
thse5febef2007-04-01 18:31:35 +00008704#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008705 case TARGET_NR_signal:
8706 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008707#endif
bellard31e31b82003-02-18 22:55:36 +00008708 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008709 if (arg1 == 0) {
8710 ret = get_errno(acct(NULL));
8711 } else {
8712 if (!(p = lock_user_string(arg1)))
8713 goto efault;
8714 ret = get_errno(acct(path(p)));
8715 unlock_user(p, arg1, 0);
8716 }
pbrook24836682006-04-16 14:14:53 +00008717 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008718#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008719 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008720 if (!(p = lock_user_string(arg1)))
8721 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008722 ret = get_errno(umount2(p, arg2));
8723 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008724 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008725#endif
bellardebc05482003-09-30 21:08:41 +00008726#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008727 case TARGET_NR_lock:
8728 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008729#endif
bellard31e31b82003-02-18 22:55:36 +00008730 case TARGET_NR_ioctl:
8731 ret = do_ioctl(arg1, arg2, arg3);
8732 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008733#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00008734 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008735 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008736 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008737#endif
bellardebc05482003-09-30 21:08:41 +00008738#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008739 case TARGET_NR_mpx:
8740 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008741#endif
bellard31e31b82003-02-18 22:55:36 +00008742 case TARGET_NR_setpgid:
8743 ret = get_errno(setpgid(arg1, arg2));
8744 break;
bellardebc05482003-09-30 21:08:41 +00008745#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008746 case TARGET_NR_ulimit:
8747 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008748#endif
8749#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008750 case TARGET_NR_oldolduname:
8751 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008752#endif
bellard31e31b82003-02-18 22:55:36 +00008753 case TARGET_NR_umask:
8754 ret = get_errno(umask(arg1));
8755 break;
8756 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008757 if (!(p = lock_user_string(arg1)))
8758 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008759 ret = get_errno(chroot(p));
8760 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008761 break;
Chen Gang704eff62015-08-21 05:37:33 +08008762#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008763 case TARGET_NR_ustat:
8764 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008765#endif
8766#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008767 case TARGET_NR_dup2:
8768 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008769 if (ret >= 0) {
8770 fd_trans_dup(arg1, arg2);
8771 }
bellard31e31b82003-02-18 22:55:36 +00008772 break;
Chen Gang704eff62015-08-21 05:37:33 +08008773#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008774#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8775 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008776 {
8777 int host_flags;
8778
8779 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8780 return -EINVAL;
8781 }
8782 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8783 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008784 if (ret >= 0) {
8785 fd_trans_dup(arg1, arg2);
8786 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008787 break;
Peter Maydell10fa9932017-12-15 15:18:00 +00008788 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008789#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008790#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008791 case TARGET_NR_getppid:
8792 ret = get_errno(getppid());
8793 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008794#endif
Chen Gang704eff62015-08-21 05:37:33 +08008795#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008796 case TARGET_NR_getpgrp:
8797 ret = get_errno(getpgrp());
8798 break;
Chen Gang704eff62015-08-21 05:37:33 +08008799#endif
bellard31e31b82003-02-18 22:55:36 +00008800 case TARGET_NR_setsid:
8801 ret = get_errno(setsid());
8802 break;
thse5febef2007-04-01 18:31:35 +00008803#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008804 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008805 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008806#if defined(TARGET_ALPHA)
8807 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008808 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008809 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008810 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8811 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008812 act._sa_handler = old_act->_sa_handler;
8813 target_siginitset(&act.sa_mask, old_act->sa_mask);
8814 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008815 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008816 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008817 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008818 }
8819 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008820 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008821 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008823 old_act->_sa_handler = oact._sa_handler;
8824 old_act->sa_mask = oact.sa_mask.sig[0];
8825 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008826 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008827 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008828#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008829 struct target_sigaction act, oact, *pact, *old_act;
8830
8831 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008832 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8833 goto efault;
bellard106ec872006-06-27 21:08:10 +00008834 act._sa_handler = old_act->_sa_handler;
8835 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8836 act.sa_flags = old_act->sa_flags;
8837 unlock_user_struct(old_act, arg2, 0);
8838 pact = &act;
8839 } else {
8840 pact = NULL;
8841 }
8842
8843 ret = get_errno(do_sigaction(arg1, pact, &oact));
8844
8845 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008846 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8847 goto efault;
bellard106ec872006-06-27 21:08:10 +00008848 old_act->_sa_handler = oact._sa_handler;
8849 old_act->sa_flags = oact.sa_flags;
8850 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8851 old_act->sa_mask.sig[1] = 0;
8852 old_act->sa_mask.sig[2] = 0;
8853 old_act->sa_mask.sig[3] = 0;
8854 unlock_user_struct(old_act, arg3, 1);
8855 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008856#else
8857 struct target_old_sigaction *old_act;
8858 struct target_sigaction act, oact, *pact;
8859 if (arg2) {
8860 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8861 goto efault;
8862 act._sa_handler = old_act->_sa_handler;
8863 target_siginitset(&act.sa_mask, old_act->sa_mask);
8864 act.sa_flags = old_act->sa_flags;
8865 act.sa_restorer = old_act->sa_restorer;
Laurent Vivier5de154e2018-04-02 12:24:52 +02008866#ifdef TARGET_ARCH_HAS_KA_RESTORER
8867 act.ka_restorer = 0;
8868#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08008869 unlock_user_struct(old_act, arg2, 0);
8870 pact = &act;
8871 } else {
8872 pact = NULL;
8873 }
8874 ret = get_errno(do_sigaction(arg1, pact, &oact));
8875 if (!is_error(ret) && arg3) {
8876 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8877 goto efault;
8878 old_act->_sa_handler = oact._sa_handler;
8879 old_act->sa_mask = oact.sa_mask.sig[0];
8880 old_act->sa_flags = oact.sa_flags;
8881 old_act->sa_restorer = oact.sa_restorer;
8882 unlock_user_struct(old_act, arg3, 1);
8883 }
ths388bb212007-05-13 13:58:00 +00008884#endif
bellard31e31b82003-02-18 22:55:36 +00008885 }
8886 break;
thse5febef2007-04-01 18:31:35 +00008887#endif
bellard66fb9762003-03-23 01:06:05 +00008888 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008889 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008890#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008891 /* For Alpha and SPARC this is a 5 argument syscall, with
8892 * a 'restorer' parameter which must be copied into the
8893 * sa_restorer field of the sigaction struct.
8894 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8895 * and arg5 is the sigsetsize.
8896 * Alpha also has a separate rt_sigaction struct that it uses
8897 * here; SPARC uses the usual sigaction struct.
8898 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008899 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008900 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008901
8902 if (arg4 != sizeof(target_sigset_t)) {
8903 ret = -TARGET_EINVAL;
8904 break;
8905 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008906 if (arg2) {
8907 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8908 goto efault;
8909 act._sa_handler = rt_act->_sa_handler;
8910 act.sa_mask = rt_act->sa_mask;
8911 act.sa_flags = rt_act->sa_flags;
8912 act.sa_restorer = arg5;
8913 unlock_user_struct(rt_act, arg2, 0);
8914 pact = &act;
8915 }
8916 ret = get_errno(do_sigaction(arg1, pact, &oact));
8917 if (!is_error(ret) && arg3) {
8918 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8919 goto efault;
8920 rt_act->_sa_handler = oact._sa_handler;
8921 rt_act->sa_mask = oact.sa_mask;
8922 rt_act->sa_flags = oact.sa_flags;
8923 unlock_user_struct(rt_act, arg3, 1);
8924 }
8925#else
Peter Maydell78bfef72017-11-06 18:33:26 +00008926#ifdef TARGET_SPARC
8927 target_ulong restorer = arg4;
8928 target_ulong sigsetsize = arg5;
8929#else
8930 target_ulong sigsetsize = arg4;
8931#endif
pbrook53a59602006-03-25 19:31:22 +00008932 struct target_sigaction *act;
8933 struct target_sigaction *oact;
8934
Peter Maydell78bfef72017-11-06 18:33:26 +00008935 if (sigsetsize != sizeof(target_sigset_t)) {
Peter Maydellc8157012016-06-30 14:23:24 +01008936 ret = -TARGET_EINVAL;
8937 break;
8938 }
bellard579a97f2007-11-11 14:26:47 +00008939 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00008940 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
bellard579a97f2007-11-11 14:26:47 +00008941 goto efault;
Peter Maydell78bfef72017-11-06 18:33:26 +00008942 }
Laurent Vivier5de154e2018-04-02 12:24:52 +02008943#ifdef TARGET_ARCH_HAS_KA_RESTORER
8944 act->ka_restorer = restorer;
Peter Maydell78bfef72017-11-06 18:33:26 +00008945#endif
8946 } else {
pbrook53a59602006-03-25 19:31:22 +00008947 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00008948 }
bellard579a97f2007-11-11 14:26:47 +00008949 if (arg3) {
8950 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8951 ret = -TARGET_EFAULT;
8952 goto rt_sigaction_fail;
8953 }
8954 } else
pbrook53a59602006-03-25 19:31:22 +00008955 oact = NULL;
8956 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008957 rt_sigaction_fail:
8958 if (act)
pbrook53a59602006-03-25 19:31:22 +00008959 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008960 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008961 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008962#endif
pbrook53a59602006-03-25 19:31:22 +00008963 }
bellard66fb9762003-03-23 01:06:05 +00008964 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008965#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008966 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008967 {
8968 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008969 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008970 ret = do_sigprocmask(0, NULL, &cur_set);
8971 if (!ret) {
8972 host_to_target_old_sigset(&target_set, &cur_set);
8973 ret = target_set;
8974 }
bellard66fb9762003-03-23 01:06:05 +00008975 }
8976 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008977#endif
8978#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008979 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008980 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02008981 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00008982 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00008983 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008984 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8985 if (!ret) {
8986 host_to_target_old_sigset(&target_set, &oset);
8987 ret = target_set;
8988 }
bellard66fb9762003-03-23 01:06:05 +00008989 }
8990 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008991#endif
thse5febef2007-04-01 18:31:35 +00008992#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008993 case TARGET_NR_sigprocmask:
8994 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008995#if defined(TARGET_ALPHA)
8996 sigset_t set, oldset;
8997 abi_ulong mask;
8998 int how;
8999
9000 switch (arg1) {
9001 case TARGET_SIG_BLOCK:
9002 how = SIG_BLOCK;
9003 break;
9004 case TARGET_SIG_UNBLOCK:
9005 how = SIG_UNBLOCK;
9006 break;
9007 case TARGET_SIG_SETMASK:
9008 how = SIG_SETMASK;
9009 break;
9010 default:
9011 ret = -TARGET_EINVAL;
9012 goto fail;
9013 }
9014 mask = arg2;
9015 target_to_host_old_sigset(&set, &mask);
9016
Peter Maydell3d3efba2016-05-27 15:51:49 +01009017 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07009018 if (!is_error(ret)) {
9019 host_to_target_old_sigset(&mask, &oldset);
9020 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07009021 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07009022 }
9023#else
bellard66fb9762003-03-23 01:06:05 +00009024 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009025 int how;
ths3b46e622007-09-17 08:09:54 +00009026
pbrook53a59602006-03-25 19:31:22 +00009027 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07009028 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00009029 case TARGET_SIG_BLOCK:
9030 how = SIG_BLOCK;
9031 break;
9032 case TARGET_SIG_UNBLOCK:
9033 how = SIG_UNBLOCK;
9034 break;
9035 case TARGET_SIG_SETMASK:
9036 how = SIG_SETMASK;
9037 break;
9038 default:
ths0da46a62007-10-20 20:23:07 +00009039 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009040 goto fail;
9041 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009042 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009043 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009044 target_to_host_old_sigset(&set, p);
9045 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009046 set_ptr = &set;
9047 } else {
9048 how = 0;
9049 set_ptr = NULL;
9050 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009051 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009052 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009053 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009054 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009055 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009056 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009057 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07009058#endif
bellard66fb9762003-03-23 01:06:05 +00009059 }
9060 break;
thse5febef2007-04-01 18:31:35 +00009061#endif
bellard66fb9762003-03-23 01:06:05 +00009062 case TARGET_NR_rt_sigprocmask:
9063 {
9064 int how = arg1;
9065 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00009066
Peter Maydellc8157012016-06-30 14:23:24 +01009067 if (arg4 != sizeof(target_sigset_t)) {
9068 ret = -TARGET_EINVAL;
9069 break;
9070 }
9071
pbrook53a59602006-03-25 19:31:22 +00009072 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009073 switch(how) {
9074 case TARGET_SIG_BLOCK:
9075 how = SIG_BLOCK;
9076 break;
9077 case TARGET_SIG_UNBLOCK:
9078 how = SIG_UNBLOCK;
9079 break;
9080 case TARGET_SIG_SETMASK:
9081 how = SIG_SETMASK;
9082 break;
9083 default:
ths0da46a62007-10-20 20:23:07 +00009084 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009085 goto fail;
9086 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009087 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009088 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009089 target_to_host_sigset(&set, p);
9090 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009091 set_ptr = &set;
9092 } else {
9093 how = 0;
9094 set_ptr = NULL;
9095 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009096 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009097 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009098 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009099 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009100 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009101 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009102 }
9103 }
9104 break;
thse5febef2007-04-01 18:31:35 +00009105#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00009106 case TARGET_NR_sigpending:
9107 {
9108 sigset_t set;
9109 ret = get_errno(sigpending(&set));
9110 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009111 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009112 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009113 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009114 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009115 }
9116 }
9117 break;
thse5febef2007-04-01 18:31:35 +00009118#endif
bellard66fb9762003-03-23 01:06:05 +00009119 case TARGET_NR_rt_sigpending:
9120 {
9121 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01009122
9123 /* Yes, this check is >, not != like most. We follow the kernel's
9124 * logic and it does it like this because it implements
9125 * NR_sigpending through the same code path, and in that case
9126 * the old_sigset_t is smaller in size.
9127 */
9128 if (arg2 > sizeof(target_sigset_t)) {
9129 ret = -TARGET_EINVAL;
9130 break;
9131 }
9132
bellard66fb9762003-03-23 01:06:05 +00009133 ret = get_errno(sigpending(&set));
9134 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009135 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009136 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009137 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009138 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009139 }
9140 }
9141 break;
thse5febef2007-04-01 18:31:35 +00009142#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00009143 case TARGET_NR_sigsuspend:
9144 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009145 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07009146#if defined(TARGET_ALPHA)
9147 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009148 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009149#else
Anthony Liguoric227f092009-10-01 16:12:16 -05009150 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009151 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009152 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009153 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009154#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01009155 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9156 SIGSET_T_SIZE));
9157 if (ret != -TARGET_ERESTARTSYS) {
9158 ts->in_sigsuspend = 1;
9159 }
bellard66fb9762003-03-23 01:06:05 +00009160 }
9161 break;
thse5febef2007-04-01 18:31:35 +00009162#endif
bellard66fb9762003-03-23 01:06:05 +00009163 case TARGET_NR_rt_sigsuspend:
9164 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009165 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01009166
9167 if (arg2 != sizeof(target_sigset_t)) {
9168 ret = -TARGET_EINVAL;
9169 break;
9170 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009171 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009172 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009173 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009174 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009175 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9176 SIGSET_T_SIZE));
9177 if (ret != -TARGET_ERESTARTSYS) {
9178 ts->in_sigsuspend = 1;
9179 }
bellard66fb9762003-03-23 01:06:05 +00009180 }
9181 break;
9182 case TARGET_NR_rt_sigtimedwait:
9183 {
bellard66fb9762003-03-23 01:06:05 +00009184 sigset_t set;
9185 struct timespec uts, *puts;
9186 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00009187
Peter Maydellc8157012016-06-30 14:23:24 +01009188 if (arg4 != sizeof(target_sigset_t)) {
9189 ret = -TARGET_EINVAL;
9190 break;
9191 }
9192
Anthony Liguoric227f092009-10-01 16:12:16 -05009193 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009194 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009195 target_to_host_sigset(&set, p);
9196 unlock_user(p, arg1, 0);
9197 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00009198 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00009199 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00009200 } else {
9201 puts = NULL;
9202 }
Peter Maydellb3f82332016-06-06 19:58:08 +01009203 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9204 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01009205 if (!is_error(ret)) {
9206 if (arg2) {
9207 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
9208 0);
9209 if (!p) {
9210 goto efault;
9211 }
9212 host_to_target_siginfo(p, &uinfo);
9213 unlock_user(p, arg2, sizeof(target_siginfo_t));
9214 }
9215 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00009216 }
9217 }
9218 break;
9219 case TARGET_NR_rt_sigqueueinfo:
9220 {
9221 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009222
9223 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9224 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00009225 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01009226 }
pbrook53a59602006-03-25 19:31:22 +00009227 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009228 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009229 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9230 }
9231 break;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009232 case TARGET_NR_rt_tgsigqueueinfo:
9233 {
9234 siginfo_t uinfo;
9235
9236 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9237 if (!p) {
9238 goto efault;
9239 }
9240 target_to_host_siginfo(&uinfo, p);
9241 unlock_user(p, arg4, 0);
9242 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9243 }
9244 break;
thse5febef2007-04-01 18:31:35 +00009245#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009246 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009247 if (block_signals()) {
9248 ret = -TARGET_ERESTARTSYS;
9249 } else {
9250 ret = do_sigreturn(cpu_env);
9251 }
bellard66fb9762003-03-23 01:06:05 +00009252 break;
thse5febef2007-04-01 18:31:35 +00009253#endif
bellard66fb9762003-03-23 01:06:05 +00009254 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009255 if (block_signals()) {
9256 ret = -TARGET_ERESTARTSYS;
9257 } else {
9258 ret = do_rt_sigreturn(cpu_env);
9259 }
bellard66fb9762003-03-23 01:06:05 +00009260 break;
bellard31e31b82003-02-18 22:55:36 +00009261 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009262 if (!(p = lock_user_string(arg1)))
9263 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009264 ret = get_errno(sethostname(p, arg2));
9265 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009266 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009267#ifdef TARGET_NR_setrlimit
bellard31e31b82003-02-18 22:55:36 +00009268 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009269 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009270 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009271 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009272 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009273 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
9274 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009275 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9276 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009277 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00009278 ret = get_errno(setrlimit(resource, &rlim));
9279 }
9280 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009281#endif
9282#ifdef TARGET_NR_getrlimit
bellard31e31b82003-02-18 22:55:36 +00009283 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009284 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009285 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009286 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009287 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009288
bellard9de5e442003-03-23 16:49:39 +00009289 ret = get_errno(getrlimit(resource, &rlim));
9290 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009291 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9292 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009293 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9294 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009295 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009296 }
9297 }
9298 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009299#endif
bellard31e31b82003-02-18 22:55:36 +00009300 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009301 {
9302 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009303 ret = get_errno(getrusage(arg1, &rusage));
9304 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009305 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009306 }
9307 }
9308 break;
bellard31e31b82003-02-18 22:55:36 +00009309 case TARGET_NR_gettimeofday:
9310 {
bellard31e31b82003-02-18 22:55:36 +00009311 struct timeval tv;
9312 ret = get_errno(gettimeofday(&tv, NULL));
9313 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00009314 if (copy_to_user_timeval(arg1, &tv))
9315 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009316 }
9317 }
9318 break;
9319 case TARGET_NR_settimeofday:
9320 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009321 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009322 struct timezone tz, *ptz = NULL;
9323
Paul Burtonb67d8032014-06-22 11:25:41 +01009324 if (arg1) {
9325 if (copy_from_user_timeval(&tv, arg1)) {
9326 goto efault;
9327 }
9328 ptv = &tv;
9329 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009330
9331 if (arg2) {
9332 if (copy_from_user_timezone(&tz, arg2)) {
9333 goto efault;
9334 }
9335 ptz = &tz;
9336 }
9337
Paul Burtonb67d8032014-06-22 11:25:41 +01009338 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009339 }
9340 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009341#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009342 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009343#if defined(TARGET_WANT_NI_OLD_SELECT)
9344 /* some architectures used to have old_select here
9345 * but now ENOSYS it.
9346 */
9347 ret = -TARGET_ENOSYS;
9348#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9349 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009350#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009351 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009352#endif
bellardf2674e32003-07-09 12:26:09 +00009353 break;
bellard048f6b42005-11-26 18:47:20 +00009354#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009355#ifdef TARGET_NR_pselect6
9356 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04009357 {
9358 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
9359 fd_set rfds, wfds, efds;
9360 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
9361 struct timespec ts, *ts_ptr;
9362
9363 /*
9364 * The 6th arg is actually two args smashed together,
9365 * so we cannot use the C library.
9366 */
9367 sigset_t set;
9368 struct {
9369 sigset_t *set;
9370 size_t size;
9371 } sig, *sig_ptr;
9372
9373 abi_ulong arg_sigset, arg_sigsize, *arg7;
9374 target_sigset_t *target_sigset;
9375
9376 n = arg1;
9377 rfd_addr = arg2;
9378 wfd_addr = arg3;
9379 efd_addr = arg4;
9380 ts_addr = arg5;
9381
9382 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9383 if (ret) {
9384 goto fail;
9385 }
9386 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9387 if (ret) {
9388 goto fail;
9389 }
9390 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9391 if (ret) {
9392 goto fail;
9393 }
9394
9395 /*
9396 * This takes a timespec, and not a timeval, so we cannot
9397 * use the do_select() helper ...
9398 */
9399 if (ts_addr) {
9400 if (target_to_host_timespec(&ts, ts_addr)) {
9401 goto efault;
9402 }
9403 ts_ptr = &ts;
9404 } else {
9405 ts_ptr = NULL;
9406 }
9407
9408 /* Extract the two packed args for the sigset */
9409 if (arg6) {
9410 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009411 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009412
9413 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9414 if (!arg7) {
9415 goto efault;
9416 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009417 arg_sigset = tswapal(arg7[0]);
9418 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009419 unlock_user(arg7, arg6, 0);
9420
9421 if (arg_sigset) {
9422 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009423 if (arg_sigsize != sizeof(*target_sigset)) {
9424 /* Like the kernel, we enforce correct size sigsets */
9425 ret = -TARGET_EINVAL;
9426 goto fail;
9427 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009428 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9429 sizeof(*target_sigset), 1);
9430 if (!target_sigset) {
9431 goto efault;
9432 }
9433 target_to_host_sigset(&set, target_sigset);
9434 unlock_user(target_sigset, arg_sigset, 0);
9435 } else {
9436 sig.set = NULL;
9437 }
9438 } else {
9439 sig_ptr = NULL;
9440 }
9441
Peter Maydell6df9d382016-05-12 18:47:51 +01009442 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9443 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009444
9445 if (!is_error(ret)) {
9446 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9447 goto efault;
9448 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9449 goto efault;
9450 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9451 goto efault;
9452
9453 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9454 goto efault;
9455 }
9456 }
9457 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009458#endif
Chen Gang704eff62015-08-21 05:37:33 +08009459#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009460 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009461 {
9462 void *p2;
9463 p = lock_user_string(arg1);
9464 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009465 if (!p || !p2)
9466 ret = -TARGET_EFAULT;
9467 else
9468 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009469 unlock_user(p2, arg2, 0);
9470 unlock_user(p, arg1, 0);
9471 }
bellard31e31b82003-02-18 22:55:36 +00009472 break;
Chen Gang704eff62015-08-21 05:37:33 +08009473#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009474#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009475 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009476 {
bellard579a97f2007-11-11 14:26:47 +00009477 void *p2;
thsf0b62432007-09-24 09:25:40 +00009478 p = lock_user_string(arg1);
9479 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009480 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009481 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009482 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009483 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009484 unlock_user(p2, arg3, 0);
9485 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009486 }
9487 break;
9488#endif
bellardebc05482003-09-30 21:08:41 +00009489#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009490 case TARGET_NR_oldlstat:
9491 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009492#endif
Chen Gang704eff62015-08-21 05:37:33 +08009493#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009494 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009495 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009496 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009497 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009498 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009499 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009500 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009501 } else if (!arg3) {
9502 /* Short circuit this for the magic exe check. */
9503 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009504 } else if (is_proc_myself((const char *)p, "exe")) {
9505 char real[PATH_MAX], *temp;
9506 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009507 /* Return value is # of bytes that we wrote to the buffer. */
9508 if (temp == NULL) {
9509 ret = get_errno(-1);
9510 } else {
9511 /* Don't worry about sign mismatch as earlier mapping
9512 * logic would have thrown a bad address error. */
9513 ret = MIN(strlen(real), arg3);
9514 /* We cannot NUL terminate the string. */
9515 memcpy(p2, real, ret);
9516 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009517 } else {
9518 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009519 }
pbrook53a59602006-03-25 19:31:22 +00009520 unlock_user(p2, arg2, ret);
9521 unlock_user(p, arg1, 0);
9522 }
bellard31e31b82003-02-18 22:55:36 +00009523 break;
Chen Gang704eff62015-08-21 05:37:33 +08009524#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009525#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009526 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009527 {
bellard579a97f2007-11-11 14:26:47 +00009528 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009529 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009530 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009531 if (!p || !p2) {
9532 ret = -TARGET_EFAULT;
9533 } else if (is_proc_myself((const char *)p, "exe")) {
9534 char real[PATH_MAX], *temp;
9535 temp = realpath(exec_path, real);
9536 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9537 snprintf((char *)p2, arg4, "%s", real);
9538 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009539 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009540 }
bellard579a97f2007-11-11 14:26:47 +00009541 unlock_user(p2, arg3, ret);
9542 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009543 }
9544 break;
9545#endif
thse5febef2007-04-01 18:31:35 +00009546#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009547 case TARGET_NR_uselib:
9548 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009549#endif
9550#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009551 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009552 if (!(p = lock_user_string(arg1)))
9553 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009554 ret = get_errno(swapon(p, arg2));
9555 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009556 break;
thse5febef2007-04-01 18:31:35 +00009557#endif
bellard31e31b82003-02-18 22:55:36 +00009558 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009559 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9560 /* arg4 must be ignored in all other cases */
9561 p = lock_user_string(arg4);
9562 if (!p) {
9563 goto efault;
9564 }
9565 ret = get_errno(reboot(arg1, arg2, arg3, p));
9566 unlock_user(p, arg4, 0);
9567 } else {
9568 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9569 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009570 break;
thse5febef2007-04-01 18:31:35 +00009571#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009572 case TARGET_NR_readdir:
9573 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009574#endif
9575#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009576 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009577#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9578 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009579 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9580 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009581 {
blueswir1992f48a2007-10-14 16:27:31 +00009582 abi_ulong *v;
9583 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009584 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9585 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009586 v1 = tswapal(v[0]);
9587 v2 = tswapal(v[1]);
9588 v3 = tswapal(v[2]);
9589 v4 = tswapal(v[3]);
9590 v5 = tswapal(v[4]);
9591 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009592 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009593 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009594 target_to_host_bitmask(v4, mmap_flags_tbl),
9595 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009596 }
bellard31e31b82003-02-18 22:55:36 +00009597#else
ths5fafdf22007-09-16 21:08:06 +00009598 ret = get_errno(target_mmap(arg1, arg2, arg3,
9599 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009600 arg5,
9601 arg6));
bellard31e31b82003-02-18 22:55:36 +00009602#endif
bellard6fb883e2003-07-09 17:12:39 +00009603 break;
thse5febef2007-04-01 18:31:35 +00009604#endif
bellarda315a142005-01-30 22:59:18 +00009605#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009606 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009607#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009608#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009609#endif
ths5fafdf22007-09-16 21:08:06 +00009610 ret = get_errno(target_mmap(arg1, arg2, arg3,
9611 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009612 arg5,
bellardc573ff62004-01-04 15:51:36 +00009613 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009614 break;
bellarda315a142005-01-30 22:59:18 +00009615#endif
bellard31e31b82003-02-18 22:55:36 +00009616 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009617 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009618 break;
bellard9de5e442003-03-23 16:49:39 +00009619 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009620 {
Andreas Färber0429a972013-08-26 18:14:44 +02009621 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009622 /* Special hack to detect libc making the stack executable. */
9623 if ((arg3 & PROT_GROWSDOWN)
9624 && arg1 >= ts->info->stack_limit
9625 && arg1 <= ts->info->start_stack) {
9626 arg3 &= ~PROT_GROWSDOWN;
9627 arg2 = arg2 + arg1 - ts->info->stack_limit;
9628 arg1 = ts->info->stack_limit;
9629 }
9630 }
bellard54936002003-05-13 00:25:15 +00009631 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009632 break;
thse5febef2007-04-01 18:31:35 +00009633#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009634 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009635 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009636 break;
thse5febef2007-04-01 18:31:35 +00009637#endif
pbrook53a59602006-03-25 19:31:22 +00009638 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009639#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009640 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009641 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009642 break;
thse5febef2007-04-01 18:31:35 +00009643#endif
9644#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009645 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009646 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009647 break;
thse5febef2007-04-01 18:31:35 +00009648#endif
9649#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009650 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009651 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009652 break;
thse5febef2007-04-01 18:31:35 +00009653#endif
9654#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009655 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009656 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009657 break;
thse5febef2007-04-01 18:31:35 +00009658#endif
9659#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009660 case TARGET_NR_munlockall:
9661 ret = get_errno(munlockall());
9662 break;
thse5febef2007-04-01 18:31:35 +00009663#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009664#ifdef TARGET_NR_truncate
bellard31e31b82003-02-18 22:55:36 +00009665 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009666 if (!(p = lock_user_string(arg1)))
9667 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009668 ret = get_errno(truncate(p, arg2));
9669 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009670 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009671#endif
9672#ifdef TARGET_NR_ftruncate
bellard31e31b82003-02-18 22:55:36 +00009673 case TARGET_NR_ftruncate:
9674 ret = get_errno(ftruncate(arg1, arg2));
9675 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009676#endif
bellard31e31b82003-02-18 22:55:36 +00009677 case TARGET_NR_fchmod:
9678 ret = get_errno(fchmod(arg1, arg2));
9679 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009680#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009681 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009682 if (!(p = lock_user_string(arg2)))
9683 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009684 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009685 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009686 break;
9687#endif
bellard31e31b82003-02-18 22:55:36 +00009688 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009689 /* Note that negative values are valid for getpriority, so we must
9690 differentiate based on errno settings. */
9691 errno = 0;
9692 ret = getpriority(arg1, arg2);
9693 if (ret == -1 && errno != 0) {
9694 ret = -host_to_target_errno(errno);
9695 break;
9696 }
9697#ifdef TARGET_ALPHA
9698 /* Return value is the unbiased priority. Signal no error. */
9699 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9700#else
9701 /* Return value is a biased priority to avoid negative numbers. */
9702 ret = 20 - ret;
9703#endif
bellard31e31b82003-02-18 22:55:36 +00009704 break;
9705 case TARGET_NR_setpriority:
9706 ret = get_errno(setpriority(arg1, arg2, arg3));
9707 break;
bellardebc05482003-09-30 21:08:41 +00009708#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009709 case TARGET_NR_profil:
9710 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009711#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009712#ifdef TARGET_NR_statfs
bellard31e31b82003-02-18 22:55:36 +00009713 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009714 if (!(p = lock_user_string(arg1)))
9715 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009716 ret = get_errno(statfs(path(p), &stfs));
9717 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009718 convert_statfs:
9719 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009720 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009721
bellard579a97f2007-11-11 14:26:47 +00009722 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9723 goto efault;
9724 __put_user(stfs.f_type, &target_stfs->f_type);
9725 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9726 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9727 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9728 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9729 __put_user(stfs.f_files, &target_stfs->f_files);
9730 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9731 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9732 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9733 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009734 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05009735#ifdef _STATFS_F_FLAGS
9736 __put_user(stfs.f_flags, &target_stfs->f_flags);
9737#else
9738 __put_user(0, &target_stfs->f_flags);
9739#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009740 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009741 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009742 }
9743 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009744#endif
9745#ifdef TARGET_NR_fstatfs
bellard31e31b82003-02-18 22:55:36 +00009746 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009747 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009748 goto convert_statfs;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009749#endif
bellard56c8f682005-11-28 22:28:41 +00009750#ifdef TARGET_NR_statfs64
9751 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009752 if (!(p = lock_user_string(arg1)))
9753 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009754 ret = get_errno(statfs(path(p), &stfs));
9755 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009756 convert_statfs64:
9757 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009758 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009759
bellard579a97f2007-11-11 14:26:47 +00009760 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9761 goto efault;
9762 __put_user(stfs.f_type, &target_stfs->f_type);
9763 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9764 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9765 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9766 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9767 __put_user(stfs.f_files, &target_stfs->f_files);
9768 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9769 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9770 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9771 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009772 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9773 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009774 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009775 }
9776 break;
9777 case TARGET_NR_fstatfs64:
9778 ret = get_errno(fstatfs(arg1, &stfs));
9779 goto convert_statfs64;
9780#endif
bellardebc05482003-09-30 21:08:41 +00009781#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009782 case TARGET_NR_ioperm:
9783 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009784#endif
thse5febef2007-04-01 18:31:35 +00009785#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009786 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009787 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009788 break;
thse5febef2007-04-01 18:31:35 +00009789#endif
bellard3532fa72006-06-24 15:06:03 +00009790#ifdef TARGET_NR_accept
9791 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009792 ret = do_accept4(arg1, arg2, arg3, 0);
9793 break;
9794#endif
9795#ifdef TARGET_NR_accept4
9796 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009797 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009798 break;
9799#endif
9800#ifdef TARGET_NR_bind
9801 case TARGET_NR_bind:
9802 ret = do_bind(arg1, arg2, arg3);
9803 break;
9804#endif
9805#ifdef TARGET_NR_connect
9806 case TARGET_NR_connect:
9807 ret = do_connect(arg1, arg2, arg3);
9808 break;
9809#endif
9810#ifdef TARGET_NR_getpeername
9811 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009812 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009813 break;
9814#endif
9815#ifdef TARGET_NR_getsockname
9816 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009817 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009818 break;
9819#endif
9820#ifdef TARGET_NR_getsockopt
9821 case TARGET_NR_getsockopt:
9822 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9823 break;
9824#endif
9825#ifdef TARGET_NR_listen
9826 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009827 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009828 break;
9829#endif
9830#ifdef TARGET_NR_recv
9831 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009832 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009833 break;
9834#endif
9835#ifdef TARGET_NR_recvfrom
9836 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009837 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009838 break;
9839#endif
9840#ifdef TARGET_NR_recvmsg
9841 case TARGET_NR_recvmsg:
9842 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9843 break;
9844#endif
9845#ifdef TARGET_NR_send
9846 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009847 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009848 break;
9849#endif
9850#ifdef TARGET_NR_sendmsg
9851 case TARGET_NR_sendmsg:
9852 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9853 break;
9854#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009855#ifdef TARGET_NR_sendmmsg
9856 case TARGET_NR_sendmmsg:
9857 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9858 break;
9859 case TARGET_NR_recvmmsg:
9860 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9861 break;
9862#endif
bellard3532fa72006-06-24 15:06:03 +00009863#ifdef TARGET_NR_sendto
9864 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009865 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009866 break;
9867#endif
9868#ifdef TARGET_NR_shutdown
9869 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009870 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009871 break;
9872#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009873#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9874 case TARGET_NR_getrandom:
9875 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9876 if (!p) {
9877 goto efault;
9878 }
9879 ret = get_errno(getrandom(p, arg2, arg3));
9880 unlock_user(p, arg1, ret);
9881 break;
9882#endif
bellard3532fa72006-06-24 15:06:03 +00009883#ifdef TARGET_NR_socket
9884 case TARGET_NR_socket:
9885 ret = do_socket(arg1, arg2, arg3);
9886 break;
9887#endif
9888#ifdef TARGET_NR_socketpair
9889 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009890 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009891 break;
9892#endif
9893#ifdef TARGET_NR_setsockopt
9894 case TARGET_NR_setsockopt:
9895 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9896 break;
9897#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009898#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009899 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009900 {
9901 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009902
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009903 switch (arg1) {
9904 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9905 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9906 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9907 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9908 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9909 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9910 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9911 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9912 {
9913 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9914 }
9915 break;
9916 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9917 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9918 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9919 {
9920 ret = -TARGET_EINVAL;
9921 if (len < 0) {
9922 goto fail;
9923 }
9924 ret = 0;
9925 if (len == 0) {
9926 break;
9927 }
9928 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9929 if (!p) {
9930 ret = -TARGET_EFAULT;
9931 goto fail;
9932 }
9933 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9934 unlock_user(p, arg2, arg3);
9935 }
9936 break;
9937 default:
9938 ret = -EINVAL;
9939 break;
9940 }
9941 }
9942 break;
9943#endif
bellard31e31b82003-02-18 22:55:36 +00009944 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009945 {
bellard66fb9762003-03-23 01:06:05 +00009946 struct itimerval value, ovalue, *pvalue;
9947
pbrook53a59602006-03-25 19:31:22 +00009948 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009949 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009950 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9951 || copy_from_user_timeval(&pvalue->it_value,
9952 arg2 + sizeof(struct target_timeval)))
9953 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009954 } else {
9955 pvalue = NULL;
9956 }
9957 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009958 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009959 if (copy_to_user_timeval(arg3,
9960 &ovalue.it_interval)
9961 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9962 &ovalue.it_value))
9963 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009964 }
9965 }
9966 break;
bellard31e31b82003-02-18 22:55:36 +00009967 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009968 {
bellard66fb9762003-03-23 01:06:05 +00009969 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009970
bellard66fb9762003-03-23 01:06:05 +00009971 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009972 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009973 if (copy_to_user_timeval(arg2,
9974 &value.it_interval)
9975 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9976 &value.it_value))
9977 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009978 }
9979 }
9980 break;
Chen Gang704eff62015-08-21 05:37:33 +08009981#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009982 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009983 if (!(p = lock_user_string(arg1)))
9984 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009985 ret = get_errno(stat(path(p), &st));
9986 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009987 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009988#endif
9989#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009990 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009991 if (!(p = lock_user_string(arg1)))
9992 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009993 ret = get_errno(lstat(path(p), &st));
9994 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009995 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009996#endif
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +02009997#ifdef TARGET_NR_fstat
bellard31e31b82003-02-18 22:55:36 +00009998 case TARGET_NR_fstat:
9999 {
10000 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +080010001#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +000010002 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +080010003#endif
bellard31e31b82003-02-18 22:55:36 +000010004 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010005 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +000010006
bellard579a97f2007-11-11 14:26:47 +000010007 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
10008 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +020010009 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +000010010 __put_user(st.st_dev, &target_st->st_dev);
10011 __put_user(st.st_ino, &target_st->st_ino);
10012 __put_user(st.st_mode, &target_st->st_mode);
10013 __put_user(st.st_uid, &target_st->st_uid);
10014 __put_user(st.st_gid, &target_st->st_gid);
10015 __put_user(st.st_nlink, &target_st->st_nlink);
10016 __put_user(st.st_rdev, &target_st->st_rdev);
10017 __put_user(st.st_size, &target_st->st_size);
10018 __put_user(st.st_blksize, &target_st->st_blksize);
10019 __put_user(st.st_blocks, &target_st->st_blocks);
10020 __put_user(st.st_atime, &target_st->target_st_atime);
10021 __put_user(st.st_mtime, &target_st->target_st_mtime);
10022 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +000010023 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +000010024 }
10025 }
10026 break;
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020010027#endif
bellardebc05482003-09-30 21:08:41 +000010028#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +000010029 case TARGET_NR_olduname:
10030 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010031#endif
10032#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +000010033 case TARGET_NR_iopl:
10034 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010035#endif
bellard31e31b82003-02-18 22:55:36 +000010036 case TARGET_NR_vhangup:
10037 ret = get_errno(vhangup());
10038 break;
bellardebc05482003-09-30 21:08:41 +000010039#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +000010040 case TARGET_NR_idle:
10041 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010042#endif
bellard42ad6ae2005-01-03 22:48:11 +000010043#ifdef TARGET_NR_syscall
10044 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +010010045 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
10046 arg6, arg7, arg8, 0);
10047 break;
bellard42ad6ae2005-01-03 22:48:11 +000010048#endif
bellard31e31b82003-02-18 22:55:36 +000010049 case TARGET_NR_wait4:
10050 {
10051 int status;
blueswir1992f48a2007-10-14 16:27:31 +000010052 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +000010053 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +000010054 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +020010055 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +000010056 if (target_rusage)
10057 rusage_ptr = &rusage;
10058 else
10059 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +010010060 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +000010061 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +010010062 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +000010063 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +000010064 if (put_user_s32(status, status_ptr))
10065 goto efault;
bellard31e31b82003-02-18 22:55:36 +000010066 }
Petar Jovanovica39fb272014-04-08 19:24:30 +020010067 if (target_rusage) {
10068 rusage_err = host_to_target_rusage(target_rusage, &rusage);
10069 if (rusage_err) {
10070 ret = rusage_err;
10071 }
10072 }
bellard31e31b82003-02-18 22:55:36 +000010073 }
10074 }
10075 break;
thse5febef2007-04-01 18:31:35 +000010076#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +000010077 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +000010078 if (!(p = lock_user_string(arg1)))
10079 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010080 ret = get_errno(swapoff(p));
10081 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010082 break;
thse5febef2007-04-01 18:31:35 +000010083#endif
bellard31e31b82003-02-18 22:55:36 +000010084 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +000010085 {
pbrook53a59602006-03-25 19:31:22 +000010086 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +000010087 struct sysinfo value;
10088 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +000010089 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +000010090 {
bellard579a97f2007-11-11 14:26:47 +000010091 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
10092 goto efault;
bellarda5448a72004-06-19 16:59:03 +000010093 __put_user(value.uptime, &target_value->uptime);
10094 __put_user(value.loads[0], &target_value->loads[0]);
10095 __put_user(value.loads[1], &target_value->loads[1]);
10096 __put_user(value.loads[2], &target_value->loads[2]);
10097 __put_user(value.totalram, &target_value->totalram);
10098 __put_user(value.freeram, &target_value->freeram);
10099 __put_user(value.sharedram, &target_value->sharedram);
10100 __put_user(value.bufferram, &target_value->bufferram);
10101 __put_user(value.totalswap, &target_value->totalswap);
10102 __put_user(value.freeswap, &target_value->freeswap);
10103 __put_user(value.procs, &target_value->procs);
10104 __put_user(value.totalhigh, &target_value->totalhigh);
10105 __put_user(value.freehigh, &target_value->freehigh);
10106 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +000010107 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +000010108 }
10109 }
10110 break;
thse5febef2007-04-01 18:31:35 +000010111#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +000010112 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +010010113 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
10114 break;
thse5febef2007-04-01 18:31:35 +000010115#endif
aurel32e5289082009-04-18 16:16:12 +000010116#ifdef TARGET_NR_semget
10117 case TARGET_NR_semget:
10118 ret = get_errno(semget(arg1, arg2, arg3));
10119 break;
10120#endif
10121#ifdef TARGET_NR_semop
10122 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +000010123 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +000010124 break;
10125#endif
10126#ifdef TARGET_NR_semctl
10127 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +010010128 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +000010129 break;
10130#endif
aurel32eeb438c2008-10-13 21:08:55 +000010131#ifdef TARGET_NR_msgctl
10132 case TARGET_NR_msgctl:
10133 ret = do_msgctl(arg1, arg2, arg3);
10134 break;
10135#endif
10136#ifdef TARGET_NR_msgget
10137 case TARGET_NR_msgget:
10138 ret = get_errno(msgget(arg1, arg2));
10139 break;
10140#endif
10141#ifdef TARGET_NR_msgrcv
10142 case TARGET_NR_msgrcv:
10143 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
10144 break;
10145#endif
10146#ifdef TARGET_NR_msgsnd
10147 case TARGET_NR_msgsnd:
10148 ret = do_msgsnd(arg1, arg2, arg3, arg4);
10149 break;
10150#endif
Riku Voipio88a8c982009-04-03 10:42:00 +030010151#ifdef TARGET_NR_shmget
10152 case TARGET_NR_shmget:
10153 ret = get_errno(shmget(arg1, arg2, arg3));
10154 break;
10155#endif
10156#ifdef TARGET_NR_shmctl
10157 case TARGET_NR_shmctl:
10158 ret = do_shmctl(arg1, arg2, arg3);
10159 break;
10160#endif
10161#ifdef TARGET_NR_shmat
10162 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +010010163 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030010164 break;
10165#endif
10166#ifdef TARGET_NR_shmdt
10167 case TARGET_NR_shmdt:
10168 ret = do_shmdt(arg1);
10169 break;
10170#endif
bellard31e31b82003-02-18 22:55:36 +000010171 case TARGET_NR_fsync:
10172 ret = get_errno(fsync(arg1));
10173 break;
bellard31e31b82003-02-18 22:55:36 +000010174 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +010010175 /* Linux manages to have three different orderings for its
10176 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
10177 * match the kernel's CONFIG_CLONE_* settings.
10178 * Microblaze is further special in that it uses a sixth
10179 * implicit argument to clone for the TLS pointer.
10180 */
10181#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020010182 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010010183#elif defined(TARGET_CLONE_BACKWARDS)
10184 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
10185#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010186 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010187#else
Peter Maydell4ce62432013-07-16 18:44:57 +010010188 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010189#endif
bellard1b6b0292003-03-22 17:31:38 +000010190 break;
bellardec86b0f2003-04-11 00:15:04 +000010191#ifdef __NR_exit_group
10192 /* new thread calls */
10193 case TARGET_NR_exit_group:
Alex Bennée708b6a62018-06-22 17:09:10 +010010194 preexit_cleanup(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +000010195 ret = get_errno(exit_group(arg1));
10196 break;
10197#endif
bellard31e31b82003-02-18 22:55:36 +000010198 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000010199 if (!(p = lock_user_string(arg1)))
10200 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010201 ret = get_errno(setdomainname(p, arg2));
10202 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010203 break;
10204 case TARGET_NR_uname:
10205 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000010206 {
10207 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000010208
bellard579a97f2007-11-11 14:26:47 +000010209 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
10210 goto efault;
bellard29e619b2004-09-13 21:41:04 +000010211 ret = get_errno(sys_uname(buf));
10212 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010010213 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000010214 emulated. */
Philippe Mathieu-Daudé871f95c2017-07-24 15:27:47 -030010215 g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
10216 sizeof(buf->machine));
pbrookc5937222006-05-14 11:30:38 +000010217 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010010218 if (qemu_uname_release && *qemu_uname_release) {
10219 g_strlcpy(buf->release, qemu_uname_release,
10220 sizeof(buf->release));
10221 }
bellard29e619b2004-09-13 21:41:04 +000010222 }
pbrook53a59602006-03-25 19:31:22 +000010223 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000010224 }
bellard31e31b82003-02-18 22:55:36 +000010225 break;
bellard6dbad632003-03-16 18:05:05 +000010226#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000010227 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +000010228 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +000010229 break;
j_mayer84409dd2007-04-06 08:56:50 +000010230#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000010231 case TARGET_NR_vm86old:
10232 goto unimplemented;
10233 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +000010234 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000010235 break;
10236#endif
j_mayer84409dd2007-04-06 08:56:50 +000010237#endif
bellard31e31b82003-02-18 22:55:36 +000010238 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010239 {
10240 struct timex host_buf;
10241
10242 if (target_to_host_timex(&host_buf, arg1) != 0) {
10243 goto efault;
10244 }
10245 ret = get_errno(adjtimex(&host_buf));
10246 if (!is_error(ret)) {
10247 if (host_to_target_timex(arg1, &host_buf) != 0) {
10248 goto efault;
10249 }
10250 }
10251 }
10252 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010253#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10254 case TARGET_NR_clock_adjtime:
10255 {
10256 struct timex htx, *phtx = &htx;
10257
10258 if (target_to_host_timex(phtx, arg2) != 0) {
10259 goto efault;
10260 }
10261 ret = get_errno(clock_adjtime(arg1, phtx));
10262 if (!is_error(ret) && phtx) {
10263 if (host_to_target_timex(arg2, phtx) != 0) {
10264 goto efault;
10265 }
10266 }
10267 }
10268 break;
10269#endif
thse5febef2007-04-01 18:31:35 +000010270#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +000010271 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +000010272#endif
bellard31e31b82003-02-18 22:55:36 +000010273 case TARGET_NR_init_module:
10274 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +000010275#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +000010276 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +000010277#endif
bellard31e31b82003-02-18 22:55:36 +000010278 goto unimplemented;
10279 case TARGET_NR_quotactl:
10280 goto unimplemented;
10281 case TARGET_NR_getpgid:
10282 ret = get_errno(getpgid(arg1));
10283 break;
10284 case TARGET_NR_fchdir:
10285 ret = get_errno(fchdir(arg1));
10286 break;
j_mayer84409dd2007-04-06 08:56:50 +000010287#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +000010288 case TARGET_NR_bdflush:
10289 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +000010290#endif
thse5febef2007-04-01 18:31:35 +000010291#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +000010292 case TARGET_NR_sysfs:
10293 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010294#endif
bellard31e31b82003-02-18 22:55:36 +000010295 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +000010296 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +000010297 break;
thse5febef2007-04-01 18:31:35 +000010298#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +000010299 case TARGET_NR_afs_syscall:
10300 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010301#endif
j_mayer7a3148a2007-04-05 07:13:51 +000010302#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010303 case TARGET_NR__llseek:
10304 {
10305 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010306#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010307 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010308 if (res == -1) {
10309 ret = get_errno(res);
10310 } else {
10311 ret = 0;
10312 }
10313#else
bellard31e31b82003-02-18 22:55:36 +000010314 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010315#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010316 if ((ret == 0) && put_user_s64(res, arg4)) {
10317 goto efault;
10318 }
bellard31e31b82003-02-18 22:55:36 +000010319 }
10320 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010321#endif
Chen Gang704eff62015-08-21 05:37:33 +080010322#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010323 case TARGET_NR_getdents:
Peter Maydell2b3f64c2018-04-19 13:57:40 +010010324#ifdef EMULATE_GETDENTS_WITH_GETDENTS
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010325#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010326 {
pbrook53a59602006-03-25 19:31:22 +000010327 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010328 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010329 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010330
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010331 dirp = g_try_malloc(count);
10332 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +000010333 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010334 goto fail;
10335 }
ths3b46e622007-09-17 08:09:54 +000010336
bellard4add45b2003-06-05 01:52:59 +000010337 ret = get_errno(sys_getdents(arg1, dirp, count));
10338 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010339 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010340 struct target_dirent *tde;
10341 int len = ret;
10342 int reclen, treclen;
10343 int count1, tnamelen;
10344
10345 count1 = 0;
10346 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010347 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10348 goto efault;
bellard4add45b2003-06-05 01:52:59 +000010349 tde = target_dirp;
10350 while (len > 0) {
10351 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010352 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10353 assert(tnamelen >= 0);
10354 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10355 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010356 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010357 tde->d_ino = tswapal(de->d_ino);
10358 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010359 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010360 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010361 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010362 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010363 count1 += treclen;
10364 }
10365 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010366 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010367 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010368 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010369 }
10370#else
bellard31e31b82003-02-18 22:55:36 +000010371 {
aurel326556a832008-10-13 21:08:17 +000010372 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010373 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010374
bellard579a97f2007-11-11 14:26:47 +000010375 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10376 goto efault;
bellard72f03902003-02-18 23:33:18 +000010377 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010378 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010379 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010380 int len = ret;
10381 int reclen;
10382 de = dirp;
10383 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010384 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010385 if (reclen > len)
10386 break;
bellard8083a3e2003-03-24 23:12:16 +000010387 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010388 tswapls(&de->d_ino);
10389 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010390 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010391 len -= reclen;
10392 }
10393 }
pbrook53a59602006-03-25 19:31:22 +000010394 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010395 }
bellard4add45b2003-06-05 01:52:59 +000010396#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010397#else
10398 /* Implement getdents in terms of getdents64 */
10399 {
10400 struct linux_dirent64 *dirp;
10401 abi_long count = arg3;
10402
10403 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10404 if (!dirp) {
10405 goto efault;
10406 }
10407 ret = get_errno(sys_getdents64(arg1, dirp, count));
10408 if (!is_error(ret)) {
10409 /* Convert the dirent64 structs to target dirent. We do this
10410 * in-place, since we can guarantee that a target_dirent is no
10411 * larger than a dirent64; however this means we have to be
10412 * careful to read everything before writing in the new format.
10413 */
10414 struct linux_dirent64 *de;
10415 struct target_dirent *tde;
10416 int len = ret;
10417 int tlen = 0;
10418
10419 de = dirp;
10420 tde = (struct target_dirent *)dirp;
10421 while (len > 0) {
10422 int namelen, treclen;
10423 int reclen = de->d_reclen;
10424 uint64_t ino = de->d_ino;
10425 int64_t off = de->d_off;
10426 uint8_t type = de->d_type;
10427
10428 namelen = strlen(de->d_name);
10429 treclen = offsetof(struct target_dirent, d_name)
10430 + namelen + 2;
10431 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10432
10433 memmove(tde->d_name, de->d_name, namelen + 1);
10434 tde->d_ino = tswapal(ino);
10435 tde->d_off = tswapal(off);
10436 tde->d_reclen = tswap16(treclen);
10437 /* The target_dirent type is in what was formerly a padding
10438 * byte at the end of the structure:
10439 */
10440 *(((char *)tde) + treclen - 1) = type;
10441
10442 de = (struct linux_dirent64 *)((char *)de + reclen);
10443 tde = (struct target_dirent *)((char *)tde + treclen);
10444 len -= reclen;
10445 tlen += treclen;
10446 }
10447 ret = tlen;
10448 }
10449 unlock_user(dirp, arg2, ret);
10450 }
10451#endif
bellard31e31b82003-02-18 22:55:36 +000010452 break;
Chen Gang704eff62015-08-21 05:37:33 +080010453#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010454#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010455 case TARGET_NR_getdents64:
10456 {
aurel326556a832008-10-13 21:08:17 +000010457 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010458 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010459 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10460 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010461 ret = get_errno(sys_getdents64(arg1, dirp, count));
10462 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010463 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010464 int len = ret;
10465 int reclen;
10466 de = dirp;
10467 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010468 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010469 if (reclen > len)
10470 break;
bellard8083a3e2003-03-24 23:12:16 +000010471 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010472 tswap64s((uint64_t *)&de->d_ino);
10473 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010474 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010475 len -= reclen;
10476 }
10477 }
pbrook53a59602006-03-25 19:31:22 +000010478 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010479 }
10480 break;
bellarda541f292004-04-12 20:39:29 +000010481#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010482#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010483 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010484 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010485 break;
thse5febef2007-04-01 18:31:35 +000010486#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010487#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10488# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010489 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010490# endif
10491# ifdef TARGET_NR_ppoll
10492 case TARGET_NR_ppoll:
10493# endif
bellard9de5e442003-03-23 16:49:39 +000010494 {
pbrook53a59602006-03-25 19:31:22 +000010495 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010496 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010497 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010498 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010499
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010500 pfd = NULL;
10501 target_pfd = NULL;
10502 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010503 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10504 ret = -TARGET_EINVAL;
10505 break;
10506 }
10507
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010508 target_pfd = lock_user(VERIFY_WRITE, arg1,
10509 sizeof(struct target_pollfd) * nfds, 1);
10510 if (!target_pfd) {
10511 goto efault;
10512 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010513
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010514 pfd = alloca(sizeof(struct pollfd) * nfds);
10515 for (i = 0; i < nfds; i++) {
10516 pfd[i].fd = tswap32(target_pfd[i].fd);
10517 pfd[i].events = tswap16(target_pfd[i].events);
10518 }
bellard9de5e442003-03-23 16:49:39 +000010519 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010520
Peter Maydella6130232016-06-06 19:58:10 +010010521 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010522# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010523 case TARGET_NR_ppoll:
10524 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010525 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10526 target_sigset_t *target_set;
10527 sigset_t _set, *set = &_set;
10528
10529 if (arg3) {
10530 if (target_to_host_timespec(timeout_ts, arg3)) {
10531 unlock_user(target_pfd, arg1, 0);
10532 goto efault;
10533 }
10534 } else {
10535 timeout_ts = NULL;
10536 }
10537
10538 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010539 if (arg5 != sizeof(target_sigset_t)) {
10540 unlock_user(target_pfd, arg1, 0);
10541 ret = -TARGET_EINVAL;
10542 break;
10543 }
10544
Mike Frysingerd8035d42011-02-07 01:05:51 -050010545 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10546 if (!target_set) {
10547 unlock_user(target_pfd, arg1, 0);
10548 goto efault;
10549 }
10550 target_to_host_sigset(set, target_set);
10551 } else {
10552 set = NULL;
10553 }
10554
Peter Maydella6130232016-06-06 19:58:10 +010010555 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10556 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010557
10558 if (!is_error(ret) && arg3) {
10559 host_to_target_timespec(arg3, timeout_ts);
10560 }
10561 if (arg4) {
10562 unlock_user(target_set, arg4, 0);
10563 }
Peter Maydella6130232016-06-06 19:58:10 +010010564 break;
10565 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010566# endif
Peter Maydella6130232016-06-06 19:58:10 +010010567# ifdef TARGET_NR_poll
10568 case TARGET_NR_poll:
10569 {
10570 struct timespec ts, *pts;
10571
10572 if (arg3 >= 0) {
10573 /* Convert ms to secs, ns */
10574 ts.tv_sec = arg3 / 1000;
10575 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10576 pts = &ts;
10577 } else {
10578 /* -ve poll() timeout means "infinite" */
10579 pts = NULL;
10580 }
10581 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10582 break;
10583 }
10584# endif
10585 default:
10586 g_assert_not_reached();
10587 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010588
bellard9de5e442003-03-23 16:49:39 +000010589 if (!is_error(ret)) {
10590 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010591 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010592 }
10593 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010594 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010595 }
10596 break;
thse5febef2007-04-01 18:31:35 +000010597#endif
bellard31e31b82003-02-18 22:55:36 +000010598 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010599 /* NOTE: the flock constant seems to be the same for every
10600 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010601 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010602 break;
10603 case TARGET_NR_readv:
10604 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010605 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10606 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010607 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010608 unlock_iovec(vec, arg2, arg3, 1);
10609 } else {
10610 ret = -host_to_target_errno(errno);
10611 }
bellard31e31b82003-02-18 22:55:36 +000010612 }
10613 break;
10614 case TARGET_NR_writev:
10615 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010616 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10617 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010618 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010619 unlock_iovec(vec, arg2, arg3, 0);
10620 } else {
10621 ret = -host_to_target_errno(errno);
10622 }
bellard31e31b82003-02-18 22:55:36 +000010623 }
10624 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010625#if defined(TARGET_NR_preadv)
10626 case TARGET_NR_preadv:
10627 {
10628 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10629 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010630 unsigned long low, high;
10631
10632 target_to_host_low_high(arg4, arg5, &low, &high);
10633 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010634 unlock_iovec(vec, arg2, arg3, 1);
10635 } else {
10636 ret = -host_to_target_errno(errno);
10637 }
10638 }
10639 break;
10640#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010641#if defined(TARGET_NR_pwritev)
10642 case TARGET_NR_pwritev:
10643 {
10644 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10645 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010646 unsigned long low, high;
10647
10648 target_to_host_low_high(arg4, arg5, &low, &high);
10649 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010650 unlock_iovec(vec, arg2, arg3, 0);
10651 } else {
10652 ret = -host_to_target_errno(errno);
10653 }
10654 }
10655 break;
10656#endif
bellard31e31b82003-02-18 22:55:36 +000010657 case TARGET_NR_getsid:
10658 ret = get_errno(getsid(arg1));
10659 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010660#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010661 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010662 ret = get_errno(fdatasync(arg1));
10663 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010664#endif
Chen Gang704eff62015-08-21 05:37:33 +080010665#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010666 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010667 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010668 return value. */
ths0da46a62007-10-20 20:23:07 +000010669 ret = -TARGET_ENOTDIR;
10670 break;
Chen Gang704eff62015-08-21 05:37:33 +080010671#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010672 case TARGET_NR_sched_getaffinity:
10673 {
10674 unsigned int mask_size;
10675 unsigned long *mask;
10676
10677 /*
10678 * sched_getaffinity needs multiples of ulong, so need to take
10679 * care of mismatches between target ulong and host ulong sizes.
10680 */
10681 if (arg2 & (sizeof(abi_ulong) - 1)) {
10682 ret = -TARGET_EINVAL;
10683 break;
10684 }
10685 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10686
10687 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010688 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010689 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10690
10691 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010692 if (ret > arg2) {
10693 /* More data returned than the caller's buffer will fit.
10694 * This only happens if sizeof(abi_long) < sizeof(long)
10695 * and the caller passed us a buffer holding an odd number
10696 * of abi_longs. If the host kernel is actually using the
10697 * extra 4 bytes then fail EINVAL; otherwise we can just
10698 * ignore them and only copy the interesting part.
10699 */
10700 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10701 if (numcpus > arg2 * 8) {
10702 ret = -TARGET_EINVAL;
10703 break;
10704 }
10705 ret = arg2;
10706 }
10707
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010708 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
10709 goto efault;
10710 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010711 }
10712 }
10713 break;
10714 case TARGET_NR_sched_setaffinity:
10715 {
10716 unsigned int mask_size;
10717 unsigned long *mask;
10718
10719 /*
10720 * sched_setaffinity needs multiples of ulong, so need to take
10721 * care of mismatches between target ulong and host ulong sizes.
10722 */
10723 if (arg2 & (sizeof(abi_ulong) - 1)) {
10724 ret = -TARGET_EINVAL;
10725 break;
10726 }
10727 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010728 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010729
10730 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10731 if (ret) {
10732 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010733 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010734
10735 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10736 }
10737 break;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010738 case TARGET_NR_getcpu:
10739 {
10740 unsigned cpu, node;
10741 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
10742 arg2 ? &node : NULL,
10743 NULL));
10744 if (is_error(ret)) {
10745 goto fail;
10746 }
10747 if (arg1 && put_user_u32(cpu, arg1)) {
10748 goto efault;
10749 }
10750 if (arg2 && put_user_u32(node, arg2)) {
10751 goto efault;
10752 }
10753 }
10754 break;
bellard31e31b82003-02-18 22:55:36 +000010755 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010756 {
pbrook53a59602006-03-25 19:31:22 +000010757 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010758 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010759
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010760 if (arg2 == 0) {
10761 return -TARGET_EINVAL;
10762 }
bellard579a97f2007-11-11 14:26:47 +000010763 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10764 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010765 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010766 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010767 ret = get_errno(sched_setparam(arg1, &schp));
10768 }
10769 break;
bellard31e31b82003-02-18 22:55:36 +000010770 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010771 {
pbrook53a59602006-03-25 19:31:22 +000010772 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010773 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010774
10775 if (arg2 == 0) {
10776 return -TARGET_EINVAL;
10777 }
bellard5cd43932003-03-29 16:54:36 +000010778 ret = get_errno(sched_getparam(arg1, &schp));
10779 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010780 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10781 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010782 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010783 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010784 }
10785 }
10786 break;
bellard31e31b82003-02-18 22:55:36 +000010787 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010788 {
pbrook53a59602006-03-25 19:31:22 +000010789 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010790 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010791 if (arg3 == 0) {
10792 return -TARGET_EINVAL;
10793 }
bellard579a97f2007-11-11 14:26:47 +000010794 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10795 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010796 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010797 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010798 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10799 }
10800 break;
bellard31e31b82003-02-18 22:55:36 +000010801 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010802 ret = get_errno(sched_getscheduler(arg1));
10803 break;
bellard31e31b82003-02-18 22:55:36 +000010804 case TARGET_NR_sched_yield:
10805 ret = get_errno(sched_yield());
10806 break;
10807 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010808 ret = get_errno(sched_get_priority_max(arg1));
10809 break;
bellard31e31b82003-02-18 22:55:36 +000010810 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010811 ret = get_errno(sched_get_priority_min(arg1));
10812 break;
bellard31e31b82003-02-18 22:55:36 +000010813 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010814 {
bellard5cd43932003-03-29 16:54:36 +000010815 struct timespec ts;
10816 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10817 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010818 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010819 }
10820 }
10821 break;
bellard31e31b82003-02-18 22:55:36 +000010822 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010823 {
bellard1b6b0292003-03-22 17:31:38 +000010824 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010825 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010826 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010827 if (is_error(ret) && arg2) {
10828 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010829 }
10830 }
10831 break;
thse5febef2007-04-01 18:31:35 +000010832#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010833 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010834 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010835#endif
10836#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010837 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010838 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010839#endif
bellard31e31b82003-02-18 22:55:36 +000010840 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010841 switch (arg1) {
10842 case PR_GET_PDEATHSIG:
10843 {
10844 int deathsig;
10845 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10846 if (!is_error(ret) && arg2
10847 && put_user_ual(deathsig, arg2)) {
10848 goto efault;
thse5574482007-02-11 20:03:13 +000010849 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010850 break;
10851 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010852#ifdef PR_GET_NAME
10853 case PR_GET_NAME:
10854 {
10855 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10856 if (!name) {
10857 goto efault;
10858 }
10859 ret = get_errno(prctl(arg1, (unsigned long)name,
10860 arg3, arg4, arg5));
10861 unlock_user(name, arg2, 16);
10862 break;
10863 }
10864 case PR_SET_NAME:
10865 {
10866 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10867 if (!name) {
10868 goto efault;
10869 }
10870 ret = get_errno(prctl(arg1, (unsigned long)name,
10871 arg3, arg4, arg5));
10872 unlock_user(name, arg2, 0);
10873 break;
10874 }
10875#endif
Richard Henderson85fc7162018-03-09 17:09:43 +000010876#ifdef TARGET_AARCH64
10877 case TARGET_PR_SVE_SET_VL:
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010878 /*
10879 * We cannot support either PR_SVE_SET_VL_ONEXEC or
10880 * PR_SVE_VL_INHERIT. Note the kernel definition
10881 * of sve_vl_valid allows for VQ=512, i.e. VL=8192,
10882 * even though the current architectural maximum is VQ=16.
10883 */
Richard Henderson85fc7162018-03-09 17:09:43 +000010884 ret = -TARGET_EINVAL;
10885 if (arm_feature(cpu_env, ARM_FEATURE_SVE)
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010886 && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
Richard Henderson85fc7162018-03-09 17:09:43 +000010887 CPUARMState *env = cpu_env;
Richard Hendersonadf92ea2018-08-16 14:05:28 +010010888 ARMCPU *cpu = arm_env_get_cpu(env);
10889 uint32_t vq, old_vq;
10890
10891 old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
10892 vq = MAX(arg2 / 16, 1);
10893 vq = MIN(vq, cpu->sve_max_vq);
Richard Henderson85fc7162018-03-09 17:09:43 +000010894
10895 if (vq < old_vq) {
10896 aarch64_sve_narrow_vq(env, vq);
10897 }
10898 env->vfp.zcr_el[1] = vq - 1;
10899 ret = vq * 16;
10900 }
10901 break;
10902 case TARGET_PR_SVE_GET_VL:
10903 ret = -TARGET_EINVAL;
10904 if (arm_feature(cpu_env, ARM_FEATURE_SVE)) {
10905 CPUARMState *env = cpu_env;
10906 ret = ((env->vfp.zcr_el[1] & 0xf) + 1) * 16;
10907 }
10908 break;
10909#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +000010910 case PR_GET_SECCOMP:
10911 case PR_SET_SECCOMP:
10912 /* Disable seccomp to prevent the target disabling syscalls we
10913 * need. */
10914 ret = -TARGET_EINVAL;
10915 break;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010916 default:
10917 /* Most prctl options have no pointer arguments */
10918 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10919 break;
10920 }
ths39b9aae2007-02-11 18:36:44 +000010921 break;
bellardd2fd1af2007-11-14 18:08:56 +000010922#ifdef TARGET_NR_arch_prctl
10923 case TARGET_NR_arch_prctl:
10924#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10925 ret = do_arch_prctl(cpu_env, arg1, arg2);
10926 break;
10927#else
10928 goto unimplemented;
10929#endif
10930#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010931#ifdef TARGET_NR_pread64
10932 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010933 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010934 arg4 = arg5;
10935 arg5 = arg6;
10936 }
aurel32f2c7ba12008-03-28 22:32:06 +000010937 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10938 goto efault;
10939 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10940 unlock_user(p, arg2, ret);
10941 break;
10942 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010943 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010944 arg4 = arg5;
10945 arg5 = arg6;
10946 }
aurel32f2c7ba12008-03-28 22:32:06 +000010947 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10948 goto efault;
10949 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10950 unlock_user(p, arg2, 0);
10951 break;
10952#endif
bellard31e31b82003-02-18 22:55:36 +000010953 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010954 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10955 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010956 ret = get_errno(sys_getcwd1(p, arg2));
10957 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010958 break;
10959 case TARGET_NR_capget:
10960 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010961 {
10962 struct target_user_cap_header *target_header;
10963 struct target_user_cap_data *target_data = NULL;
10964 struct __user_cap_header_struct header;
10965 struct __user_cap_data_struct data[2];
10966 struct __user_cap_data_struct *dataptr = NULL;
10967 int i, target_datalen;
10968 int data_items = 1;
10969
10970 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10971 goto efault;
10972 }
10973 header.version = tswap32(target_header->version);
10974 header.pid = tswap32(target_header->pid);
10975
Peter Maydellec864872014-03-19 16:07:30 +000010976 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010977 /* Version 2 and up takes pointer to two user_data structs */
10978 data_items = 2;
10979 }
10980
10981 target_datalen = sizeof(*target_data) * data_items;
10982
10983 if (arg2) {
10984 if (num == TARGET_NR_capget) {
10985 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10986 } else {
10987 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10988 }
10989 if (!target_data) {
10990 unlock_user_struct(target_header, arg1, 0);
10991 goto efault;
10992 }
10993
10994 if (num == TARGET_NR_capset) {
10995 for (i = 0; i < data_items; i++) {
10996 data[i].effective = tswap32(target_data[i].effective);
10997 data[i].permitted = tswap32(target_data[i].permitted);
10998 data[i].inheritable = tswap32(target_data[i].inheritable);
10999 }
11000 }
11001
11002 dataptr = data;
11003 }
11004
11005 if (num == TARGET_NR_capget) {
11006 ret = get_errno(capget(&header, dataptr));
11007 } else {
11008 ret = get_errno(capset(&header, dataptr));
11009 }
11010
11011 /* The kernel always updates version for both capget and capset */
11012 target_header->version = tswap32(header.version);
11013 unlock_user_struct(target_header, arg1, 1);
11014
11015 if (arg2) {
11016 if (num == TARGET_NR_capget) {
11017 for (i = 0; i < data_items; i++) {
11018 target_data[i].effective = tswap32(data[i].effective);
11019 target_data[i].permitted = tswap32(data[i].permitted);
11020 target_data[i].inheritable = tswap32(data[i].inheritable);
11021 }
11022 unlock_user(target_data, arg2, target_datalen);
11023 } else {
11024 unlock_user(target_data, arg2, 0);
11025 }
11026 }
11027 break;
11028 }
bellard31e31b82003-02-18 22:55:36 +000011029 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010011030 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000011031 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011032
11033#ifdef CONFIG_SENDFILE
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011034#ifdef TARGET_NR_sendfile
bellard31e31b82003-02-18 22:55:36 +000011035 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011036 {
11037 off_t *offp = NULL;
11038 off_t off;
11039 if (arg3) {
11040 ret = get_user_sal(off, arg3);
11041 if (is_error(ret)) {
11042 break;
11043 }
11044 offp = &off;
11045 }
11046 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11047 if (!is_error(ret) && arg3) {
11048 abi_long ret2 = put_user_sal(off, arg3);
11049 if (is_error(ret2)) {
11050 ret = ret2;
11051 }
11052 }
11053 break;
11054 }
Aleksandar Rikalo4f7f8922018-08-02 16:16:00 +020011055#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011056#ifdef TARGET_NR_sendfile64
11057 case TARGET_NR_sendfile64:
11058 {
11059 off_t *offp = NULL;
11060 off_t off;
11061 if (arg3) {
11062 ret = get_user_s64(off, arg3);
11063 if (is_error(ret)) {
11064 break;
11065 }
11066 offp = &off;
11067 }
11068 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11069 if (!is_error(ret) && arg3) {
11070 abi_long ret2 = put_user_s64(off, arg3);
11071 if (is_error(ret2)) {
11072 ret = ret2;
11073 }
11074 }
11075 break;
11076 }
11077#endif
11078#else
11079 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010011080#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011081 case TARGET_NR_sendfile64:
11082#endif
bellard5cd43932003-03-29 16:54:36 +000011083 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011084#endif
11085
bellardebc05482003-09-30 21:08:41 +000011086#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000011087 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000011088 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011089#endif
11090#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000011091 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000011092 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011093#endif
bellard048f6b42005-11-26 18:47:20 +000011094#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000011095 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010011096 ret = get_errno(do_fork(cpu_env,
11097 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000011098 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000011099 break;
bellard048f6b42005-11-26 18:47:20 +000011100#endif
bellardebc05482003-09-30 21:08:41 +000011101#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000011102 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000011103 {
11104 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030011105 int resource = target_to_host_resource(arg1);
11106 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000011107 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000011108 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000011109 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
11110 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090011111 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
11112 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000011113 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000011114 }
11115 break;
11116 }
bellardebc05482003-09-30 21:08:41 +000011117#endif
bellarda315a142005-01-30 22:59:18 +000011118#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000011119 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000011120 if (!(p = lock_user_string(arg1)))
11121 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011122 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
11123 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000011124 break;
bellarda315a142005-01-30 22:59:18 +000011125#endif
11126#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000011127 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000011128 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000011129 break;
bellarda315a142005-01-30 22:59:18 +000011130#endif
11131#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000011132 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000011133 if (!(p = lock_user_string(arg1)))
11134 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011135 ret = get_errno(stat(path(p), &st));
11136 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011137 if (!is_error(ret))
11138 ret = host_to_target_stat64(cpu_env, arg2, &st);
11139 break;
bellarda315a142005-01-30 22:59:18 +000011140#endif
11141#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000011142 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000011143 if (!(p = lock_user_string(arg1)))
11144 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011145 ret = get_errno(lstat(path(p), &st));
11146 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011147 if (!is_error(ret))
11148 ret = host_to_target_stat64(cpu_env, arg2, &st);
11149 break;
bellarda315a142005-01-30 22:59:18 +000011150#endif
11151#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000011152 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000011153 ret = get_errno(fstat(arg1, &st));
11154 if (!is_error(ret))
11155 ret = host_to_target_stat64(cpu_env, arg2, &st);
11156 break;
bellardec86b0f2003-04-11 00:15:04 +000011157#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010011158#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000011159#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000011160 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000011161#endif
11162#ifdef TARGET_NR_newfstatat
11163 case TARGET_NR_newfstatat:
11164#endif
balrog6a24a772008-09-20 02:23:36 +000011165 if (!(p = lock_user_string(arg2)))
11166 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011167 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000011168 if (!is_error(ret))
11169 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000011170 break;
bellarda315a142005-01-30 22:59:18 +000011171#endif
Chen Gang704eff62015-08-21 05:37:33 +080011172#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000011173 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000011174 if (!(p = lock_user_string(arg1)))
11175 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011176 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
11177 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011178 break;
Chen Gang704eff62015-08-21 05:37:33 +080011179#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030011180#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000011181 case TARGET_NR_getuid:
11182 ret = get_errno(high2lowuid(getuid()));
11183 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011184#endif
11185#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000011186 case TARGET_NR_getgid:
11187 ret = get_errno(high2lowgid(getgid()));
11188 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011189#endif
11190#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000011191 case TARGET_NR_geteuid:
11192 ret = get_errno(high2lowuid(geteuid()));
11193 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011194#endif
11195#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011196 case TARGET_NR_getegid:
11197 ret = get_errno(high2lowgid(getegid()));
11198 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011199#endif
bellard67867302003-11-23 17:05:30 +000011200 case TARGET_NR_setreuid:
11201 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
11202 break;
11203 case TARGET_NR_setregid:
11204 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
11205 break;
11206 case TARGET_NR_getgroups:
11207 {
11208 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011209 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000011210 gid_t *grouplist;
11211 int i;
11212
11213 grouplist = alloca(gidsetsize * sizeof(gid_t));
11214 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011215 if (gidsetsize == 0)
11216 break;
bellard67867302003-11-23 17:05:30 +000011217 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000011218 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000011219 if (!target_grouplist)
11220 goto efault;
balroga2155fc2008-09-20 02:12:08 +000011221 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030011222 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011223 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000011224 }
11225 }
11226 break;
11227 case TARGET_NR_setgroups:
11228 {
11229 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011230 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011231 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011232 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011233 if (gidsetsize) {
11234 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011235 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011236 if (!target_grouplist) {
11237 ret = -TARGET_EFAULT;
11238 goto fail;
11239 }
11240 for (i = 0; i < gidsetsize; i++) {
11241 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11242 }
11243 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000011244 }
bellard67867302003-11-23 17:05:30 +000011245 ret = get_errno(setgroups(gidsetsize, grouplist));
11246 }
11247 break;
11248 case TARGET_NR_fchown:
11249 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
11250 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011251#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011252 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011253 if (!(p = lock_user_string(arg2)))
11254 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011255 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11256 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011257 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000011258 break;
11259#endif
bellard67867302003-11-23 17:05:30 +000011260#ifdef TARGET_NR_setresuid
11261 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011262 ret = get_errno(sys_setresuid(low2highuid(arg1),
11263 low2highuid(arg2),
11264 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011265 break;
11266#endif
11267#ifdef TARGET_NR_getresuid
11268 case TARGET_NR_getresuid:
11269 {
pbrook53a59602006-03-25 19:31:22 +000011270 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011271 ret = get_errno(getresuid(&ruid, &euid, &suid));
11272 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011273 if (put_user_id(high2lowuid(ruid), arg1)
11274 || put_user_id(high2lowuid(euid), arg2)
11275 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000011276 goto efault;
bellard67867302003-11-23 17:05:30 +000011277 }
11278 }
11279 break;
11280#endif
11281#ifdef TARGET_NR_getresgid
11282 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011283 ret = get_errno(sys_setresgid(low2highgid(arg1),
11284 low2highgid(arg2),
11285 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011286 break;
11287#endif
11288#ifdef TARGET_NR_getresgid
11289 case TARGET_NR_getresgid:
11290 {
pbrook53a59602006-03-25 19:31:22 +000011291 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011292 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11293 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011294 if (put_user_id(high2lowgid(rgid), arg1)
11295 || put_user_id(high2lowgid(egid), arg2)
11296 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000011297 goto efault;
bellard67867302003-11-23 17:05:30 +000011298 }
11299 }
11300 break;
11301#endif
Chen Gang704eff62015-08-21 05:37:33 +080011302#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011303 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011304 if (!(p = lock_user_string(arg1)))
11305 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011306 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11307 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011308 break;
Chen Gang704eff62015-08-21 05:37:33 +080011309#endif
bellard67867302003-11-23 17:05:30 +000011310 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011311 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011312 break;
11313 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011314 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011315 break;
11316 case TARGET_NR_setfsuid:
11317 ret = get_errno(setfsuid(arg1));
11318 break;
11319 case TARGET_NR_setfsgid:
11320 ret = get_errno(setfsgid(arg1));
11321 break;
bellard67867302003-11-23 17:05:30 +000011322
bellarda315a142005-01-30 22:59:18 +000011323#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011324 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011325 if (!(p = lock_user_string(arg1)))
11326 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011327 ret = get_errno(lchown(p, arg2, arg3));
11328 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011329 break;
bellarda315a142005-01-30 22:59:18 +000011330#endif
11331#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011332 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000011333 ret = get_errno(getuid());
11334 break;
bellarda315a142005-01-30 22:59:18 +000011335#endif
aurel3264b4d282008-11-14 17:20:15 +000011336
11337#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11338 /* Alpha specific */
11339 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011340 {
11341 uid_t euid;
11342 euid=geteuid();
11343 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11344 }
aurel3264b4d282008-11-14 17:20:15 +000011345 ret = get_errno(getuid());
11346 break;
11347#endif
11348#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11349 /* Alpha specific */
11350 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011351 {
11352 uid_t egid;
11353 egid=getegid();
11354 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11355 }
aurel3264b4d282008-11-14 17:20:15 +000011356 ret = get_errno(getgid());
11357 break;
11358#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011359#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11360 /* Alpha specific */
11361 case TARGET_NR_osf_getsysinfo:
11362 ret = -TARGET_EOPNOTSUPP;
11363 switch (arg1) {
11364 case TARGET_GSI_IEEE_FP_CONTROL:
11365 {
11366 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
11367
11368 /* Copied from linux ieee_fpcr_to_swcr. */
11369 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
11370 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
11371 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
11372 | SWCR_TRAP_ENABLE_DZE
11373 | SWCR_TRAP_ENABLE_OVF);
11374 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
11375 | SWCR_TRAP_ENABLE_INE);
11376 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
11377 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
11378
11379 if (put_user_u64 (swcr, arg2))
11380 goto efault;
11381 ret = 0;
11382 }
11383 break;
11384
11385 /* case GSI_IEEE_STATE_AT_SIGNAL:
11386 -- Not implemented in linux kernel.
11387 case GSI_UACPROC:
11388 -- Retrieves current unaligned access state; not much used.
11389 case GSI_PROC_TYPE:
11390 -- Retrieves implver information; surely not used.
11391 case GSI_GET_HWRPB:
11392 -- Grabs a copy of the HWRPB; surely not used.
11393 */
11394 }
11395 break;
11396#endif
11397#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11398 /* Alpha specific */
11399 case TARGET_NR_osf_setsysinfo:
11400 ret = -TARGET_EOPNOTSUPP;
11401 switch (arg1) {
11402 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011403 {
11404 uint64_t swcr, fpcr, orig_fpcr;
11405
Richard Henderson6e06d512012-06-01 09:08:21 -070011406 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080011407 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070011408 }
11409 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011410 fpcr = orig_fpcr & FPCR_DYN_MASK;
11411
11412 /* Copied from linux ieee_swcr_to_fpcr. */
11413 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
11414 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
11415 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
11416 | SWCR_TRAP_ENABLE_DZE
11417 | SWCR_TRAP_ENABLE_OVF)) << 48;
11418 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
11419 | SWCR_TRAP_ENABLE_INE)) << 57;
11420 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
11421 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
11422
Richard Henderson6e06d512012-06-01 09:08:21 -070011423 cpu_alpha_store_fpcr(cpu_env, fpcr);
11424 ret = 0;
11425 }
11426 break;
11427
11428 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11429 {
11430 uint64_t exc, fpcr, orig_fpcr;
11431 int si_code;
11432
11433 if (get_user_u64(exc, arg2)) {
11434 goto efault;
11435 }
11436
11437 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
11438
11439 /* We only add to the exception status here. */
11440 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
11441
11442 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011443 ret = 0;
11444
Richard Henderson6e06d512012-06-01 09:08:21 -070011445 /* Old exceptions are not signaled. */
11446 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011447
Richard Henderson6e06d512012-06-01 09:08:21 -070011448 /* If any exceptions set by this call,
11449 and are unmasked, send a signal. */
11450 si_code = 0;
11451 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11452 si_code = TARGET_FPE_FLTRES;
11453 }
11454 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11455 si_code = TARGET_FPE_FLTUND;
11456 }
11457 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11458 si_code = TARGET_FPE_FLTOVF;
11459 }
11460 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11461 si_code = TARGET_FPE_FLTDIV;
11462 }
11463 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11464 si_code = TARGET_FPE_FLTINV;
11465 }
11466 if (si_code != 0) {
11467 target_siginfo_t info;
11468 info.si_signo = SIGFPE;
11469 info.si_errno = 0;
11470 info.si_code = si_code;
11471 info._sifields._sigfault._addr
11472 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011473 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11474 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011475 }
11476 }
11477 break;
11478
11479 /* case SSI_NVPAIRS:
11480 -- Used with SSIN_UACPROC to enable unaligned accesses.
11481 case SSI_IEEE_STATE_AT_SIGNAL:
11482 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11483 -- Not implemented in linux kernel
11484 */
11485 }
11486 break;
11487#endif
11488#ifdef TARGET_NR_osf_sigprocmask
11489 /* Alpha specific. */
11490 case TARGET_NR_osf_sigprocmask:
11491 {
11492 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011493 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011494 sigset_t set, oldset;
11495
11496 switch(arg1) {
11497 case TARGET_SIG_BLOCK:
11498 how = SIG_BLOCK;
11499 break;
11500 case TARGET_SIG_UNBLOCK:
11501 how = SIG_UNBLOCK;
11502 break;
11503 case TARGET_SIG_SETMASK:
11504 how = SIG_SETMASK;
11505 break;
11506 default:
11507 ret = -TARGET_EINVAL;
11508 goto fail;
11509 }
11510 mask = arg2;
11511 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011512 ret = do_sigprocmask(how, &set, &oldset);
11513 if (!ret) {
11514 host_to_target_old_sigset(&mask, &oldset);
11515 ret = mask;
11516 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011517 }
11518 break;
11519#endif
aurel3264b4d282008-11-14 17:20:15 +000011520
bellarda315a142005-01-30 22:59:18 +000011521#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011522 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011523 ret = get_errno(getgid());
11524 break;
bellarda315a142005-01-30 22:59:18 +000011525#endif
11526#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011527 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011528 ret = get_errno(geteuid());
11529 break;
bellarda315a142005-01-30 22:59:18 +000011530#endif
11531#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011532 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011533 ret = get_errno(getegid());
11534 break;
bellarda315a142005-01-30 22:59:18 +000011535#endif
11536#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011537 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011538 ret = get_errno(setreuid(arg1, arg2));
11539 break;
bellarda315a142005-01-30 22:59:18 +000011540#endif
11541#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011542 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011543 ret = get_errno(setregid(arg1, arg2));
11544 break;
bellarda315a142005-01-30 22:59:18 +000011545#endif
11546#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011547 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011548 {
11549 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011550 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011551 gid_t *grouplist;
11552 int i;
11553
11554 grouplist = alloca(gidsetsize * sizeof(gid_t));
11555 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011556 if (gidsetsize == 0)
11557 break;
bellard99c475a2005-01-31 20:45:13 +000011558 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011559 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11560 if (!target_grouplist) {
11561 ret = -TARGET_EFAULT;
11562 goto fail;
11563 }
balroga2155fc2008-09-20 02:12:08 +000011564 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011565 target_grouplist[i] = tswap32(grouplist[i]);
11566 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011567 }
11568 }
11569 break;
bellarda315a142005-01-30 22:59:18 +000011570#endif
11571#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011572 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011573 {
11574 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011575 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011576 gid_t *grouplist;
11577 int i;
ths3b46e622007-09-17 08:09:54 +000011578
bellard99c475a2005-01-31 20:45:13 +000011579 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011580 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11581 if (!target_grouplist) {
11582 ret = -TARGET_EFAULT;
11583 goto fail;
11584 }
bellard99c475a2005-01-31 20:45:13 +000011585 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011586 grouplist[i] = tswap32(target_grouplist[i]);
11587 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011588 ret = get_errno(setgroups(gidsetsize, grouplist));
11589 }
11590 break;
bellarda315a142005-01-30 22:59:18 +000011591#endif
11592#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011593 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011594 ret = get_errno(fchown(arg1, arg2, arg3));
11595 break;
bellarda315a142005-01-30 22:59:18 +000011596#endif
11597#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011598 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011599 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011600 break;
bellarda315a142005-01-30 22:59:18 +000011601#endif
11602#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011603 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011604 {
pbrook53a59602006-03-25 19:31:22 +000011605 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011606 ret = get_errno(getresuid(&ruid, &euid, &suid));
11607 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011608 if (put_user_u32(ruid, arg1)
11609 || put_user_u32(euid, arg2)
11610 || put_user_u32(suid, arg3))
11611 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011612 }
11613 }
11614 break;
bellarda315a142005-01-30 22:59:18 +000011615#endif
11616#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011617 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011618 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011619 break;
bellarda315a142005-01-30 22:59:18 +000011620#endif
11621#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011622 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011623 {
pbrook53a59602006-03-25 19:31:22 +000011624 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011625 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11626 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011627 if (put_user_u32(rgid, arg1)
11628 || put_user_u32(egid, arg2)
11629 || put_user_u32(sgid, arg3))
11630 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011631 }
11632 }
11633 break;
bellarda315a142005-01-30 22:59:18 +000011634#endif
11635#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011636 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011637 if (!(p = lock_user_string(arg1)))
11638 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011639 ret = get_errno(chown(p, arg2, arg3));
11640 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011641 break;
bellarda315a142005-01-30 22:59:18 +000011642#endif
11643#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011644 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011645 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011646 break;
bellarda315a142005-01-30 22:59:18 +000011647#endif
11648#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011649 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011650 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011651 break;
bellarda315a142005-01-30 22:59:18 +000011652#endif
11653#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011654 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011655 ret = get_errno(setfsuid(arg1));
11656 break;
bellarda315a142005-01-30 22:59:18 +000011657#endif
11658#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011659 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011660 ret = get_errno(setfsgid(arg1));
11661 break;
bellarda315a142005-01-30 22:59:18 +000011662#endif
bellard67867302003-11-23 17:05:30 +000011663
bellard31e31b82003-02-18 22:55:36 +000011664 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011665 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011666#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011667 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011668 {
11669 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011670 ret = -TARGET_ENOMEM;
11671 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11672 if (!a) {
11673 goto fail;
11674 }
aurel3204bb9ac2008-10-01 21:46:41 +000011675 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011676 p = lock_user_string(arg3);
11677 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011678 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011679 }
aurel3204bb9ac2008-10-01 21:46:41 +000011680 ret = get_errno(mincore(a, arg2, p));
11681 unlock_user(p, arg3, ret);
11682 mincore_fail:
11683 unlock_user(a, arg1, 0);
11684 }
11685 break;
bellardffa65c32004-01-04 23:57:22 +000011686#endif
aurel32408321b2008-10-01 21:46:32 +000011687#ifdef TARGET_NR_arm_fadvise64_64
11688 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011689 /* arm_fadvise64_64 looks like fadvise64_64 but
11690 * with different argument order: fd, advice, offset, len
11691 * rather than the usual fd, offset, len, advice.
11692 * Note that offset and len are both 64-bit so appear as
11693 * pairs of 32-bit registers.
11694 */
11695 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11696 target_offset64(arg5, arg6), arg2);
11697 ret = -host_to_target_errno(ret);
11698 break;
aurel32408321b2008-10-01 21:46:32 +000011699#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011700
11701#if TARGET_ABI_BITS == 32
11702
11703#ifdef TARGET_NR_fadvise64_64
11704 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070011705#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010011706 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11707 ret = arg2;
11708 arg2 = arg3;
11709 arg3 = arg4;
11710 arg4 = arg5;
11711 arg5 = arg6;
11712 arg6 = ret;
11713#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011714 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011715 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011716 /* offset is in (3,4), len in (5,6) and advice in 7 */
11717 arg2 = arg3;
11718 arg3 = arg4;
11719 arg4 = arg5;
11720 arg5 = arg6;
11721 arg6 = arg7;
11722 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011723#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011724 ret = -host_to_target_errno(posix_fadvise(arg1,
11725 target_offset64(arg2, arg3),
11726 target_offset64(arg4, arg5),
11727 arg6));
11728 break;
11729#endif
11730
11731#ifdef TARGET_NR_fadvise64
11732 case TARGET_NR_fadvise64:
11733 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011734 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011735 /* offset is in (3,4), len in 5 and advice in 6 */
11736 arg2 = arg3;
11737 arg3 = arg4;
11738 arg4 = arg5;
11739 arg5 = arg6;
11740 }
11741 ret = -host_to_target_errno(posix_fadvise(arg1,
11742 target_offset64(arg2, arg3),
11743 arg4, arg5));
11744 break;
11745#endif
11746
11747#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011748#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011749#ifdef TARGET_NR_fadvise64_64
11750 case TARGET_NR_fadvise64_64:
11751#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011752#ifdef TARGET_NR_fadvise64
11753 case TARGET_NR_fadvise64:
11754#endif
11755#ifdef TARGET_S390X
11756 switch (arg4) {
11757 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11758 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11759 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11760 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11761 default: break;
11762 }
11763#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011764 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11765 break;
aurel32408321b2008-10-01 21:46:32 +000011766#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011767#endif /* end of 64-bit ABI fadvise handling */
11768
bellardffa65c32004-01-04 23:57:22 +000011769#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011770 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011771 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011772 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011773 This will break MADV_DONTNEED.
11774 This is a hint, so ignoring and returning success is ok. */
11775 ret = get_errno(0);
11776 break;
bellardffa65c32004-01-04 23:57:22 +000011777#endif
blueswir1992f48a2007-10-14 16:27:31 +000011778#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011779 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011780 {
thsb1e341e2007-03-20 21:50:52 +000011781 int cmd;
bellard77e46722003-04-29 20:39:06 +000011782 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011783 from_flock64_fn *copyfrom = copy_from_user_flock64;
11784 to_flock64_fn *copyto = copy_to_user_flock64;
11785
pbrookce4defa2006-02-09 16:49:55 +000011786#ifdef TARGET_ARM
Laurent Vivier7f254c52018-05-02 23:57:30 +020011787 if (!((CPUARMState *)cpu_env)->eabi) {
11788 copyfrom = copy_from_user_oabi_flock64;
11789 copyto = copy_to_user_oabi_flock64;
Peter Maydell213d3e92016-06-13 11:22:05 +010011790 }
pbrookce4defa2006-02-09 16:49:55 +000011791#endif
bellard77e46722003-04-29 20:39:06 +000011792
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011793 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011794 if (cmd == -TARGET_EINVAL) {
11795 ret = cmd;
11796 break;
11797 }
thsb1e341e2007-03-20 21:50:52 +000011798
bellard60cd49d2003-03-16 22:53:56 +000011799 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011800 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011801 ret = copyfrom(&fl, arg3);
11802 if (ret) {
11803 break;
ths58134272007-03-31 18:59:32 +000011804 }
Laurent Vivieraf8ab2b2018-07-13 14:58:05 +020011805 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011806 if (ret == 0) {
11807 ret = copyto(arg3, &fl);
11808 }
bellard77e46722003-04-29 20:39:06 +000011809 break;
11810
thsb1e341e2007-03-20 21:50:52 +000011811 case TARGET_F_SETLK64:
11812 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011813 ret = copyfrom(&fl, arg3);
11814 if (ret) {
11815 break;
pbrookce4defa2006-02-09 16:49:55 +000011816 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011817 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011818 break;
bellard60cd49d2003-03-16 22:53:56 +000011819 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011820 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011821 break;
11822 }
bellard77e46722003-04-29 20:39:06 +000011823 break;
11824 }
bellard60cd49d2003-03-16 22:53:56 +000011825#endif
ths7d600c82006-12-08 01:32:58 +000011826#ifdef TARGET_NR_cacheflush
11827 case TARGET_NR_cacheflush:
11828 /* self-modifying code is handled automatically, so nothing needed */
11829 ret = 0;
11830 break;
11831#endif
bellardebc05482003-09-30 21:08:41 +000011832#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011833 case TARGET_NR_security:
11834 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011835#endif
bellardc573ff62004-01-04 15:51:36 +000011836#ifdef TARGET_NR_getpagesize
11837 case TARGET_NR_getpagesize:
11838 ret = TARGET_PAGE_SIZE;
11839 break;
11840#endif
bellard31e31b82003-02-18 22:55:36 +000011841 case TARGET_NR_gettid:
11842 ret = get_errno(gettid());
11843 break;
thse5febef2007-04-01 18:31:35 +000011844#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011845 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011846#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011847 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011848 arg2 = arg3;
11849 arg3 = arg4;
11850 arg4 = arg5;
11851 }
Lena Djokic77c68502016-11-24 17:08:56 +010011852 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011853#else
11854 ret = get_errno(readahead(arg1, arg2, arg3));
11855#endif
11856 break;
thse5febef2007-04-01 18:31:35 +000011857#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011858#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011859#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011860 case TARGET_NR_listxattr:
11861 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011862 {
11863 void *p, *b = 0;
11864 if (arg2) {
11865 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11866 if (!b) {
11867 ret = -TARGET_EFAULT;
11868 break;
11869 }
11870 }
11871 p = lock_user_string(arg1);
11872 if (p) {
11873 if (num == TARGET_NR_listxattr) {
11874 ret = get_errno(listxattr(p, b, arg3));
11875 } else {
11876 ret = get_errno(llistxattr(p, b, arg3));
11877 }
11878 } else {
11879 ret = -TARGET_EFAULT;
11880 }
11881 unlock_user(p, arg1, 0);
11882 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011883 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011884 }
11885 case TARGET_NR_flistxattr:
11886 {
11887 void *b = 0;
11888 if (arg2) {
11889 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11890 if (!b) {
11891 ret = -TARGET_EFAULT;
11892 break;
11893 }
11894 }
11895 ret = get_errno(flistxattr(arg1, b, arg3));
11896 unlock_user(b, arg2, arg3);
11897 break;
11898 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011899 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011900 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011901 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011902 void *p, *n, *v = 0;
11903 if (arg3) {
11904 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11905 if (!v) {
11906 ret = -TARGET_EFAULT;
11907 break;
11908 }
11909 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011910 p = lock_user_string(arg1);
11911 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011912 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011913 if (num == TARGET_NR_setxattr) {
11914 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11915 } else {
11916 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11917 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011918 } else {
11919 ret = -TARGET_EFAULT;
11920 }
11921 unlock_user(p, arg1, 0);
11922 unlock_user(n, arg2, 0);
11923 unlock_user(v, arg3, 0);
11924 }
11925 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011926 case TARGET_NR_fsetxattr:
11927 {
11928 void *n, *v = 0;
11929 if (arg3) {
11930 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11931 if (!v) {
11932 ret = -TARGET_EFAULT;
11933 break;
11934 }
11935 }
11936 n = lock_user_string(arg2);
11937 if (n) {
11938 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11939 } else {
11940 ret = -TARGET_EFAULT;
11941 }
11942 unlock_user(n, arg2, 0);
11943 unlock_user(v, arg3, 0);
11944 }
11945 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011946 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011947 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011948 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011949 void *p, *n, *v = 0;
11950 if (arg3) {
11951 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11952 if (!v) {
11953 ret = -TARGET_EFAULT;
11954 break;
11955 }
11956 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011957 p = lock_user_string(arg1);
11958 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011959 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011960 if (num == TARGET_NR_getxattr) {
11961 ret = get_errno(getxattr(p, n, v, arg4));
11962 } else {
11963 ret = get_errno(lgetxattr(p, n, v, arg4));
11964 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011965 } else {
11966 ret = -TARGET_EFAULT;
11967 }
11968 unlock_user(p, arg1, 0);
11969 unlock_user(n, arg2, 0);
11970 unlock_user(v, arg3, arg4);
11971 }
11972 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011973 case TARGET_NR_fgetxattr:
11974 {
11975 void *n, *v = 0;
11976 if (arg3) {
11977 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11978 if (!v) {
11979 ret = -TARGET_EFAULT;
11980 break;
11981 }
11982 }
11983 n = lock_user_string(arg2);
11984 if (n) {
11985 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11986 } else {
11987 ret = -TARGET_EFAULT;
11988 }
11989 unlock_user(n, arg2, 0);
11990 unlock_user(v, arg3, arg4);
11991 }
11992 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011993 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011994 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011995 {
11996 void *p, *n;
11997 p = lock_user_string(arg1);
11998 n = lock_user_string(arg2);
11999 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000012000 if (num == TARGET_NR_removexattr) {
12001 ret = get_errno(removexattr(p, n));
12002 } else {
12003 ret = get_errno(lremovexattr(p, n));
12004 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012005 } else {
12006 ret = -TARGET_EFAULT;
12007 }
12008 unlock_user(p, arg1, 0);
12009 unlock_user(n, arg2, 0);
12010 }
12011 break;
Peter Maydell30297b52011-12-14 15:37:18 +000012012 case TARGET_NR_fremovexattr:
12013 {
12014 void *n;
12015 n = lock_user_string(arg2);
12016 if (n) {
12017 ret = get_errno(fremovexattr(arg1, n));
12018 } else {
12019 ret = -TARGET_EFAULT;
12020 }
12021 unlock_user(n, arg2, 0);
12022 }
12023 break;
bellardebc05482003-09-30 21:08:41 +000012024#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070012025#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000012026#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000012027 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012028#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020012029 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000012030 ret = 0;
12031 break;
edgar_iglef967792009-01-07 14:19:38 +000012032#elif defined(TARGET_CRIS)
12033 if (arg1 & 0xff)
12034 ret = -TARGET_EINVAL;
12035 else {
12036 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
12037 ret = 0;
12038 }
12039 break;
bellard8d18e892007-11-14 15:18:40 +000012040#elif defined(TARGET_I386) && defined(TARGET_ABI32)
12041 ret = do_set_thread_area(cpu_env, arg1);
12042 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012043#elif defined(TARGET_M68K)
12044 {
Andreas Färber0429a972013-08-26 18:14:44 +020012045 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012046 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010012047 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012048 break;
12049 }
ths6f5b89a2007-03-02 20:48:00 +000012050#else
12051 goto unimplemented_nowarn;
12052#endif
12053#endif
12054#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000012055 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012056#if defined(TARGET_I386) && defined(TARGET_ABI32)
12057 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010012058 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012059#elif defined(TARGET_M68K)
12060 {
Andreas Färber0429a972013-08-26 18:14:44 +020012061 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012062 ret = ts->tp_value;
12063 break;
12064 }
bellard8d18e892007-11-14 15:18:40 +000012065#else
bellard5cd43932003-03-29 16:54:36 +000012066 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000012067#endif
bellard8d18e892007-11-14 15:18:40 +000012068#endif
bellard48dc41e2006-06-21 18:15:50 +000012069#ifdef TARGET_NR_getdomainname
12070 case TARGET_NR_getdomainname:
12071 goto unimplemented_nowarn;
12072#endif
ths6f5b89a2007-03-02 20:48:00 +000012073
Max Filippov12e33402018-04-01 13:13:49 -070012074#ifdef TARGET_NR_clock_settime
12075 case TARGET_NR_clock_settime:
12076 {
12077 struct timespec ts;
12078
12079 ret = target_to_host_timespec(&ts, arg2);
12080 if (!is_error(ret)) {
12081 ret = get_errno(clock_settime(arg1, &ts));
12082 }
12083 break;
12084 }
12085#endif
thsb5906f92007-03-19 13:32:45 +000012086#ifdef TARGET_NR_clock_gettime
12087 case TARGET_NR_clock_gettime:
12088 {
12089 struct timespec ts;
12090 ret = get_errno(clock_gettime(arg1, &ts));
12091 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070012092 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000012093 }
12094 break;
12095 }
12096#endif
12097#ifdef TARGET_NR_clock_getres
12098 case TARGET_NR_clock_getres:
12099 {
12100 struct timespec ts;
12101 ret = get_errno(clock_getres(arg1, &ts));
12102 if (!is_error(ret)) {
12103 host_to_target_timespec(arg2, &ts);
12104 }
12105 break;
12106 }
12107#endif
pbrook63d76512008-05-29 13:43:29 +000012108#ifdef TARGET_NR_clock_nanosleep
12109 case TARGET_NR_clock_nanosleep:
12110 {
12111 struct timespec ts;
12112 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010012113 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12114 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000012115 if (arg4)
12116 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012117
12118#if defined(TARGET_PPC)
12119 /* clock_nanosleep is odd in that it returns positive errno values.
12120 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010012121 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012122 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
12123 }
12124#endif
pbrook63d76512008-05-29 13:43:29 +000012125 break;
12126 }
12127#endif
thsb5906f92007-03-19 13:32:45 +000012128
ths6f5b89a2007-03-02 20:48:00 +000012129#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
12130 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000012131 ret = get_errno(set_tid_address((int *)g2h(arg1)));
12132 break;
ths6f5b89a2007-03-02 20:48:00 +000012133#endif
12134
ths4cae1d12007-07-12 11:06:53 +000012135 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010012136 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000012137 break;
ths4cae1d12007-07-12 11:06:53 +000012138
ths71455572007-06-21 21:45:30 +000012139 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010012140 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000012141 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010012142 break;
ths71455572007-06-21 21:45:30 +000012143
ths4f2b1fe2007-06-21 21:57:12 +000012144#ifdef TARGET_NR_set_robust_list
12145 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000012146 case TARGET_NR_get_robust_list:
12147 /* The ABI for supporting robust futexes has userspace pass
12148 * the kernel a pointer to a linked list which is updated by
12149 * userspace after the syscall; the list is walked by the kernel
12150 * when the thread exits. Since the linked list in QEMU guest
12151 * memory isn't a valid linked list for the host and we have
12152 * no way to reliably intercept the thread-death event, we can't
12153 * support these. Silently return ENOSYS so that guest userspace
12154 * falls back to a non-robust futex implementation (which should
12155 * be OK except in the corner case of the guest crashing while
12156 * holding a mutex that is shared with another process via
12157 * shared memory).
12158 */
12159 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000012160#endif
12161
Peter Maydell1acae9f2013-07-02 14:04:12 +010012162#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000012163 case TARGET_NR_utimensat:
12164 {
Riku Voipioebc996f2009-04-21 15:01:51 +030012165 struct timespec *tsp, ts[2];
12166 if (!arg3) {
12167 tsp = NULL;
12168 } else {
12169 target_to_host_timespec(ts, arg3);
12170 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
12171 tsp = ts;
12172 }
ths9007f0e2007-09-25 17:50:37 +000012173 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030012174 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000012175 else {
bellard579a97f2007-11-11 14:26:47 +000012176 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000012177 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012178 goto fail;
12179 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012180 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000012181 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000012182 }
12183 }
12184 break;
12185#endif
pbrookbd0c5662008-05-29 14:34:11 +000012186 case TARGET_NR_futex:
12187 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
12188 break;
aurel32dbfe4c32009-04-08 21:29:30 +000012189#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000012190 case TARGET_NR_inotify_init:
12191 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012192 if (ret >= 0) {
12193 fd_trans_register(ret, &target_inotify_trans);
12194 }
aurel3239b59762008-10-01 21:46:50 +000012195 break;
12196#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012197#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000012198#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
12199 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010012200 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
12201 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012202 if (ret >= 0) {
12203 fd_trans_register(ret, &target_inotify_trans);
12204 }
Riku Voipioc05c7a72010-03-26 15:25:11 +000012205 break;
12206#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012207#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012208#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012209 case TARGET_NR_inotify_add_watch:
12210 p = lock_user_string(arg2);
12211 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
12212 unlock_user(p, arg2, 0);
12213 break;
12214#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012215#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012216 case TARGET_NR_inotify_rm_watch:
12217 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
12218 break;
12219#endif
ths9007f0e2007-09-25 17:50:37 +000012220
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012221#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012222 case TARGET_NR_mq_open:
12223 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012224 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012225 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012226 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012227
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012228 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012229 pposix_mq_attr = NULL;
12230 if (arg4) {
12231 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
12232 goto efault;
12233 }
12234 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012235 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012236 p = lock_user_string(arg1 - 1);
12237 if (!p) {
12238 goto efault;
12239 }
Lena Djokic26400772016-11-24 17:08:58 +010012240 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012241 unlock_user (p, arg1, 0);
12242 }
12243 break;
12244
12245 case TARGET_NR_mq_unlink:
12246 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012247 if (!p) {
12248 ret = -TARGET_EFAULT;
12249 break;
12250 }
aurel3224e10032009-04-15 16:11:43 +000012251 ret = get_errno(mq_unlink(p));
12252 unlock_user (p, arg1, 0);
12253 break;
12254
12255 case TARGET_NR_mq_timedsend:
12256 {
12257 struct timespec ts;
12258
12259 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12260 if (arg5 != 0) {
12261 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012262 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000012263 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012264 } else {
12265 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012266 }
aurel3224e10032009-04-15 16:11:43 +000012267 unlock_user (p, arg2, arg3);
12268 }
12269 break;
12270
12271 case TARGET_NR_mq_timedreceive:
12272 {
12273 struct timespec ts;
12274 unsigned int prio;
12275
12276 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12277 if (arg5 != 0) {
12278 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012279 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12280 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000012281 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012282 } else {
12283 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12284 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000012285 }
aurel3224e10032009-04-15 16:11:43 +000012286 unlock_user (p, arg2, arg3);
12287 if (arg4 != 0)
12288 put_user_u32(prio, arg4);
12289 }
12290 break;
12291
12292 /* Not implemented for now... */
12293/* case TARGET_NR_mq_notify: */
12294/* break; */
12295
12296 case TARGET_NR_mq_getsetattr:
12297 {
12298 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
12299 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000012300 if (arg2 != 0) {
12301 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070012302 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
12303 &posix_mq_attr_out));
12304 } else if (arg3 != 0) {
12305 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000012306 }
Max Filippova23ea402018-03-31 08:20:15 -070012307 if (ret == 0 && arg3 != 0) {
12308 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
12309 }
aurel3224e10032009-04-15 16:11:43 +000012310 }
12311 break;
12312#endif
12313
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012314#ifdef CONFIG_SPLICE
12315#ifdef TARGET_NR_tee
12316 case TARGET_NR_tee:
12317 {
12318 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12319 }
12320 break;
12321#endif
12322#ifdef TARGET_NR_splice
12323 case TARGET_NR_splice:
12324 {
12325 loff_t loff_in, loff_out;
12326 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012327 if (arg2) {
12328 if (get_user_u64(loff_in, arg2)) {
12329 goto efault;
12330 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012331 ploff_in = &loff_in;
12332 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012333 if (arg4) {
12334 if (get_user_u64(loff_out, arg4)) {
12335 goto efault;
12336 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012337 ploff_out = &loff_out;
12338 }
12339 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012340 if (arg2) {
12341 if (put_user_u64(loff_in, arg2)) {
12342 goto efault;
12343 }
12344 }
12345 if (arg4) {
12346 if (put_user_u64(loff_out, arg4)) {
12347 goto efault;
12348 }
12349 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012350 }
12351 break;
12352#endif
12353#ifdef TARGET_NR_vmsplice
12354 case TARGET_NR_vmsplice:
12355 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012356 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12357 if (vec != NULL) {
12358 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12359 unlock_iovec(vec, arg2, arg3, 0);
12360 } else {
12361 ret = -host_to_target_errno(errno);
12362 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012363 }
12364 break;
12365#endif
12366#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012367#ifdef CONFIG_EVENTFD
12368#if defined(TARGET_NR_eventfd)
12369 case TARGET_NR_eventfd:
12370 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012371 if (ret >= 0) {
12372 fd_trans_register(ret, &target_eventfd_trans);
12373 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012374 break;
12375#endif
12376#if defined(TARGET_NR_eventfd2)
12377 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012378 {
12379 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12380 if (arg2 & TARGET_O_NONBLOCK) {
12381 host_flags |= O_NONBLOCK;
12382 }
12383 if (arg2 & TARGET_O_CLOEXEC) {
12384 host_flags |= O_CLOEXEC;
12385 }
12386 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012387 if (ret >= 0) {
12388 fd_trans_register(ret, &target_eventfd_trans);
12389 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012390 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012391 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012392#endif
12393#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012394#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12395 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012396#if TARGET_ABI_BITS == 32
12397 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12398 target_offset64(arg5, arg6)));
12399#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012400 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012401#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030012402 break;
12403#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012404#if defined(CONFIG_SYNC_FILE_RANGE)
12405#if defined(TARGET_NR_sync_file_range)
12406 case TARGET_NR_sync_file_range:
12407#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012408#if defined(TARGET_MIPS)
12409 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12410 target_offset64(arg5, arg6), arg7));
12411#else
Peter Maydellc727f472011-01-06 11:05:10 +000012412 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12413 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012414#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012415#else
12416 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12417#endif
12418 break;
12419#endif
12420#if defined(TARGET_NR_sync_file_range2)
12421 case TARGET_NR_sync_file_range2:
12422 /* This is like sync_file_range but the arguments are reordered */
12423#if TARGET_ABI_BITS == 32
12424 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12425 target_offset64(arg5, arg6), arg2));
12426#else
12427 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12428#endif
12429 break;
12430#endif
12431#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012432#if defined(TARGET_NR_signalfd4)
12433 case TARGET_NR_signalfd4:
12434 ret = do_signalfd4(arg1, arg2, arg4);
12435 break;
12436#endif
12437#if defined(TARGET_NR_signalfd)
12438 case TARGET_NR_signalfd:
12439 ret = do_signalfd4(arg1, arg2, 0);
12440 break;
12441#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012442#if defined(CONFIG_EPOLL)
12443#if defined(TARGET_NR_epoll_create)
12444 case TARGET_NR_epoll_create:
12445 ret = get_errno(epoll_create(arg1));
12446 break;
12447#endif
12448#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12449 case TARGET_NR_epoll_create1:
12450 ret = get_errno(epoll_create1(arg1));
12451 break;
12452#endif
12453#if defined(TARGET_NR_epoll_ctl)
12454 case TARGET_NR_epoll_ctl:
12455 {
12456 struct epoll_event ep;
12457 struct epoll_event *epp = 0;
12458 if (arg4) {
12459 struct target_epoll_event *target_ep;
12460 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
12461 goto efault;
12462 }
12463 ep.events = tswap32(target_ep->events);
12464 /* The epoll_data_t union is just opaque data to the kernel,
12465 * so we transfer all 64 bits across and need not worry what
12466 * actual data type it is.
12467 */
12468 ep.data.u64 = tswap64(target_ep->data.u64);
12469 unlock_user_struct(target_ep, arg4, 0);
12470 epp = &ep;
12471 }
12472 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12473 break;
12474 }
12475#endif
12476
Peter Maydell227f0212016-06-06 19:58:11 +010012477#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012478#if defined(TARGET_NR_epoll_wait)
12479 case TARGET_NR_epoll_wait:
12480#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012481#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012482 case TARGET_NR_epoll_pwait:
12483#endif
12484 {
12485 struct target_epoll_event *target_ep;
12486 struct epoll_event *ep;
12487 int epfd = arg1;
12488 int maxevents = arg3;
12489 int timeout = arg4;
12490
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012491 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12492 ret = -TARGET_EINVAL;
12493 break;
12494 }
12495
Peter Maydell3b6edd12011-02-15 18:35:05 +000012496 target_ep = lock_user(VERIFY_WRITE, arg2,
12497 maxevents * sizeof(struct target_epoll_event), 1);
12498 if (!target_ep) {
12499 goto efault;
12500 }
12501
Peter Maydell04c95f42016-07-18 15:36:00 +010012502 ep = g_try_new(struct epoll_event, maxevents);
12503 if (!ep) {
12504 unlock_user(target_ep, arg2, 0);
12505 ret = -TARGET_ENOMEM;
12506 break;
12507 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012508
12509 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012510#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012511 case TARGET_NR_epoll_pwait:
12512 {
12513 target_sigset_t *target_set;
12514 sigset_t _set, *set = &_set;
12515
12516 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012517 if (arg6 != sizeof(target_sigset_t)) {
12518 ret = -TARGET_EINVAL;
12519 break;
12520 }
12521
Peter Maydell3b6edd12011-02-15 18:35:05 +000012522 target_set = lock_user(VERIFY_READ, arg5,
12523 sizeof(target_sigset_t), 1);
12524 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012525 ret = -TARGET_EFAULT;
12526 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012527 }
12528 target_to_host_sigset(set, target_set);
12529 unlock_user(target_set, arg5, 0);
12530 } else {
12531 set = NULL;
12532 }
12533
Peter Maydell227f0212016-06-06 19:58:11 +010012534 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12535 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012536 break;
12537 }
12538#endif
12539#if defined(TARGET_NR_epoll_wait)
12540 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012541 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12542 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012543 break;
12544#endif
12545 default:
12546 ret = -TARGET_ENOSYS;
12547 }
12548 if (!is_error(ret)) {
12549 int i;
12550 for (i = 0; i < ret; i++) {
12551 target_ep[i].events = tswap32(ep[i].events);
12552 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12553 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012554 unlock_user(target_ep, arg2,
12555 ret * sizeof(struct target_epoll_event));
12556 } else {
12557 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012558 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012559 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012560 break;
12561 }
12562#endif
12563#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012564#ifdef TARGET_NR_prlimit64
12565 case TARGET_NR_prlimit64:
12566 {
12567 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12568 struct target_rlimit64 *target_rnew, *target_rold;
12569 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012570 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012571 if (arg3) {
12572 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12573 goto efault;
12574 }
12575 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12576 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12577 unlock_user_struct(target_rnew, arg3, 0);
12578 rnewp = &rnew;
12579 }
12580
Felix Janda95018012014-12-02 22:11:17 +010012581 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012582 if (!is_error(ret) && arg4) {
12583 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12584 goto efault;
12585 }
12586 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12587 target_rold->rlim_max = tswap64(rold.rlim_max);
12588 unlock_user_struct(target_rold, arg4, 1);
12589 }
12590 break;
12591 }
12592#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012593#ifdef TARGET_NR_gethostname
12594 case TARGET_NR_gethostname:
12595 {
12596 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12597 if (name) {
12598 ret = get_errno(gethostname(name, arg2));
12599 unlock_user(name, arg1, arg2);
12600 } else {
12601 ret = -TARGET_EFAULT;
12602 }
12603 break;
12604 }
12605#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012606#ifdef TARGET_NR_atomic_cmpxchg_32
12607 case TARGET_NR_atomic_cmpxchg_32:
12608 {
12609 /* should use start_exclusive from main.c */
12610 abi_ulong mem_value;
12611 if (get_user_u32(mem_value, arg6)) {
12612 target_siginfo_t info;
12613 info.si_signo = SIGSEGV;
12614 info.si_errno = 0;
12615 info.si_code = TARGET_SEGV_MAPERR;
12616 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012617 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12618 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012619 ret = 0xdeadbeef;
12620
12621 }
12622 if (mem_value == arg2)
12623 put_user_u32(arg1, arg6);
12624 ret = mem_value;
12625 break;
12626 }
12627#endif
12628#ifdef TARGET_NR_atomic_barrier
12629 case TARGET_NR_atomic_barrier:
12630 {
12631 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012632 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012633 break;
12634 }
12635#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012636
12637#ifdef TARGET_NR_timer_create
12638 case TARGET_NR_timer_create:
12639 {
12640 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12641
12642 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012643
12644 int clkid = arg1;
12645 int timer_index = next_free_host_timer();
12646
12647 if (timer_index < 0) {
12648 ret = -TARGET_EAGAIN;
12649 } else {
12650 timer_t *phtimer = g_posix_timers + timer_index;
12651
12652 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012653 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012654 ret = target_to_host_sigevent(phost_sevp, arg2);
12655 if (ret != 0) {
12656 break;
12657 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012658 }
12659
12660 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12661 if (ret) {
12662 phtimer = NULL;
12663 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012664 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012665 goto efault;
12666 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012667 }
12668 }
12669 break;
12670 }
12671#endif
12672
12673#ifdef TARGET_NR_timer_settime
12674 case TARGET_NR_timer_settime:
12675 {
12676 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12677 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012678 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012679
Alexander Grafaecc8862014-11-10 21:33:03 +010012680 if (timerid < 0) {
12681 ret = timerid;
12682 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012683 ret = -TARGET_EINVAL;
12684 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012685 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012686 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12687
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012688 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12689 goto efault;
12690 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012691 ret = get_errno(
12692 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012693 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12694 goto efault;
12695 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012696 }
12697 break;
12698 }
12699#endif
12700
12701#ifdef TARGET_NR_timer_gettime
12702 case TARGET_NR_timer_gettime:
12703 {
12704 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012705 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012706
Alexander Grafaecc8862014-11-10 21:33:03 +010012707 if (timerid < 0) {
12708 ret = timerid;
12709 } else if (!arg2) {
12710 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012711 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012712 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012713 struct itimerspec hspec;
12714 ret = get_errno(timer_gettime(htimer, &hspec));
12715
12716 if (host_to_target_itimerspec(arg2, &hspec)) {
12717 ret = -TARGET_EFAULT;
12718 }
12719 }
12720 break;
12721 }
12722#endif
12723
12724#ifdef TARGET_NR_timer_getoverrun
12725 case TARGET_NR_timer_getoverrun:
12726 {
12727 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012728 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012729
Alexander Grafaecc8862014-11-10 21:33:03 +010012730 if (timerid < 0) {
12731 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012732 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012733 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012734 ret = get_errno(timer_getoverrun(htimer));
12735 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012736 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012737 break;
12738 }
12739#endif
12740
12741#ifdef TARGET_NR_timer_delete
12742 case TARGET_NR_timer_delete:
12743 {
12744 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012745 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012746
Alexander Grafaecc8862014-11-10 21:33:03 +010012747 if (timerid < 0) {
12748 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012749 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012750 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012751 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012752 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012753 }
12754 break;
12755 }
12756#endif
12757
Riku Voipio51834342014-06-22 11:25:42 +010012758#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12759 case TARGET_NR_timerfd_create:
12760 ret = get_errno(timerfd_create(arg1,
12761 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12762 break;
12763#endif
12764
12765#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12766 case TARGET_NR_timerfd_gettime:
12767 {
12768 struct itimerspec its_curr;
12769
12770 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12771
12772 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12773 goto efault;
12774 }
12775 }
12776 break;
12777#endif
12778
12779#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12780 case TARGET_NR_timerfd_settime:
12781 {
12782 struct itimerspec its_new, its_old, *p_new;
12783
12784 if (arg3) {
12785 if (target_to_host_itimerspec(&its_new, arg3)) {
12786 goto efault;
12787 }
12788 p_new = &its_new;
12789 } else {
12790 p_new = NULL;
12791 }
12792
12793 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12794
12795 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12796 goto efault;
12797 }
12798 }
12799 break;
12800#endif
12801
Paul Burtonab31cda2014-06-22 11:25:43 +010012802#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12803 case TARGET_NR_ioprio_get:
12804 ret = get_errno(ioprio_get(arg1, arg2));
12805 break;
12806#endif
12807
12808#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12809 case TARGET_NR_ioprio_set:
12810 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12811 break;
12812#endif
12813
Riku Voipio9af5c902014-08-12 15:58:57 +030012814#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12815 case TARGET_NR_setns:
12816 ret = get_errno(setns(arg1, arg2));
12817 break;
12818#endif
12819#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12820 case TARGET_NR_unshare:
12821 ret = get_errno(unshare(arg1));
12822 break;
12823#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012824#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12825 case TARGET_NR_kcmp:
12826 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12827 break;
12828#endif
Richard Hendersonfa97e382018-07-18 13:06:48 -070012829#ifdef TARGET_NR_swapcontext
12830 case TARGET_NR_swapcontext:
12831 /* PowerPC specific. */
12832 ret = do_swapcontext(cpu_env, arg1, arg2, arg3);
12833 break;
12834#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012835
bellard31e31b82003-02-18 22:55:36 +000012836 default:
12837 unimplemented:
Philippe Mathieu-Daudé122f9c82018-07-06 12:51:25 -030012838 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012839#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
bellard5cd43932003-03-29 16:54:36 +000012840 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012841#endif
ths0da46a62007-10-20 20:23:07 +000012842 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012843 break;
12844 }
bellard579a97f2007-11-11 14:26:47 +000012845fail:
bellardc573ff62004-01-04 15:51:36 +000012846#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012847 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012848#endif
thsb92c47c2007-11-01 00:07:38 +000012849 if(do_strace)
12850 print_syscall_ret(num, ret);
Lluís Vilanova9c15e702016-06-21 15:52:04 +020012851 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012852 return ret;
bellard579a97f2007-11-11 14:26:47 +000012853efault:
12854 ret = -TARGET_EFAULT;
12855 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012856}