blob: b8b7bced9f1a90aea3ac2762df7518977595ee05 [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);
3846 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003847
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003848 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003849 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003850
3851 if (count > IOV_MAX) {
3852 /* sendrcvmsg returns a different errno for this condition than
3853 * readv/writev, so we must catch it here before lock_iovec() does.
3854 */
3855 ret = -TARGET_EMSGSIZE;
3856 goto out2;
3857 }
3858
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003859 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3860 target_vec, count, send);
3861 if (vec == NULL) {
3862 ret = -host_to_target_errno(errno);
3863 goto out2;
3864 }
bellard3532fa72006-06-24 15:06:03 +00003865 msg.msg_iovlen = count;
3866 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003867
bellard3532fa72006-06-24 15:06:03 +00003868 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003869 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003870 void *host_msg;
3871
3872 host_msg = g_malloc(msg.msg_iov->iov_len);
3873 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3874 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003875 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003876 if (ret >= 0) {
3877 msg.msg_iov->iov_base = host_msg;
3878 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3879 }
3880 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003881 } else {
3882 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003883 if (ret == 0) {
3884 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3885 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003886 }
bellard3532fa72006-06-24 15:06:03 +00003887 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003888 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003889 if (!is_error(ret)) {
3890 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003891 if (fd_trans_host_to_target_data(fd)) {
3892 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003893 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003894 } else {
3895 ret = host_to_target_cmsg(msgp, &msg);
3896 }
Jing Huangca619062012-07-24 13:58:02 +00003897 if (!is_error(ret)) {
3898 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003899 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003900 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3901 msg.msg_name, msg.msg_namelen);
3902 if (ret) {
3903 goto out;
3904 }
3905 }
3906
balrog6de645c2008-10-28 10:26:29 +00003907 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003908 }
balrog6de645c2008-10-28 10:26:29 +00003909 }
bellard3532fa72006-06-24 15:06:03 +00003910 }
Jing Huangca619062012-07-24 13:58:02 +00003911
3912out:
bellard3532fa72006-06-24 15:06:03 +00003913 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003914out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003915 return ret;
3916}
3917
3918static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3919 int flags, int send)
3920{
3921 abi_long ret;
3922 struct target_msghdr *msgp;
3923
3924 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3925 msgp,
3926 target_msg,
3927 send ? 1 : 0)) {
3928 return -TARGET_EFAULT;
3929 }
3930 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003931 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003932 return ret;
3933}
3934
Alexander Graff19e00d2014-03-02 19:36:42 +00003935/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3936 * so it might not have this *mmsg-specific flag either.
3937 */
3938#ifndef MSG_WAITFORONE
3939#define MSG_WAITFORONE 0x10000
3940#endif
3941
3942static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3943 unsigned int vlen, unsigned int flags,
3944 int send)
3945{
3946 struct target_mmsghdr *mmsgp;
3947 abi_long ret = 0;
3948 int i;
3949
3950 if (vlen > UIO_MAXIOV) {
3951 vlen = UIO_MAXIOV;
3952 }
3953
3954 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3955 if (!mmsgp) {
3956 return -TARGET_EFAULT;
3957 }
3958
3959 for (i = 0; i < vlen; i++) {
3960 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3961 if (is_error(ret)) {
3962 break;
3963 }
3964 mmsgp[i].msg_len = tswap32(ret);
3965 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3966 if (flags & MSG_WAITFORONE) {
3967 flags |= MSG_DONTWAIT;
3968 }
3969 }
3970
3971 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3972
3973 /* Return number of datagrams sent if we sent any at all;
3974 * otherwise return the error.
3975 */
3976 if (i) {
3977 return i;
3978 }
3979 return ret;
3980}
Alexander Graff19e00d2014-03-02 19:36:42 +00003981
Peter Maydella94b4982013-02-08 04:35:04 +00003982/* do_accept4() Must return target values and target errnos. */
3983static abi_long do_accept4(int fd, abi_ulong target_addr,
3984 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003985{
bellard2f619692007-11-16 10:46:05 +00003986 socklen_t addrlen;
3987 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003988 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003989 int host_flags;
3990
3991 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003992
Peter Maydella94b4982013-02-08 04:35:04 +00003993 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003994 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003995 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003996
3997 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003998 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003999 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00004000
Blue Swirl38724252010-09-18 05:53:14 +00004001 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004002 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004003 }
aurel328f7aeaf2009-01-30 19:47:57 +00004004
Arnaud Patard917507b2009-06-19 10:44:45 +03004005 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4006 return -TARGET_EINVAL;
4007
bellard2f619692007-11-16 10:46:05 +00004008 addr = alloca(addrlen);
4009
Peter Maydellff6dc132016-06-06 19:58:13 +01004010 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00004011 if (!is_error(ret)) {
4012 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004013 if (put_user_u32(addrlen, target_addrlen_addr))
4014 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004015 }
4016 return ret;
4017}
4018
ths0da46a62007-10-20 20:23:07 +00004019/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004020static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00004021 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004022{
bellard2f619692007-11-16 10:46:05 +00004023 socklen_t addrlen;
4024 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00004025 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004026
bellard2f619692007-11-16 10:46:05 +00004027 if (get_user_u32(addrlen, target_addrlen_addr))
4028 return -TARGET_EFAULT;
4029
Blue Swirl38724252010-09-18 05:53:14 +00004030 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004031 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004032 }
aurel328f7aeaf2009-01-30 19:47:57 +00004033
Arnaud Patard917507b2009-06-19 10:44:45 +03004034 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4035 return -TARGET_EFAULT;
4036
bellard2f619692007-11-16 10:46:05 +00004037 addr = alloca(addrlen);
4038
pbrook1be9e1d2006-11-19 15:26:04 +00004039 ret = get_errno(getpeername(fd, addr, &addrlen));
4040 if (!is_error(ret)) {
4041 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004042 if (put_user_u32(addrlen, target_addrlen_addr))
4043 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004044 }
4045 return ret;
4046}
4047
ths0da46a62007-10-20 20:23:07 +00004048/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004049static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00004050 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004051{
bellard2f619692007-11-16 10:46:05 +00004052 socklen_t addrlen;
4053 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00004054 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004055
bellard2f619692007-11-16 10:46:05 +00004056 if (get_user_u32(addrlen, target_addrlen_addr))
4057 return -TARGET_EFAULT;
4058
Blue Swirl38724252010-09-18 05:53:14 +00004059 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004060 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004061 }
aurel328f7aeaf2009-01-30 19:47:57 +00004062
Arnaud Patard917507b2009-06-19 10:44:45 +03004063 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
4064 return -TARGET_EFAULT;
4065
bellard2f619692007-11-16 10:46:05 +00004066 addr = alloca(addrlen);
4067
pbrook1be9e1d2006-11-19 15:26:04 +00004068 ret = get_errno(getsockname(fd, addr, &addrlen));
4069 if (!is_error(ret)) {
4070 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004071 if (put_user_u32(addrlen, target_addrlen_addr))
4072 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004073 }
4074 return ret;
4075}
4076
ths0da46a62007-10-20 20:23:07 +00004077/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004078static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00004079 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004080{
4081 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00004082 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004083
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02004084 target_to_host_sock_type(&type);
4085
pbrook1be9e1d2006-11-19 15:26:04 +00004086 ret = get_errno(socketpair(domain, type, protocol, tab));
4087 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00004088 if (put_user_s32(tab[0], target_tab_addr)
4089 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
4090 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004091 }
4092 return ret;
4093}
4094
ths0da46a62007-10-20 20:23:07 +00004095/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004096static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
4097 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004098{
4099 void *addr;
4100 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02004101 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00004102 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004103
Blue Swirl38724252010-09-18 05:53:14 +00004104 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004105 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004106 }
aurel328f7aeaf2009-01-30 19:47:57 +00004107
bellard579a97f2007-11-11 14:26:47 +00004108 host_msg = lock_user(VERIFY_READ, msg, len, 1);
4109 if (!host_msg)
4110 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004111 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004112 copy_msg = host_msg;
4113 host_msg = g_malloc(len);
4114 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004115 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
4116 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004117 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004118 }
4119 }
pbrook1be9e1d2006-11-19 15:26:04 +00004120 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02004121 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01004122 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03004123 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004124 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03004125 }
Peter Maydell66687532016-06-06 19:58:04 +01004126 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004127 } else {
Peter Maydell66687532016-06-06 19:58:04 +01004128 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004129 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02004130fail:
4131 if (copy_msg) {
4132 g_free(host_msg);
4133 host_msg = copy_msg;
4134 }
pbrook1be9e1d2006-11-19 15:26:04 +00004135 unlock_user(host_msg, msg, 0);
4136 return ret;
4137}
4138
ths0da46a62007-10-20 20:23:07 +00004139/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004140static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4141 abi_ulong target_addr,
4142 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004143{
4144 socklen_t addrlen;
4145 void *addr;
4146 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004147 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004148
bellard579a97f2007-11-11 14:26:47 +00004149 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4150 if (!host_msg)
4151 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004152 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004153 if (get_user_u32(addrlen, target_addrlen)) {
4154 ret = -TARGET_EFAULT;
4155 goto fail;
4156 }
Blue Swirl38724252010-09-18 05:53:14 +00004157 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004158 ret = -TARGET_EINVAL;
4159 goto fail;
4160 }
pbrook1be9e1d2006-11-19 15:26:04 +00004161 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004162 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4163 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004164 } else {
4165 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004166 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004167 }
4168 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004169 if (fd_trans_host_to_target_data(fd)) {
4170 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4171 }
pbrook1be9e1d2006-11-19 15:26:04 +00004172 if (target_addr) {
4173 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004174 if (put_user_u32(addrlen, target_addrlen)) {
4175 ret = -TARGET_EFAULT;
4176 goto fail;
4177 }
pbrook1be9e1d2006-11-19 15:26:04 +00004178 }
4179 unlock_user(host_msg, msg, len);
4180 } else {
bellard2f619692007-11-16 10:46:05 +00004181fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004182 unlock_user(host_msg, msg, 0);
4183 }
4184 return ret;
4185}
4186
j_mayer32407102007-09-26 23:01:49 +00004187#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004188/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004189static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004190{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004191 static const unsigned nargs[] = { /* number of arguments per operation */
4192 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4193 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4194 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4195 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4196 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4197 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4198 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4199 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4200 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4201 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4202 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4203 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4204 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4205 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4206 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4207 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4208 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4209 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4210 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4211 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004212 };
4213 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004214 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004215
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004216 /* check the range of the first argument num */
4217 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4218 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4219 return -TARGET_EINVAL;
4220 }
4221 /* ensure we have space for args */
4222 if (nargs[num] > ARRAY_SIZE(a)) {
4223 return -TARGET_EINVAL;
4224 }
4225 /* collect the arguments in a[] according to nargs[] */
4226 for (i = 0; i < nargs[num]; ++i) {
4227 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4228 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004229 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004230 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004231 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004232 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004233 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004234 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004235 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004236 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004237 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004238 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004239 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004240 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004241 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004242 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004243 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004244 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004245 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004246 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004247 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004248 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004249 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004250 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004251 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004252 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004253 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004254 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004255 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004256 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004257 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004258 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004259 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004260 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004261 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004262 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004263 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4264 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4265 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4266 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4267 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4268 return do_accept4(a[0], a[1], a[2], a[3]);
4269 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4270 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4271 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4272 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004273 default:
4274 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004275 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004276 }
bellard31e31b82003-02-18 22:55:36 +00004277}
j_mayer32407102007-09-26 23:01:49 +00004278#endif
bellard31e31b82003-02-18 22:55:36 +00004279
bellard8853f862004-02-22 14:57:26 +00004280#define N_SHM_REGIONS 32
4281
4282static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004283 abi_ulong start;
4284 abi_ulong size;
4285 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004286} shm_regions[N_SHM_REGIONS];
4287
Peter Maydell005eb2a2016-07-15 16:50:47 +01004288#ifndef TARGET_SEMID64_DS
4289/* asm-generic version of this struct */
4290struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004291{
4292 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004293 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004294#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004295 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004296#endif
blueswir1992f48a2007-10-14 16:27:31 +00004297 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004298#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004299 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004300#endif
blueswir1992f48a2007-10-14 16:27:31 +00004301 abi_ulong sem_nsems;
4302 abi_ulong __unused3;
4303 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004304};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004305#endif
ths3eb6b042007-06-03 14:26:27 +00004306
bellard579a97f2007-11-11 14:26:47 +00004307static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4308 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004309{
4310 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004311 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004312
bellard579a97f2007-11-11 14:26:47 +00004313 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4314 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004315 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004316 host_ip->__key = tswap32(target_ip->__key);
4317 host_ip->uid = tswap32(target_ip->uid);
4318 host_ip->gid = tswap32(target_ip->gid);
4319 host_ip->cuid = tswap32(target_ip->cuid);
4320 host_ip->cgid = tswap32(target_ip->cgid);
4321#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4322 host_ip->mode = tswap32(target_ip->mode);
4323#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004324 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004325#endif
4326#if defined(TARGET_PPC)
4327 host_ip->__seq = tswap32(target_ip->__seq);
4328#else
4329 host_ip->__seq = tswap16(target_ip->__seq);
4330#endif
ths3eb6b042007-06-03 14:26:27 +00004331 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004332 return 0;
ths3eb6b042007-06-03 14:26:27 +00004333}
4334
bellard579a97f2007-11-11 14:26:47 +00004335static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4336 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004337{
4338 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004339 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004340
bellard579a97f2007-11-11 14:26:47 +00004341 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4342 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004343 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004344 target_ip->__key = tswap32(host_ip->__key);
4345 target_ip->uid = tswap32(host_ip->uid);
4346 target_ip->gid = tswap32(host_ip->gid);
4347 target_ip->cuid = tswap32(host_ip->cuid);
4348 target_ip->cgid = tswap32(host_ip->cgid);
4349#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4350 target_ip->mode = tswap32(host_ip->mode);
4351#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004352 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004353#endif
4354#if defined(TARGET_PPC)
4355 target_ip->__seq = tswap32(host_ip->__seq);
4356#else
4357 target_ip->__seq = tswap16(host_ip->__seq);
4358#endif
ths3eb6b042007-06-03 14:26:27 +00004359 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004360 return 0;
ths3eb6b042007-06-03 14:26:27 +00004361}
4362
bellard579a97f2007-11-11 14:26:47 +00004363static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4364 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004365{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004366 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004367
bellard579a97f2007-11-11 14:26:47 +00004368 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4369 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004370 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4371 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004372 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4373 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4374 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004375 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004376 return 0;
ths3eb6b042007-06-03 14:26:27 +00004377}
4378
bellard579a97f2007-11-11 14:26:47 +00004379static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4380 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004381{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004382 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004383
bellard579a97f2007-11-11 14:26:47 +00004384 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4385 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004386 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004387 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004388 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4389 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4390 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004391 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004392 return 0;
ths3eb6b042007-06-03 14:26:27 +00004393}
4394
aurel32e5289082009-04-18 16:16:12 +00004395struct target_seminfo {
4396 int semmap;
4397 int semmni;
4398 int semmns;
4399 int semmnu;
4400 int semmsl;
4401 int semopm;
4402 int semume;
4403 int semusz;
4404 int semvmx;
4405 int semaem;
4406};
4407
4408static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4409 struct seminfo *host_seminfo)
4410{
4411 struct target_seminfo *target_seminfo;
4412 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4413 return -TARGET_EFAULT;
4414 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4415 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4416 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4417 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4418 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4419 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4420 __put_user(host_seminfo->semume, &target_seminfo->semume);
4421 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4422 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4423 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4424 unlock_user_struct(target_seminfo, target_addr, 1);
4425 return 0;
4426}
4427
thsfa294812007-02-02 22:05:00 +00004428union semun {
4429 int val;
ths3eb6b042007-06-03 14:26:27 +00004430 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004431 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004432 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004433};
4434
ths3eb6b042007-06-03 14:26:27 +00004435union target_semun {
4436 int val;
aurel32e5289082009-04-18 16:16:12 +00004437 abi_ulong buf;
4438 abi_ulong array;
4439 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004440};
4441
aurel32e5289082009-04-18 16:16:12 +00004442static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4443 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004444{
aurel32e5289082009-04-18 16:16:12 +00004445 int nsems;
4446 unsigned short *array;
4447 union semun semun;
4448 struct semid_ds semid_ds;
4449 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004450
aurel32e5289082009-04-18 16:16:12 +00004451 semun.buf = &semid_ds;
4452
4453 ret = semctl(semid, 0, IPC_STAT, semun);
4454 if (ret == -1)
4455 return get_errno(ret);
4456
4457 nsems = semid_ds.sem_nsems;
4458
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304459 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004460 if (!*host_array) {
4461 return -TARGET_ENOMEM;
4462 }
aurel32e5289082009-04-18 16:16:12 +00004463 array = lock_user(VERIFY_READ, target_addr,
4464 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004465 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304466 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004467 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004468 }
aurel32e5289082009-04-18 16:16:12 +00004469
4470 for(i=0; i<nsems; i++) {
4471 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004472 }
aurel32e5289082009-04-18 16:16:12 +00004473 unlock_user(array, target_addr, 0);
4474
bellard579a97f2007-11-11 14:26:47 +00004475 return 0;
ths3eb6b042007-06-03 14:26:27 +00004476}
4477
aurel32e5289082009-04-18 16:16:12 +00004478static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4479 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004480{
aurel32e5289082009-04-18 16:16:12 +00004481 int nsems;
4482 unsigned short *array;
4483 union semun semun;
4484 struct semid_ds semid_ds;
4485 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004486
aurel32e5289082009-04-18 16:16:12 +00004487 semun.buf = &semid_ds;
4488
4489 ret = semctl(semid, 0, IPC_STAT, semun);
4490 if (ret == -1)
4491 return get_errno(ret);
4492
4493 nsems = semid_ds.sem_nsems;
4494
4495 array = lock_user(VERIFY_WRITE, target_addr,
4496 nsems*sizeof(unsigned short), 0);
4497 if (!array)
4498 return -TARGET_EFAULT;
4499
4500 for(i=0; i<nsems; i++) {
4501 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004502 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304503 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004504 unlock_user(array, target_addr, 1);
4505
bellard579a97f2007-11-11 14:26:47 +00004506 return 0;
ths3eb6b042007-06-03 14:26:27 +00004507}
4508
aurel32e5289082009-04-18 16:16:12 +00004509static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004510 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004511{
Stefan Weild1c002b2015-02-08 15:40:58 +01004512 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004513 union semun arg;
4514 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304515 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004516 struct seminfo seminfo;
4517 abi_long ret = -TARGET_EINVAL;
4518 abi_long err;
4519 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004520
4521 switch( cmd ) {
4522 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004523 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004524 /* In 64 bit cross-endian situations, we will erroneously pick up
4525 * the wrong half of the union for the "val" element. To rectify
4526 * this, the entire 8-byte structure is byteswapped, followed by
4527 * a swap of the 4 byte val field. In other cases, the data is
4528 * already in proper host byte order. */
4529 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4530 target_su.buf = tswapal(target_su.buf);
4531 arg.val = tswap32(target_su.val);
4532 } else {
4533 arg.val = target_su.val;
4534 }
aurel32e5289082009-04-18 16:16:12 +00004535 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004536 break;
4537 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004538 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004539 err = target_to_host_semarray(semid, &array, target_su.array);
4540 if (err)
4541 return err;
4542 arg.array = array;
4543 ret = get_errno(semctl(semid, semnum, cmd, arg));
4544 err = host_to_target_semarray(semid, target_su.array, &array);
4545 if (err)
4546 return err;
ths3eb6b042007-06-03 14:26:27 +00004547 break;
4548 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004549 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004550 case SEM_STAT:
4551 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4552 if (err)
4553 return err;
4554 arg.buf = &dsarg;
4555 ret = get_errno(semctl(semid, semnum, cmd, arg));
4556 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4557 if (err)
4558 return err;
ths3eb6b042007-06-03 14:26:27 +00004559 break;
aurel32e5289082009-04-18 16:16:12 +00004560 case IPC_INFO:
4561 case SEM_INFO:
4562 arg.__buf = &seminfo;
4563 ret = get_errno(semctl(semid, semnum, cmd, arg));
4564 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4565 if (err)
4566 return err;
4567 break;
4568 case IPC_RMID:
4569 case GETPID:
4570 case GETNCNT:
4571 case GETZCNT:
4572 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4573 break;
ths3eb6b042007-06-03 14:26:27 +00004574 }
4575
4576 return ret;
4577}
4578
aurel32e5289082009-04-18 16:16:12 +00004579struct target_sembuf {
4580 unsigned short sem_num;
4581 short sem_op;
4582 short sem_flg;
4583};
4584
4585static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4586 abi_ulong target_addr,
4587 unsigned nsops)
4588{
4589 struct target_sembuf *target_sembuf;
4590 int i;
4591
4592 target_sembuf = lock_user(VERIFY_READ, target_addr,
4593 nsops*sizeof(struct target_sembuf), 1);
4594 if (!target_sembuf)
4595 return -TARGET_EFAULT;
4596
4597 for(i=0; i<nsops; i++) {
4598 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4599 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4600 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4601 }
4602
4603 unlock_user(target_sembuf, target_addr, 0);
4604
4605 return 0;
4606}
4607
4608static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4609{
4610 struct sembuf sops[nsops];
4611
4612 if (target_to_host_sembuf(sops, ptr, nsops))
4613 return -TARGET_EFAULT;
4614
Peter Maydellffb7ee72016-06-06 19:58:12 +01004615 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004616}
4617
ths1bc012f2007-06-03 14:27:49 +00004618struct target_msqid_ds
4619{
aurel321c54ff92008-10-13 21:08:44 +00004620 struct target_ipc_perm msg_perm;
4621 abi_ulong msg_stime;
4622#if TARGET_ABI_BITS == 32
4623 abi_ulong __unused1;
4624#endif
4625 abi_ulong msg_rtime;
4626#if TARGET_ABI_BITS == 32
4627 abi_ulong __unused2;
4628#endif
4629 abi_ulong msg_ctime;
4630#if TARGET_ABI_BITS == 32
4631 abi_ulong __unused3;
4632#endif
4633 abi_ulong __msg_cbytes;
4634 abi_ulong msg_qnum;
4635 abi_ulong msg_qbytes;
4636 abi_ulong msg_lspid;
4637 abi_ulong msg_lrpid;
4638 abi_ulong __unused4;
4639 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004640};
4641
bellard579a97f2007-11-11 14:26:47 +00004642static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4643 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004644{
4645 struct target_msqid_ds *target_md;
4646
bellard579a97f2007-11-11 14:26:47 +00004647 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4648 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004649 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4650 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004651 host_md->msg_stime = tswapal(target_md->msg_stime);
4652 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4653 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4654 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4655 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4656 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4657 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4658 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004659 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004660 return 0;
ths1bc012f2007-06-03 14:27:49 +00004661}
4662
bellard579a97f2007-11-11 14:26:47 +00004663static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4664 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004665{
4666 struct target_msqid_ds *target_md;
4667
bellard579a97f2007-11-11 14:26:47 +00004668 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4669 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004670 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4671 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004672 target_md->msg_stime = tswapal(host_md->msg_stime);
4673 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4674 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4675 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4676 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4677 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4678 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4679 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004680 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004681 return 0;
ths1bc012f2007-06-03 14:27:49 +00004682}
4683
aurel321c54ff92008-10-13 21:08:44 +00004684struct target_msginfo {
4685 int msgpool;
4686 int msgmap;
4687 int msgmax;
4688 int msgmnb;
4689 int msgmni;
4690 int msgssz;
4691 int msgtql;
4692 unsigned short int msgseg;
4693};
4694
4695static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4696 struct msginfo *host_msginfo)
4697{
4698 struct target_msginfo *target_msginfo;
4699 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4700 return -TARGET_EFAULT;
4701 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4702 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4703 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4704 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4705 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4706 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4707 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4708 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4709 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004710 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004711}
4712
4713static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004714{
4715 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004716 struct msginfo msginfo;
4717 abi_long ret = -TARGET_EINVAL;
4718
4719 cmd &= 0xff;
4720
4721 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004722 case IPC_STAT:
4723 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004724 case MSG_STAT:
4725 if (target_to_host_msqid_ds(&dsarg,ptr))
4726 return -TARGET_EFAULT;
4727 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4728 if (host_to_target_msqid_ds(ptr,&dsarg))
4729 return -TARGET_EFAULT;
4730 break;
4731 case IPC_RMID:
4732 ret = get_errno(msgctl(msgid, cmd, NULL));
4733 break;
4734 case IPC_INFO:
4735 case MSG_INFO:
4736 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4737 if (host_to_target_msginfo(ptr, &msginfo))
4738 return -TARGET_EFAULT;
4739 break;
ths1bc012f2007-06-03 14:27:49 +00004740 }
aurel321c54ff92008-10-13 21:08:44 +00004741
ths1bc012f2007-06-03 14:27:49 +00004742 return ret;
4743}
4744
4745struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004746 abi_long mtype;
4747 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004748};
4749
blueswir1992f48a2007-10-14 16:27:31 +00004750static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004751 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004752{
4753 struct target_msgbuf *target_mb;
4754 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004755 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004756
Tom Mustaedcc5f92014-08-12 13:53:37 -05004757 if (msgsz < 0) {
4758 return -TARGET_EINVAL;
4759 }
4760
bellard579a97f2007-11-11 14:26:47 +00004761 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4762 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304763 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004764 if (!host_mb) {
4765 unlock_user_struct(target_mb, msgp, 0);
4766 return -TARGET_ENOMEM;
4767 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004768 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004769 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004770 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304771 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004772 unlock_user_struct(target_mb, msgp, 0);
4773
4774 return ret;
4775}
4776
blueswir1992f48a2007-10-14 16:27:31 +00004777static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004778 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004779 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004780{
4781 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004782 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004783 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004784 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004785
Peter Maydell99874f62016-05-20 19:00:56 +01004786 if (msgsz < 0) {
4787 return -TARGET_EINVAL;
4788 }
4789
bellard579a97f2007-11-11 14:26:47 +00004790 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4791 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004792
Peter Maydell415d8472016-05-20 19:00:57 +01004793 host_mb = g_try_malloc(msgsz + sizeof(long));
4794 if (!host_mb) {
4795 ret = -TARGET_ENOMEM;
4796 goto end;
4797 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004798 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004799
bellard579a97f2007-11-11 14:26:47 +00004800 if (ret > 0) {
4801 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4802 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4803 if (!target_mtext) {
4804 ret = -TARGET_EFAULT;
4805 goto end;
4806 }
aurel321c54ff92008-10-13 21:08:44 +00004807 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004808 unlock_user(target_mtext, target_mtext_addr, ret);
4809 }
aurel321c54ff92008-10-13 21:08:44 +00004810
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004811 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004812
bellard579a97f2007-11-11 14:26:47 +00004813end:
4814 if (target_mb)
4815 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004816 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004817 return ret;
4818}
4819
Riku Voipio88a8c982009-04-03 10:42:00 +03004820static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4821 abi_ulong target_addr)
4822{
4823 struct target_shmid_ds *target_sd;
4824
4825 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4826 return -TARGET_EFAULT;
4827 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4828 return -TARGET_EFAULT;
4829 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4830 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4831 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4832 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4833 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4834 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4835 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4836 unlock_user_struct(target_sd, target_addr, 0);
4837 return 0;
4838}
4839
4840static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4841 struct shmid_ds *host_sd)
4842{
4843 struct target_shmid_ds *target_sd;
4844
4845 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4846 return -TARGET_EFAULT;
4847 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4848 return -TARGET_EFAULT;
4849 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4850 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4851 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4852 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4853 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4854 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4855 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4856 unlock_user_struct(target_sd, target_addr, 1);
4857 return 0;
4858}
4859
4860struct target_shminfo {
4861 abi_ulong shmmax;
4862 abi_ulong shmmin;
4863 abi_ulong shmmni;
4864 abi_ulong shmseg;
4865 abi_ulong shmall;
4866};
4867
4868static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4869 struct shminfo *host_shminfo)
4870{
4871 struct target_shminfo *target_shminfo;
4872 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4873 return -TARGET_EFAULT;
4874 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4875 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4876 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4877 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4878 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4879 unlock_user_struct(target_shminfo, target_addr, 1);
4880 return 0;
4881}
4882
4883struct target_shm_info {
4884 int used_ids;
4885 abi_ulong shm_tot;
4886 abi_ulong shm_rss;
4887 abi_ulong shm_swp;
4888 abi_ulong swap_attempts;
4889 abi_ulong swap_successes;
4890};
4891
4892static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4893 struct shm_info *host_shm_info)
4894{
4895 struct target_shm_info *target_shm_info;
4896 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4897 return -TARGET_EFAULT;
4898 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4899 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4900 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4901 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4902 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4903 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4904 unlock_user_struct(target_shm_info, target_addr, 1);
4905 return 0;
4906}
4907
4908static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4909{
4910 struct shmid_ds dsarg;
4911 struct shminfo shminfo;
4912 struct shm_info shm_info;
4913 abi_long ret = -TARGET_EINVAL;
4914
4915 cmd &= 0xff;
4916
4917 switch(cmd) {
4918 case IPC_STAT:
4919 case IPC_SET:
4920 case SHM_STAT:
4921 if (target_to_host_shmid_ds(&dsarg, buf))
4922 return -TARGET_EFAULT;
4923 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4924 if (host_to_target_shmid_ds(buf, &dsarg))
4925 return -TARGET_EFAULT;
4926 break;
4927 case IPC_INFO:
4928 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4929 if (host_to_target_shminfo(buf, &shminfo))
4930 return -TARGET_EFAULT;
4931 break;
4932 case SHM_INFO:
4933 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4934 if (host_to_target_shm_info(buf, &shm_info))
4935 return -TARGET_EFAULT;
4936 break;
4937 case IPC_RMID:
4938 case SHM_LOCK:
4939 case SHM_UNLOCK:
4940 ret = get_errno(shmctl(shmid, cmd, NULL));
4941 break;
4942 }
4943
4944 return ret;
4945}
4946
Peter Maydellee8e7612016-07-11 16:48:11 +01004947#ifndef TARGET_FORCE_SHMLBA
4948/* For most architectures, SHMLBA is the same as the page size;
4949 * some architectures have larger values, in which case they should
4950 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4951 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4952 * and defining its own value for SHMLBA.
4953 *
4954 * The kernel also permits SHMLBA to be set by the architecture to a
4955 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4956 * this means that addresses are rounded to the large size if
4957 * SHM_RND is set but addresses not aligned to that size are not rejected
4958 * as long as they are at least page-aligned. Since the only architecture
4959 * which uses this is ia64 this code doesn't provide for that oddity.
4960 */
4961static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4962{
4963 return TARGET_PAGE_SIZE;
4964}
4965#endif
4966
4967static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4968 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004969{
4970 abi_long raddr;
4971 void *host_raddr;
4972 struct shmid_ds shm_info;
4973 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004974 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004975
4976 /* find out the length of the shared memory segment */
4977 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4978 if (is_error(ret)) {
4979 /* can't get length, bail out */
4980 return ret;
4981 }
4982
Peter Maydellee8e7612016-07-11 16:48:11 +01004983 shmlba = target_shmlba(cpu_env);
4984
4985 if (shmaddr & (shmlba - 1)) {
4986 if (shmflg & SHM_RND) {
4987 shmaddr &= ~(shmlba - 1);
4988 } else {
4989 return -TARGET_EINVAL;
4990 }
4991 }
Max Filippovebf9a362018-03-07 13:50:10 -08004992 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
4993 return -TARGET_EINVAL;
4994 }
Peter Maydellee8e7612016-07-11 16:48:11 +01004995
Riku Voipio88a8c982009-04-03 10:42:00 +03004996 mmap_lock();
4997
4998 if (shmaddr)
4999 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
5000 else {
5001 abi_ulong mmap_start;
5002
5003 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
5004
5005 if (mmap_start == -1) {
5006 errno = ENOMEM;
5007 host_raddr = (void *)-1;
5008 } else
5009 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
5010 }
5011
5012 if (host_raddr == (void *)-1) {
5013 mmap_unlock();
5014 return get_errno((long)host_raddr);
5015 }
5016 raddr=h2g((unsigned long)host_raddr);
5017
5018 page_set_flags(raddr, raddr + shm_info.shm_segsz,
5019 PAGE_VALID | PAGE_READ |
5020 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
5021
5022 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00005023 if (!shm_regions[i].in_use) {
5024 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03005025 shm_regions[i].start = raddr;
5026 shm_regions[i].size = shm_info.shm_segsz;
5027 break;
5028 }
5029 }
5030
5031 mmap_unlock();
5032 return raddr;
5033
5034}
5035
5036static inline abi_long do_shmdt(abi_ulong shmaddr)
5037{
5038 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08005039 abi_long rv;
5040
5041 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03005042
5043 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00005044 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
5045 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09005046 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03005047 break;
5048 }
5049 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08005050 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03005051
Max Filippov3c5f6a52018-02-28 14:16:04 -08005052 mmap_unlock();
5053
5054 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03005055}
5056
aurel321c54ff92008-10-13 21:08:44 +00005057#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00005058/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00005059/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01005060static abi_long do_ipc(CPUArchState *cpu_env,
5061 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05005062 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00005063 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00005064{
5065 int version;
blueswir1992f48a2007-10-14 16:27:31 +00005066 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00005067
5068 version = call >> 16;
5069 call &= 0xffff;
5070
5071 switch (call) {
thsfa294812007-02-02 22:05:00 +00005072 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00005073 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00005074 break;
5075
5076 case IPCOP_semget:
5077 ret = get_errno(semget(first, second, third));
5078 break;
5079
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005080 case IPCOP_semctl: {
5081 /* The semun argument to semctl is passed by value, so dereference the
5082 * ptr argument. */
5083 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05005084 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01005085 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00005086 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005087 }
thsd96372e2007-02-02 22:05:44 +00005088
aurel321c54ff92008-10-13 21:08:44 +00005089 case IPCOP_msgget:
5090 ret = get_errno(msgget(first, second));
5091 break;
thsd96372e2007-02-02 22:05:44 +00005092
aurel321c54ff92008-10-13 21:08:44 +00005093 case IPCOP_msgsnd:
5094 ret = do_msgsnd(first, ptr, second, third);
5095 break;
thsd96372e2007-02-02 22:05:44 +00005096
aurel321c54ff92008-10-13 21:08:44 +00005097 case IPCOP_msgctl:
5098 ret = do_msgctl(first, second, ptr);
5099 break;
thsd96372e2007-02-02 22:05:44 +00005100
aurel321c54ff92008-10-13 21:08:44 +00005101 case IPCOP_msgrcv:
5102 switch (version) {
5103 case 0:
5104 {
5105 struct target_ipc_kludge {
5106 abi_long msgp;
5107 abi_long msgtyp;
5108 } *tmp;
thsd96372e2007-02-02 22:05:44 +00005109
aurel321c54ff92008-10-13 21:08:44 +00005110 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
5111 ret = -TARGET_EFAULT;
5112 break;
ths1bc012f2007-06-03 14:27:49 +00005113 }
aurel321c54ff92008-10-13 21:08:44 +00005114
Laurent Vivier79dd77d2012-12-20 11:00:11 +00005115 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00005116
5117 unlock_user_struct(tmp, ptr, 0);
5118 break;
5119 }
5120 default:
5121 ret = do_msgrcv(first, ptr, second, fifth, third);
5122 }
5123 break;
thsd96372e2007-02-02 22:05:44 +00005124
bellard8853f862004-02-22 14:57:26 +00005125 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03005126 switch (version) {
5127 default:
bellard5a4a8982007-11-11 17:39:18 +00005128 {
5129 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01005130 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03005131 if (is_error(raddr))
5132 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00005133 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00005134 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03005135 break;
5136 }
5137 case 1:
5138 ret = -TARGET_EINVAL;
5139 break;
bellard5a4a8982007-11-11 17:39:18 +00005140 }
bellard8853f862004-02-22 14:57:26 +00005141 break;
5142 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03005143 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00005144 break;
5145
5146 case IPCOP_shmget:
5147 /* IPC_* flag values are the same on all linux platforms */
5148 ret = get_errno(shmget(first, second, third));
5149 break;
5150
5151 /* IPC_* and SHM_* command values are the same on all linux platforms */
5152 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005153 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005154 break;
5155 default:
j_mayer32407102007-09-26 23:01:49 +00005156 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005157 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005158 break;
5159 }
5160 return ret;
5161}
j_mayer32407102007-09-26 23:01:49 +00005162#endif
bellard8853f862004-02-22 14:57:26 +00005163
bellard31e31b82003-02-18 22:55:36 +00005164/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005165
Blue Swirl001faf32009-05-13 17:53:17 +00005166#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005167#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5168enum {
5169#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005170STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005171};
5172#undef STRUCT
5173#undef STRUCT_SPECIAL
5174
Blue Swirl001faf32009-05-13 17:53:17 +00005175#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005176#define STRUCT_SPECIAL(name)
5177#include "syscall_types.h"
5178#undef STRUCT
5179#undef STRUCT_SPECIAL
5180
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005181typedef struct IOCTLEntry IOCTLEntry;
5182
5183typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005184 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005185
5186struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005187 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005188 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005189 const char *name;
5190 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005191 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005192 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005193};
bellard31e31b82003-02-18 22:55:36 +00005194
5195#define IOC_R 0x0001
5196#define IOC_W 0x0002
5197#define IOC_RW (IOC_R | IOC_W)
5198
5199#define MAX_STRUCT_SIZE 4096
5200
Peter Maydelldace20d2011-01-10 13:11:24 +00005201#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005202/* So fiemap access checks don't overflow on 32 bit systems.
5203 * This is very slightly smaller than the limit imposed by
5204 * the underlying kernel.
5205 */
5206#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5207 / sizeof(struct fiemap_extent))
5208
5209static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005210 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005211{
5212 /* The parameter for this ioctl is a struct fiemap followed
5213 * by an array of struct fiemap_extent whose size is set
5214 * in fiemap->fm_extent_count. The array is filled in by the
5215 * ioctl.
5216 */
5217 int target_size_in, target_size_out;
5218 struct fiemap *fm;
5219 const argtype *arg_type = ie->arg_type;
5220 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5221 void *argptr, *p;
5222 abi_long ret;
5223 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5224 uint32_t outbufsz;
5225 int free_fm = 0;
5226
5227 assert(arg_type[0] == TYPE_PTR);
5228 assert(ie->access == IOC_RW);
5229 arg_type++;
5230 target_size_in = thunk_type_size(arg_type, 0);
5231 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5232 if (!argptr) {
5233 return -TARGET_EFAULT;
5234 }
5235 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5236 unlock_user(argptr, arg, 0);
5237 fm = (struct fiemap *)buf_temp;
5238 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5239 return -TARGET_EINVAL;
5240 }
5241
5242 outbufsz = sizeof (*fm) +
5243 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5244
5245 if (outbufsz > MAX_STRUCT_SIZE) {
5246 /* We can't fit all the extents into the fixed size buffer.
5247 * Allocate one that is large enough and use it instead.
5248 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305249 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005250 if (!fm) {
5251 return -TARGET_ENOMEM;
5252 }
5253 memcpy(fm, buf_temp, sizeof(struct fiemap));
5254 free_fm = 1;
5255 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005256 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005257 if (!is_error(ret)) {
5258 target_size_out = target_size_in;
5259 /* An extent_count of 0 means we were only counting the extents
5260 * so there are no structs to copy
5261 */
5262 if (fm->fm_extent_count != 0) {
5263 target_size_out += fm->fm_mapped_extents * extent_size;
5264 }
5265 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5266 if (!argptr) {
5267 ret = -TARGET_EFAULT;
5268 } else {
5269 /* Convert the struct fiemap */
5270 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5271 if (fm->fm_extent_count != 0) {
5272 p = argptr + target_size_in;
5273 /* ...and then all the struct fiemap_extents */
5274 for (i = 0; i < fm->fm_mapped_extents; i++) {
5275 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5276 THUNK_TARGET);
5277 p += extent_size;
5278 }
5279 }
5280 unlock_user(argptr, arg, target_size_out);
5281 }
5282 }
5283 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305284 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005285 }
5286 return ret;
5287}
Peter Maydelldace20d2011-01-10 13:11:24 +00005288#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005289
Laurent Vivier059c2f22011-03-30 00:12:12 +02005290static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005291 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005292{
5293 const argtype *arg_type = ie->arg_type;
5294 int target_size;
5295 void *argptr;
5296 int ret;
5297 struct ifconf *host_ifconf;
5298 uint32_t outbufsz;
5299 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5300 int target_ifreq_size;
5301 int nb_ifreq;
5302 int free_buf = 0;
5303 int i;
5304 int target_ifc_len;
5305 abi_long target_ifc_buf;
5306 int host_ifc_len;
5307 char *host_ifc_buf;
5308
5309 assert(arg_type[0] == TYPE_PTR);
5310 assert(ie->access == IOC_RW);
5311
5312 arg_type++;
5313 target_size = thunk_type_size(arg_type, 0);
5314
5315 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5316 if (!argptr)
5317 return -TARGET_EFAULT;
5318 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5319 unlock_user(argptr, arg, 0);
5320
5321 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5322 target_ifc_len = host_ifconf->ifc_len;
5323 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5324
5325 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5326 nb_ifreq = target_ifc_len / target_ifreq_size;
5327 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5328
5329 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5330 if (outbufsz > MAX_STRUCT_SIZE) {
5331 /* We can't fit all the extents into the fixed size buffer.
5332 * Allocate one that is large enough and use it instead.
5333 */
5334 host_ifconf = malloc(outbufsz);
5335 if (!host_ifconf) {
5336 return -TARGET_ENOMEM;
5337 }
5338 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5339 free_buf = 1;
5340 }
5341 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5342
5343 host_ifconf->ifc_len = host_ifc_len;
5344 host_ifconf->ifc_buf = host_ifc_buf;
5345
Peter Maydell49ca6f32016-06-06 19:58:14 +01005346 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005347 if (!is_error(ret)) {
5348 /* convert host ifc_len to target ifc_len */
5349
5350 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5351 target_ifc_len = nb_ifreq * target_ifreq_size;
5352 host_ifconf->ifc_len = target_ifc_len;
5353
5354 /* restore target ifc_buf */
5355
5356 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5357
5358 /* copy struct ifconf to target user */
5359
5360 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5361 if (!argptr)
5362 return -TARGET_EFAULT;
5363 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5364 unlock_user(argptr, arg, target_size);
5365
5366 /* copy ifreq[] to target user */
5367
5368 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5369 for (i = 0; i < nb_ifreq ; i++) {
5370 thunk_convert(argptr + i * target_ifreq_size,
5371 host_ifc_buf + i * sizeof(struct ifreq),
5372 ifreq_arg_type, THUNK_TARGET);
5373 }
5374 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5375 }
5376
5377 if (free_buf) {
5378 free(host_ifconf);
5379 }
5380
5381 return ret;
5382}
5383
Alexander Graf56e904e2012-01-31 18:42:06 +01005384static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005385 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005386{
5387 void *argptr;
5388 struct dm_ioctl *host_dm;
5389 abi_long guest_data;
5390 uint32_t guest_data_size;
5391 int target_size;
5392 const argtype *arg_type = ie->arg_type;
5393 abi_long ret;
5394 void *big_buf = NULL;
5395 char *host_data;
5396
5397 arg_type++;
5398 target_size = thunk_type_size(arg_type, 0);
5399 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5400 if (!argptr) {
5401 ret = -TARGET_EFAULT;
5402 goto out;
5403 }
5404 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5405 unlock_user(argptr, arg, 0);
5406
5407 /* buf_temp is too small, so fetch things into a bigger buffer */
5408 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5409 memcpy(big_buf, buf_temp, target_size);
5410 buf_temp = big_buf;
5411 host_dm = big_buf;
5412
5413 guest_data = arg + host_dm->data_start;
5414 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005415 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005416 goto out;
5417 }
5418 guest_data_size = host_dm->data_size - host_dm->data_start;
5419 host_data = (char*)host_dm + host_dm->data_start;
5420
5421 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005422 if (!argptr) {
5423 ret = -TARGET_EFAULT;
5424 goto out;
5425 }
5426
Alexander Graf56e904e2012-01-31 18:42:06 +01005427 switch (ie->host_cmd) {
5428 case DM_REMOVE_ALL:
5429 case DM_LIST_DEVICES:
5430 case DM_DEV_CREATE:
5431 case DM_DEV_REMOVE:
5432 case DM_DEV_SUSPEND:
5433 case DM_DEV_STATUS:
5434 case DM_DEV_WAIT:
5435 case DM_TABLE_STATUS:
5436 case DM_TABLE_CLEAR:
5437 case DM_TABLE_DEPS:
5438 case DM_LIST_VERSIONS:
5439 /* no input data */
5440 break;
5441 case DM_DEV_RENAME:
5442 case DM_DEV_SET_GEOMETRY:
5443 /* data contains only strings */
5444 memcpy(host_data, argptr, guest_data_size);
5445 break;
5446 case DM_TARGET_MSG:
5447 memcpy(host_data, argptr, guest_data_size);
5448 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5449 break;
5450 case DM_TABLE_LOAD:
5451 {
5452 void *gspec = argptr;
5453 void *cur_data = host_data;
5454 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5455 int spec_size = thunk_type_size(arg_type, 0);
5456 int i;
5457
5458 for (i = 0; i < host_dm->target_count; i++) {
5459 struct dm_target_spec *spec = cur_data;
5460 uint32_t next;
5461 int slen;
5462
5463 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5464 slen = strlen((char*)gspec + spec_size) + 1;
5465 next = spec->next;
5466 spec->next = sizeof(*spec) + slen;
5467 strcpy((char*)&spec[1], gspec + spec_size);
5468 gspec += next;
5469 cur_data += spec->next;
5470 }
5471 break;
5472 }
5473 default:
5474 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005475 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005476 goto out;
5477 }
5478 unlock_user(argptr, guest_data, 0);
5479
Peter Maydell49ca6f32016-06-06 19:58:14 +01005480 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005481 if (!is_error(ret)) {
5482 guest_data = arg + host_dm->data_start;
5483 guest_data_size = host_dm->data_size - host_dm->data_start;
5484 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5485 switch (ie->host_cmd) {
5486 case DM_REMOVE_ALL:
5487 case DM_DEV_CREATE:
5488 case DM_DEV_REMOVE:
5489 case DM_DEV_RENAME:
5490 case DM_DEV_SUSPEND:
5491 case DM_DEV_STATUS:
5492 case DM_TABLE_LOAD:
5493 case DM_TABLE_CLEAR:
5494 case DM_TARGET_MSG:
5495 case DM_DEV_SET_GEOMETRY:
5496 /* no return data */
5497 break;
5498 case DM_LIST_DEVICES:
5499 {
5500 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5501 uint32_t remaining_data = guest_data_size;
5502 void *cur_data = argptr;
5503 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5504 int nl_size = 12; /* can't use thunk_size due to alignment */
5505
5506 while (1) {
5507 uint32_t next = nl->next;
5508 if (next) {
5509 nl->next = nl_size + (strlen(nl->name) + 1);
5510 }
5511 if (remaining_data < nl->next) {
5512 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5513 break;
5514 }
5515 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5516 strcpy(cur_data + nl_size, nl->name);
5517 cur_data += nl->next;
5518 remaining_data -= nl->next;
5519 if (!next) {
5520 break;
5521 }
5522 nl = (void*)nl + next;
5523 }
5524 break;
5525 }
5526 case DM_DEV_WAIT:
5527 case DM_TABLE_STATUS:
5528 {
5529 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5530 void *cur_data = argptr;
5531 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5532 int spec_size = thunk_type_size(arg_type, 0);
5533 int i;
5534
5535 for (i = 0; i < host_dm->target_count; i++) {
5536 uint32_t next = spec->next;
5537 int slen = strlen((char*)&spec[1]) + 1;
5538 spec->next = (cur_data - argptr) + spec_size + slen;
5539 if (guest_data_size < spec->next) {
5540 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5541 break;
5542 }
5543 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5544 strcpy(cur_data + spec_size, (char*)&spec[1]);
5545 cur_data = argptr + spec->next;
5546 spec = (void*)host_dm + host_dm->data_start + next;
5547 }
5548 break;
5549 }
5550 case DM_TABLE_DEPS:
5551 {
5552 void *hdata = (void*)host_dm + host_dm->data_start;
5553 int count = *(uint32_t*)hdata;
5554 uint64_t *hdev = hdata + 8;
5555 uint64_t *gdev = argptr + 8;
5556 int i;
5557
5558 *(uint32_t*)argptr = tswap32(count);
5559 for (i = 0; i < count; i++) {
5560 *gdev = tswap64(*hdev);
5561 gdev++;
5562 hdev++;
5563 }
5564 break;
5565 }
5566 case DM_LIST_VERSIONS:
5567 {
5568 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5569 uint32_t remaining_data = guest_data_size;
5570 void *cur_data = argptr;
5571 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5572 int vers_size = thunk_type_size(arg_type, 0);
5573
5574 while (1) {
5575 uint32_t next = vers->next;
5576 if (next) {
5577 vers->next = vers_size + (strlen(vers->name) + 1);
5578 }
5579 if (remaining_data < vers->next) {
5580 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5581 break;
5582 }
5583 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5584 strcpy(cur_data + vers_size, vers->name);
5585 cur_data += vers->next;
5586 remaining_data -= vers->next;
5587 if (!next) {
5588 break;
5589 }
5590 vers = (void*)vers + next;
5591 }
5592 break;
5593 }
5594 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005595 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005596 ret = -TARGET_EINVAL;
5597 goto out;
5598 }
5599 unlock_user(argptr, guest_data, guest_data_size);
5600
5601 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5602 if (!argptr) {
5603 ret = -TARGET_EFAULT;
5604 goto out;
5605 }
5606 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5607 unlock_user(argptr, arg, target_size);
5608 }
5609out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005610 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005611 return ret;
5612}
5613
Alexander Grafa59b5e32014-08-22 13:15:50 +02005614static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005615 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005616{
5617 void *argptr;
5618 int target_size;
5619 const argtype *arg_type = ie->arg_type;
5620 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5621 abi_long ret;
5622
5623 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5624 struct blkpg_partition host_part;
5625
5626 /* Read and convert blkpg */
5627 arg_type++;
5628 target_size = thunk_type_size(arg_type, 0);
5629 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5630 if (!argptr) {
5631 ret = -TARGET_EFAULT;
5632 goto out;
5633 }
5634 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5635 unlock_user(argptr, arg, 0);
5636
5637 switch (host_blkpg->op) {
5638 case BLKPG_ADD_PARTITION:
5639 case BLKPG_DEL_PARTITION:
5640 /* payload is struct blkpg_partition */
5641 break;
5642 default:
5643 /* Unknown opcode */
5644 ret = -TARGET_EINVAL;
5645 goto out;
5646 }
5647
5648 /* Read and convert blkpg->data */
5649 arg = (abi_long)(uintptr_t)host_blkpg->data;
5650 target_size = thunk_type_size(part_arg_type, 0);
5651 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5652 if (!argptr) {
5653 ret = -TARGET_EFAULT;
5654 goto out;
5655 }
5656 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5657 unlock_user(argptr, arg, 0);
5658
5659 /* Swizzle the data pointer to our local copy and call! */
5660 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005661 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005662
5663out:
5664 return ret;
5665}
5666
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005667static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005668 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005669{
5670 const argtype *arg_type = ie->arg_type;
5671 const StructEntry *se;
5672 const argtype *field_types;
5673 const int *dst_offsets, *src_offsets;
5674 int target_size;
5675 void *argptr;
5676 abi_ulong *target_rt_dev_ptr;
5677 unsigned long *host_rt_dev_ptr;
5678 abi_long ret;
5679 int i;
5680
5681 assert(ie->access == IOC_W);
5682 assert(*arg_type == TYPE_PTR);
5683 arg_type++;
5684 assert(*arg_type == TYPE_STRUCT);
5685 target_size = thunk_type_size(arg_type, 0);
5686 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5687 if (!argptr) {
5688 return -TARGET_EFAULT;
5689 }
5690 arg_type++;
5691 assert(*arg_type == (int)STRUCT_rtentry);
5692 se = struct_entries + *arg_type++;
5693 assert(se->convert[0] == NULL);
5694 /* convert struct here to be able to catch rt_dev string */
5695 field_types = se->field_types;
5696 dst_offsets = se->field_offsets[THUNK_HOST];
5697 src_offsets = se->field_offsets[THUNK_TARGET];
5698 for (i = 0; i < se->nb_fields; i++) {
5699 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5700 assert(*field_types == TYPE_PTRVOID);
5701 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5702 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5703 if (*target_rt_dev_ptr != 0) {
5704 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5705 tswapal(*target_rt_dev_ptr));
5706 if (!*host_rt_dev_ptr) {
5707 unlock_user(argptr, arg, 0);
5708 return -TARGET_EFAULT;
5709 }
5710 } else {
5711 *host_rt_dev_ptr = 0;
5712 }
5713 field_types++;
5714 continue;
5715 }
5716 field_types = thunk_convert(buf_temp + dst_offsets[i],
5717 argptr + src_offsets[i],
5718 field_types, THUNK_HOST);
5719 }
5720 unlock_user(argptr, arg, 0);
5721
Peter Maydell49ca6f32016-06-06 19:58:14 +01005722 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005723 if (*host_rt_dev_ptr != 0) {
5724 unlock_user((void *)*host_rt_dev_ptr,
5725 *target_rt_dev_ptr, 0);
5726 }
5727 return ret;
5728}
5729
Paul Burtonca56f5b2014-06-22 11:25:47 +01005730static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005731 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005732{
5733 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005734 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005735}
5736
Andreas Schwab2b74f622018-01-29 11:47:06 +01005737#ifdef TIOCGPTPEER
5738static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5739 int fd, int cmd, abi_long arg)
5740{
5741 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5742 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5743}
5744#endif
5745
blueswir19f106a72008-10-05 10:52:52 +00005746static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005747#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005748 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5749#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5750 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005751#define IOCTL_IGNORE(cmd) \
5752 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005753#include "ioctls.h"
5754 { 0, 0, },
5755};
5756
pbrook53a59602006-03-25 19:31:22 +00005757/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005758/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005759static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005760{
5761 const IOCTLEntry *ie;
5762 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005763 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005764 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005765 int target_size;
5766 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005767
5768 ie = ioctl_entries;
5769 for(;;) {
5770 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005771 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005772 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005773 }
5774 if (ie->target_cmd == cmd)
5775 break;
5776 ie++;
5777 }
5778 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005779#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005780 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005781#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005782 if (ie->do_ioctl) {
5783 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005784 } else if (!ie->host_cmd) {
5785 /* Some architectures define BSD ioctls in their headers
5786 that are not implemented in Linux. */
5787 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005788 }
5789
bellard31e31b82003-02-18 22:55:36 +00005790 switch(arg_type[0]) {
5791 case TYPE_NULL:
5792 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005793 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005794 break;
5795 case TYPE_PTRVOID:
5796 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005797 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005798 break;
5799 case TYPE_PTR:
5800 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005801 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005802 switch(ie->access) {
5803 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005804 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005805 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005806 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5807 if (!argptr)
5808 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005809 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5810 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005811 }
5812 break;
5813 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005814 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5815 if (!argptr)
5816 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005817 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5818 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005819 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005820 break;
5821 default:
5822 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005823 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5824 if (!argptr)
5825 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005826 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5827 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005828 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005829 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005830 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5831 if (!argptr)
5832 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005833 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5834 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005835 }
5836 break;
5837 }
5838 break;
5839 default:
j_mayer32407102007-09-26 23:01:49 +00005840 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5841 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005842 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005843 break;
5844 }
5845 return ret;
5846}
5847
blueswir1b39bc502008-10-05 10:51:10 +00005848static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005849 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5850 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5851 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5852 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5853 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5854 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5855 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5856 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5857 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5858 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5859 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5860 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5861 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5862 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5863 { 0, 0, 0, 0 }
5864};
5865
blueswir1b39bc502008-10-05 10:51:10 +00005866static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005867 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5868 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5869 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5870 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5871 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5872 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5873 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5874 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5875 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5876 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5877 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5878 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5879 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5880 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5881 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5882 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5883 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5884 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5885 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5886 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5887 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5888 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5889 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5890 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5891 { 0, 0, 0, 0 }
5892};
5893
blueswir1b39bc502008-10-05 10:51:10 +00005894static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005895 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5896 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5897 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5898 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5899 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5900 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5901 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5902 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5903 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5904 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5905 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5906 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5907 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5908 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5909 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5910 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5911 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5912 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5913 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5914 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5915 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5916 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5917 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5918 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5919 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5920 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5921 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5922 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5923 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5924 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5925 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5926 { 0, 0, 0, 0 }
5927};
5928
blueswir1b39bc502008-10-05 10:51:10 +00005929static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005930 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5931 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5932 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5933 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5934 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5935 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5936 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5937 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5938 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5939 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5940 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5941 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5942 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5943 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5944 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5945 { 0, 0, 0, 0 }
5946};
5947
5948static void target_to_host_termios (void *dst, const void *src)
5949{
5950 struct host_termios *host = dst;
5951 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005952
ths5fafdf22007-09-16 21:08:06 +00005953 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005954 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005955 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005956 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005957 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005958 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005959 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005960 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5961 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005962
Arnaud Patard44607122009-04-21 17:39:08 +03005963 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005964 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5965 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005966 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005967 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005968 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005969 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005970 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005971 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005972 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005973 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5974 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005975 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5976 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5977 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5978 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5979 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005980 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005981}
ths3b46e622007-09-17 08:09:54 +00005982
bellard31e31b82003-02-18 22:55:36 +00005983static void host_to_target_termios (void *dst, const void *src)
5984{
5985 struct target_termios *target = dst;
5986 const struct host_termios *host = src;
5987
ths5fafdf22007-09-16 21:08:06 +00005988 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005989 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005990 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005991 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005992 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005993 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005994 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005995 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5996 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005997
Arnaud Patard44607122009-04-21 17:39:08 +03005998 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005999 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
6000 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
6001 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
6002 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
6003 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
6004 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
6005 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
6006 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
6007 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
6008 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
6009 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
6010 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
6011 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
6012 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
6013 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
6014 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
6015 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
6016}
6017
blueswir18e853dc2008-10-05 10:49:32 +00006018static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00006019 .convert = { host_to_target_termios, target_to_host_termios },
6020 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
6021 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
6022};
6023
bellard5286db72003-06-05 00:57:30 +00006024static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01006025 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
6026 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
6027 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
6028 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
6029 MAP_ANONYMOUS, MAP_ANONYMOUS },
6030 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
6031 MAP_GROWSDOWN, MAP_GROWSDOWN },
6032 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
6033 MAP_DENYWRITE, MAP_DENYWRITE },
6034 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
6035 MAP_EXECUTABLE, MAP_EXECUTABLE },
6036 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
6037 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
6038 MAP_NORESERVE, MAP_NORESERVE },
6039 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
6040 /* MAP_STACK had been ignored by the kernel for quite some time.
6041 Recognize it for the target insofar as we do not want to pass
6042 it through to the host. */
6043 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
6044 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00006045};
6046
bellard2ab83ea2003-06-15 19:56:46 +00006047#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00006048
6049/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00006050static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00006051
bellard03acab62007-11-11 14:57:14 +00006052static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006053{
6054 int size;
pbrook53a59602006-03-25 19:31:22 +00006055 void *p;
bellard6dbad632003-03-16 18:05:05 +00006056
6057 if (!ldt_table)
6058 return 0;
6059 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
6060 if (size > bytecount)
6061 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00006062 p = lock_user(VERIFY_WRITE, ptr, size, 0);
6063 if (!p)
bellard03acab62007-11-11 14:57:14 +00006064 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00006065 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00006066 memcpy(p, ldt_table, size);
6067 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00006068 return size;
6069}
6070
6071/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00006072static abi_long write_ldt(CPUX86State *env,
6073 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00006074{
6075 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00006076 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00006077 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00006078 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00006079 uint32_t *lp, entry_1, entry_2;
6080
6081 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00006082 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00006083 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00006084 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00006085 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006086 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00006087 ldt_info.limit = tswap32(target_ldt_info->limit);
6088 ldt_info.flags = tswap32(target_ldt_info->flags);
6089 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00006090
bellard6dbad632003-03-16 18:05:05 +00006091 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00006092 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006093 seg_32bit = ldt_info.flags & 1;
6094 contents = (ldt_info.flags >> 1) & 3;
6095 read_exec_only = (ldt_info.flags >> 3) & 1;
6096 limit_in_pages = (ldt_info.flags >> 4) & 1;
6097 seg_not_present = (ldt_info.flags >> 5) & 1;
6098 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00006099#ifdef TARGET_ABI32
6100 lm = 0;
6101#else
6102 lm = (ldt_info.flags >> 7) & 1;
6103#endif
bellard6dbad632003-03-16 18:05:05 +00006104 if (contents == 3) {
6105 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00006106 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006107 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00006108 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006109 }
6110 /* allocate the LDT */
6111 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006112 env->ldt.base = target_mmap(0,
6113 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6114 PROT_READ|PROT_WRITE,
6115 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6116 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006117 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00006118 memset(g2h(env->ldt.base), 0,
6119 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006120 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006121 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006122 }
6123
6124 /* NOTE: same code as Linux kernel */
6125 /* Allow LDTs to be cleared by the user. */
6126 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6127 if (oldmode ||
6128 (contents == 0 &&
6129 read_exec_only == 1 &&
6130 seg_32bit == 0 &&
6131 limit_in_pages == 0 &&
6132 seg_not_present == 1 &&
6133 useable == 0 )) {
6134 entry_1 = 0;
6135 entry_2 = 0;
6136 goto install;
6137 }
6138 }
ths3b46e622007-09-17 08:09:54 +00006139
bellard6dbad632003-03-16 18:05:05 +00006140 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6141 (ldt_info.limit & 0x0ffff);
6142 entry_2 = (ldt_info.base_addr & 0xff000000) |
6143 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6144 (ldt_info.limit & 0xf0000) |
6145 ((read_exec_only ^ 1) << 9) |
6146 (contents << 10) |
6147 ((seg_not_present ^ 1) << 15) |
6148 (seg_32bit << 22) |
6149 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006150 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006151 0x7000;
6152 if (!oldmode)
6153 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006154
bellard6dbad632003-03-16 18:05:05 +00006155 /* Install the new entry ... */
6156install:
6157 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6158 lp[0] = tswap32(entry_1);
6159 lp[1] = tswap32(entry_2);
6160 return 0;
6161}
6162
6163/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006164static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6165 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006166{
bellard03acab62007-11-11 14:57:14 +00006167 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006168
bellard6dbad632003-03-16 18:05:05 +00006169 switch (func) {
6170 case 0:
6171 ret = read_ldt(ptr, bytecount);
6172 break;
6173 case 1:
6174 ret = write_ldt(env, ptr, bytecount, 1);
6175 break;
6176 case 0x11:
6177 ret = write_ldt(env, ptr, bytecount, 0);
6178 break;
bellard03acab62007-11-11 14:57:14 +00006179 default:
6180 ret = -TARGET_ENOSYS;
6181 break;
bellard6dbad632003-03-16 18:05:05 +00006182 }
6183 return ret;
6184}
bellard1b6b0292003-03-22 17:31:38 +00006185
blueswir14583f582008-08-24 10:35:55 +00006186#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006187abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006188{
6189 uint64_t *gdt_table = g2h(env->gdt.base);
6190 struct target_modify_ldt_ldt_s ldt_info;
6191 struct target_modify_ldt_ldt_s *target_ldt_info;
6192 int seg_32bit, contents, read_exec_only, limit_in_pages;
6193 int seg_not_present, useable, lm;
6194 uint32_t *lp, entry_1, entry_2;
6195 int i;
6196
6197 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6198 if (!target_ldt_info)
6199 return -TARGET_EFAULT;
6200 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006201 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006202 ldt_info.limit = tswap32(target_ldt_info->limit);
6203 ldt_info.flags = tswap32(target_ldt_info->flags);
6204 if (ldt_info.entry_number == -1) {
6205 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6206 if (gdt_table[i] == 0) {
6207 ldt_info.entry_number = i;
6208 target_ldt_info->entry_number = tswap32(i);
6209 break;
6210 }
6211 }
6212 }
6213 unlock_user_struct(target_ldt_info, ptr, 1);
6214
6215 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6216 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6217 return -TARGET_EINVAL;
6218 seg_32bit = ldt_info.flags & 1;
6219 contents = (ldt_info.flags >> 1) & 3;
6220 read_exec_only = (ldt_info.flags >> 3) & 1;
6221 limit_in_pages = (ldt_info.flags >> 4) & 1;
6222 seg_not_present = (ldt_info.flags >> 5) & 1;
6223 useable = (ldt_info.flags >> 6) & 1;
6224#ifdef TARGET_ABI32
6225 lm = 0;
6226#else
6227 lm = (ldt_info.flags >> 7) & 1;
6228#endif
6229
6230 if (contents == 3) {
6231 if (seg_not_present == 0)
6232 return -TARGET_EINVAL;
6233 }
6234
6235 /* NOTE: same code as Linux kernel */
6236 /* Allow LDTs to be cleared by the user. */
6237 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6238 if ((contents == 0 &&
6239 read_exec_only == 1 &&
6240 seg_32bit == 0 &&
6241 limit_in_pages == 0 &&
6242 seg_not_present == 1 &&
6243 useable == 0 )) {
6244 entry_1 = 0;
6245 entry_2 = 0;
6246 goto install;
6247 }
6248 }
6249
6250 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6251 (ldt_info.limit & 0x0ffff);
6252 entry_2 = (ldt_info.base_addr & 0xff000000) |
6253 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6254 (ldt_info.limit & 0xf0000) |
6255 ((read_exec_only ^ 1) << 9) |
6256 (contents << 10) |
6257 ((seg_not_present ^ 1) << 15) |
6258 (seg_32bit << 22) |
6259 (limit_in_pages << 23) |
6260 (useable << 20) |
6261 (lm << 21) |
6262 0x7000;
6263
6264 /* Install the new entry ... */
6265install:
6266 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6267 lp[0] = tswap32(entry_1);
6268 lp[1] = tswap32(entry_2);
6269 return 0;
6270}
6271
blueswir18fcd3692008-08-17 20:26:25 +00006272static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006273{
6274 struct target_modify_ldt_ldt_s *target_ldt_info;
6275 uint64_t *gdt_table = g2h(env->gdt.base);
6276 uint32_t base_addr, limit, flags;
6277 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6278 int seg_not_present, useable, lm;
6279 uint32_t *lp, entry_1, entry_2;
6280
6281 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6282 if (!target_ldt_info)
6283 return -TARGET_EFAULT;
6284 idx = tswap32(target_ldt_info->entry_number);
6285 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6286 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6287 unlock_user_struct(target_ldt_info, ptr, 1);
6288 return -TARGET_EINVAL;
6289 }
6290 lp = (uint32_t *)(gdt_table + idx);
6291 entry_1 = tswap32(lp[0]);
6292 entry_2 = tswap32(lp[1]);
6293
6294 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6295 contents = (entry_2 >> 10) & 3;
6296 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6297 seg_32bit = (entry_2 >> 22) & 1;
6298 limit_in_pages = (entry_2 >> 23) & 1;
6299 useable = (entry_2 >> 20) & 1;
6300#ifdef TARGET_ABI32
6301 lm = 0;
6302#else
6303 lm = (entry_2 >> 21) & 1;
6304#endif
6305 flags = (seg_32bit << 0) | (contents << 1) |
6306 (read_exec_only << 3) | (limit_in_pages << 4) |
6307 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6308 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6309 base_addr = (entry_1 >> 16) |
6310 (entry_2 & 0xff000000) |
6311 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006312 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006313 target_ldt_info->limit = tswap32(limit);
6314 target_ldt_info->flags = tswap32(flags);
6315 unlock_user_struct(target_ldt_info, ptr, 1);
6316 return 0;
6317}
blueswir14583f582008-08-24 10:35:55 +00006318#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006319
bellardd2fd1af2007-11-14 18:08:56 +00006320#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006321abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006322{
Juan Quintela1add8692011-06-16 17:37:09 +01006323 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006324 abi_ulong val;
6325 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006326
bellardd2fd1af2007-11-14 18:08:56 +00006327 switch(code) {
6328 case TARGET_ARCH_SET_GS:
6329 case TARGET_ARCH_SET_FS:
6330 if (code == TARGET_ARCH_SET_GS)
6331 idx = R_GS;
6332 else
6333 idx = R_FS;
6334 cpu_x86_load_seg(env, idx, 0);
6335 env->segs[idx].base = addr;
6336 break;
6337 case TARGET_ARCH_GET_GS:
6338 case TARGET_ARCH_GET_FS:
6339 if (code == TARGET_ARCH_GET_GS)
6340 idx = R_GS;
6341 else
6342 idx = R_FS;
6343 val = env->segs[idx].base;
6344 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006345 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006346 break;
6347 default:
6348 ret = -TARGET_EINVAL;
6349 break;
6350 }
Juan Quintela1add8692011-06-16 17:37:09 +01006351 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006352}
6353#endif
6354
bellard2ab83ea2003-06-15 19:56:46 +00006355#endif /* defined(TARGET_I386) */
6356
Riku Voipio05098a92011-03-04 15:27:29 +02006357#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006358
pbrookd865bab2008-06-07 22:12:17 +00006359
6360static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6361typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006362 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006363 pthread_mutex_t mutex;
6364 pthread_cond_t cond;
6365 pthread_t thread;
6366 uint32_t tid;
6367 abi_ulong child_tidptr;
6368 abi_ulong parent_tidptr;
6369 sigset_t sigmask;
6370} new_thread_info;
6371
6372static void *clone_func(void *arg)
6373{
6374 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006375 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006376 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006377 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006378
Emilio G. Cota70903762015-08-23 20:23:41 -04006379 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006380 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006381 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006382 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006383 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006384 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006385 info->tid = gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006386 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006387 if (info->child_tidptr)
6388 put_user_u32(info->tid, info->child_tidptr);
6389 if (info->parent_tidptr)
6390 put_user_u32(info->tid, info->parent_tidptr);
6391 /* Enable signals. */
6392 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6393 /* Signal to the parent that we're ready. */
6394 pthread_mutex_lock(&info->mutex);
6395 pthread_cond_broadcast(&info->cond);
6396 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006397 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006398 pthread_mutex_lock(&clone_lock);
6399 pthread_mutex_unlock(&clone_lock);
6400 cpu_loop(env);
6401 /* never exits */
6402 return NULL;
6403}
bellard1b6b0292003-03-22 17:31:38 +00006404
ths0da46a62007-10-20 20:23:07 +00006405/* do_fork() Must return host values and target errnos (unlike most
6406 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006407static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006408 abi_ulong parent_tidptr, target_ulong newtls,
6409 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006410{
Andreas Färber0429a972013-08-26 18:14:44 +02006411 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006412 int ret;
bellard5cd43932003-03-29 16:54:36 +00006413 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006414 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006415 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006416 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006417
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006418 flags &= ~CLONE_IGNORED_FLAGS;
6419
balrog436d1242008-09-21 02:39:45 +00006420 /* Emulate vfork() with fork() */
6421 if (flags & CLONE_VFORK)
6422 flags &= ~(CLONE_VFORK | CLONE_VM);
6423
bellard1b6b0292003-03-22 17:31:38 +00006424 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006425 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006426 new_thread_info info;
6427 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006428
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006429 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6430 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6431 return -TARGET_EINVAL;
6432 }
6433
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006434 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006435 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006436
6437 /* Grab a mutex so that thread setup appears atomic. */
6438 pthread_mutex_lock(&clone_lock);
6439
bellard1b6b0292003-03-22 17:31:38 +00006440 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006441 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006442 /* Init regs that differ from the parent. */
6443 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006444 new_cpu = ENV_GET_CPU(new_env);
6445 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006446 ts->bprm = parent_ts->bprm;
6447 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006448 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006449
Peter Maydell7cfbd382016-08-02 18:41:26 +01006450 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006451 ts->child_tidptr = child_tidptr;
6452 }
6453
Peter Maydell7cfbd382016-08-02 18:41:26 +01006454 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006455 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006456 }
pbrookd865bab2008-06-07 22:12:17 +00006457
pbrookd865bab2008-06-07 22:12:17 +00006458 memset(&info, 0, sizeof(info));
6459 pthread_mutex_init(&info.mutex, NULL);
6460 pthread_mutex_lock(&info.mutex);
6461 pthread_cond_init(&info.cond, NULL);
6462 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006463 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006464 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006465 }
6466 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006467 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006468 }
pbrookd865bab2008-06-07 22:12:17 +00006469
6470 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006471 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6472 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006473 /* It is not safe to deliver signals until the child has finished
6474 initializing, so temporarily block all signals. */
6475 sigfillset(&sigmask);
6476 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6477
Alex Bennéeb67cb682016-10-05 11:13:04 -07006478 /* If this is our first additional thread, we need to ensure we
6479 * generate code for parallel execution and flush old translations.
6480 */
6481 if (!parallel_cpus) {
6482 parallel_cpus = true;
6483 tb_flush(cpu);
6484 }
6485
pbrookd865bab2008-06-07 22:12:17 +00006486 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006487 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006488
6489 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6490 pthread_attr_destroy(&attr);
6491 if (ret == 0) {
6492 /* Wait for the child to initialize. */
6493 pthread_cond_wait(&info.cond, &info.mutex);
6494 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006495 } else {
6496 ret = -1;
6497 }
6498 pthread_mutex_unlock(&info.mutex);
6499 pthread_cond_destroy(&info.cond);
6500 pthread_mutex_destroy(&info.mutex);
6501 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006502 } else {
6503 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006504 if (flags & CLONE_INVALID_FORK_FLAGS) {
6505 return -TARGET_EINVAL;
6506 }
6507
6508 /* We can't support custom termination signals */
6509 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006510 return -TARGET_EINVAL;
6511 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006512
6513 if (block_signals()) {
6514 return -TARGET_ERESTARTSYS;
6515 }
6516
pbrookd865bab2008-06-07 22:12:17 +00006517 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006518 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006519 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006520 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00006521 cpu_clone_regs(env, newsp);
6522 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006523 /* There is a race condition here. The parent process could
6524 theoretically read the TID in the child process before the child
6525 tid is set. This would require using either ptrace
6526 (not implemented) or having *_tidptr to point at a shared memory
6527 mapping. We can't repeat the spinlock hack used above because
6528 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006529 if (flags & CLONE_CHILD_SETTID)
6530 put_user_u32(gettid(), child_tidptr);
6531 if (flags & CLONE_PARENT_SETTID)
6532 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006533 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006534 if (flags & CLONE_SETTLS)
6535 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006536 if (flags & CLONE_CHILD_CLEARTID)
6537 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006538 } else {
6539 fork_end(0);
6540 }
bellard1b6b0292003-03-22 17:31:38 +00006541 }
6542 return ret;
6543}
6544
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006545/* warning : doesn't handle linux specific flags... */
6546static int target_to_host_fcntl_cmd(int cmd)
6547{
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006548 int ret;
6549
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006550 switch(cmd) {
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006551 case TARGET_F_DUPFD:
6552 case TARGET_F_GETFD:
6553 case TARGET_F_SETFD:
6554 case TARGET_F_GETFL:
6555 case TARGET_F_SETFL:
6556 ret = cmd;
6557 break;
6558 case TARGET_F_GETLK:
6559 ret = F_GETLK64;
6560 break;
6561 case TARGET_F_SETLK:
6562 ret = F_SETLK64;
6563 break;
6564 case TARGET_F_SETLKW:
6565 ret = F_SETLKW64;
6566 break;
6567 case TARGET_F_GETOWN:
6568 ret = F_GETOWN;
6569 break;
6570 case TARGET_F_SETOWN:
6571 ret = F_SETOWN;
6572 break;
6573 case TARGET_F_GETSIG:
6574 ret = F_GETSIG;
6575 break;
6576 case TARGET_F_SETSIG:
6577 ret = F_SETSIG;
6578 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006579#if TARGET_ABI_BITS == 32
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006580 case TARGET_F_GETLK64:
6581 ret = F_GETLK64;
6582 break;
6583 case TARGET_F_SETLK64:
6584 ret = F_SETLK64;
6585 break;
6586 case TARGET_F_SETLKW64:
6587 ret = F_SETLKW64;
6588 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006589#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006590 case TARGET_F_SETLEASE:
6591 ret = F_SETLEASE;
6592 break;
6593 case TARGET_F_GETLEASE:
6594 ret = F_GETLEASE;
6595 break;
malcfbd5de92009-09-06 06:31:59 +04006596#ifdef F_DUPFD_CLOEXEC
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006597 case TARGET_F_DUPFD_CLOEXEC:
6598 ret = F_DUPFD_CLOEXEC;
6599 break;
malcfbd5de92009-09-06 06:31:59 +04006600#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006601 case TARGET_F_NOTIFY:
6602 ret = F_NOTIFY;
6603 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006604#ifdef F_GETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006605 case TARGET_F_GETOWN_EX:
6606 ret = F_GETOWN_EX;
6607 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006608#endif
6609#ifdef F_SETOWN_EX
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006610 case TARGET_F_SETOWN_EX:
6611 ret = F_SETOWN_EX;
6612 break;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006613#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006614#ifdef F_SETPIPE_SZ
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006615 case TARGET_F_SETPIPE_SZ:
6616 ret = F_SETPIPE_SZ;
6617 break;
6618 case TARGET_F_GETPIPE_SZ:
6619 ret = F_GETPIPE_SZ;
6620 break;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006621#endif
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006622 default:
6623 ret = -TARGET_EINVAL;
6624 break;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006625 }
Shivaprasad G Bhat4a545762018-07-13 07:34:46 -05006626
6627#if defined(__powerpc64__)
6628 /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
6629 * is not supported by kernel. The glibc fcntl call actually adjusts
6630 * them to 5, 6 and 7 before making the syscall(). Since we make the
6631 * syscall directly, adjust to what is supported by the kernel.
6632 */
6633 if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
6634 ret -= F_GETLK64 - 5;
6635 }
6636#endif
6637
6638 return ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006639}
6640
Laurent Vivierae68ad92018-05-10 01:11:21 +02006641#define FLOCK_TRANSTBL \
6642 switch (type) { \
6643 TRANSTBL_CONVERT(F_RDLCK); \
6644 TRANSTBL_CONVERT(F_WRLCK); \
6645 TRANSTBL_CONVERT(F_UNLCK); \
6646 TRANSTBL_CONVERT(F_EXLCK); \
6647 TRANSTBL_CONVERT(F_SHLCK); \
6648 }
6649
6650static int target_to_host_flock(int type)
6651{
6652#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
6653 FLOCK_TRANSTBL
6654#undef TRANSTBL_CONVERT
6655 return -TARGET_EINVAL;
6656}
6657
6658static int host_to_target_flock(int type)
6659{
6660#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
6661 FLOCK_TRANSTBL
6662#undef TRANSTBL_CONVERT
6663 /* if we don't know how to convert the value coming
6664 * from the host we copy to the target field as-is
6665 */
6666 return type;
6667}
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006668
Peter Maydell213d3e92016-06-13 11:22:05 +01006669static inline abi_long copy_from_user_flock(struct flock64 *fl,
6670 abi_ulong target_flock_addr)
6671{
6672 struct target_flock *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006673 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006674
6675 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6676 return -TARGET_EFAULT;
6677 }
6678
6679 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006680 l_type = target_to_host_flock(l_type);
6681 if (l_type < 0) {
6682 return l_type;
6683 }
6684 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006685 __get_user(fl->l_whence, &target_fl->l_whence);
6686 __get_user(fl->l_start, &target_fl->l_start);
6687 __get_user(fl->l_len, &target_fl->l_len);
6688 __get_user(fl->l_pid, &target_fl->l_pid);
6689 unlock_user_struct(target_fl, target_flock_addr, 0);
6690 return 0;
6691}
6692
6693static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6694 const struct flock64 *fl)
6695{
6696 struct target_flock *target_fl;
6697 short l_type;
6698
6699 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6700 return -TARGET_EFAULT;
6701 }
6702
Laurent Vivierae68ad92018-05-10 01:11:21 +02006703 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006704 __put_user(l_type, &target_fl->l_type);
6705 __put_user(fl->l_whence, &target_fl->l_whence);
6706 __put_user(fl->l_start, &target_fl->l_start);
6707 __put_user(fl->l_len, &target_fl->l_len);
6708 __put_user(fl->l_pid, &target_fl->l_pid);
6709 unlock_user_struct(target_fl, target_flock_addr, 1);
6710 return 0;
6711}
6712
6713typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6714typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6715
6716#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
Laurent Vivier7f254c52018-05-02 23:57:30 +02006717static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
Peter Maydell213d3e92016-06-13 11:22:05 +01006718 abi_ulong target_flock_addr)
6719{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006720 struct target_oabi_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006721 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006722
6723 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6724 return -TARGET_EFAULT;
6725 }
6726
6727 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006728 l_type = target_to_host_flock(l_type);
6729 if (l_type < 0) {
6730 return l_type;
6731 }
6732 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006733 __get_user(fl->l_whence, &target_fl->l_whence);
6734 __get_user(fl->l_start, &target_fl->l_start);
6735 __get_user(fl->l_len, &target_fl->l_len);
6736 __get_user(fl->l_pid, &target_fl->l_pid);
6737 unlock_user_struct(target_fl, target_flock_addr, 0);
6738 return 0;
6739}
6740
Laurent Vivier7f254c52018-05-02 23:57:30 +02006741static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
Peter Maydell213d3e92016-06-13 11:22:05 +01006742 const struct flock64 *fl)
6743{
Laurent Vivier7f254c52018-05-02 23:57:30 +02006744 struct target_oabi_flock64 *target_fl;
Peter Maydell213d3e92016-06-13 11:22:05 +01006745 short l_type;
6746
6747 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6748 return -TARGET_EFAULT;
6749 }
6750
Laurent Vivierae68ad92018-05-10 01:11:21 +02006751 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006752 __put_user(l_type, &target_fl->l_type);
6753 __put_user(fl->l_whence, &target_fl->l_whence);
6754 __put_user(fl->l_start, &target_fl->l_start);
6755 __put_user(fl->l_len, &target_fl->l_len);
6756 __put_user(fl->l_pid, &target_fl->l_pid);
6757 unlock_user_struct(target_fl, target_flock_addr, 1);
6758 return 0;
6759}
6760#endif
6761
6762static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6763 abi_ulong target_flock_addr)
6764{
6765 struct target_flock64 *target_fl;
Laurent Vivierae68ad92018-05-10 01:11:21 +02006766 int l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006767
6768 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6769 return -TARGET_EFAULT;
6770 }
6771
6772 __get_user(l_type, &target_fl->l_type);
Laurent Vivierae68ad92018-05-10 01:11:21 +02006773 l_type = target_to_host_flock(l_type);
6774 if (l_type < 0) {
6775 return l_type;
6776 }
6777 fl->l_type = l_type;
Peter Maydell213d3e92016-06-13 11:22:05 +01006778 __get_user(fl->l_whence, &target_fl->l_whence);
6779 __get_user(fl->l_start, &target_fl->l_start);
6780 __get_user(fl->l_len, &target_fl->l_len);
6781 __get_user(fl->l_pid, &target_fl->l_pid);
6782 unlock_user_struct(target_fl, target_flock_addr, 0);
6783 return 0;
6784}
6785
6786static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6787 const struct flock64 *fl)
6788{
6789 struct target_flock64 *target_fl;
6790 short l_type;
6791
6792 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6793 return -TARGET_EFAULT;
6794 }
6795
Laurent Vivierae68ad92018-05-10 01:11:21 +02006796 l_type = host_to_target_flock(fl->l_type);
Peter Maydell213d3e92016-06-13 11:22:05 +01006797 __put_user(l_type, &target_fl->l_type);
6798 __put_user(fl->l_whence, &target_fl->l_whence);
6799 __put_user(fl->l_start, &target_fl->l_start);
6800 __put_user(fl->l_len, &target_fl->l_len);
6801 __put_user(fl->l_pid, &target_fl->l_pid);
6802 unlock_user_struct(target_fl, target_flock_addr, 1);
6803 return 0;
6804}
6805
blueswir1992f48a2007-10-14 16:27:31 +00006806static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006807{
ths43f238d2007-01-05 20:55:49 +00006808 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006809#ifdef F_GETOWN_EX
6810 struct f_owner_ex fox;
6811 struct target_f_owner_ex *target_fox;
6812#endif
blueswir1992f48a2007-10-14 16:27:31 +00006813 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006814 int host_cmd = target_to_host_fcntl_cmd(cmd);
6815
6816 if (host_cmd == -TARGET_EINVAL)
6817 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006818
bellard7775e9e2003-05-14 22:46:48 +00006819 switch(cmd) {
6820 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006821 ret = copy_from_user_flock(&fl64, arg);
6822 if (ret) {
6823 return ret;
6824 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006825 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006826 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006827 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006828 }
6829 break;
ths3b46e622007-09-17 08:09:54 +00006830
bellard7775e9e2003-05-14 22:46:48 +00006831 case TARGET_F_SETLK:
6832 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006833 ret = copy_from_user_flock(&fl64, arg);
6834 if (ret) {
6835 return ret;
6836 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006837 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006838 break;
ths3b46e622007-09-17 08:09:54 +00006839
bellard7775e9e2003-05-14 22:46:48 +00006840 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006841 ret = copy_from_user_flock64(&fl64, arg);
6842 if (ret) {
6843 return ret;
6844 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006845 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006846 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006847 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006848 }
bellard9ee1fa22007-11-11 15:11:19 +00006849 break;
bellard7775e9e2003-05-14 22:46:48 +00006850 case TARGET_F_SETLK64:
6851 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006852 ret = copy_from_user_flock64(&fl64, arg);
6853 if (ret) {
6854 return ret;
6855 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006856 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006857 break;
6858
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006859 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006860 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006861 if (ret >= 0) {
6862 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6863 }
bellardffa65c32004-01-04 23:57:22 +00006864 break;
6865
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006866 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006867 ret = get_errno(safe_fcntl(fd, host_cmd,
6868 target_to_host_bitmask(arg,
6869 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006870 break;
6871
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006872#ifdef F_GETOWN_EX
6873 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006874 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006875 if (ret >= 0) {
6876 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6877 return -TARGET_EFAULT;
6878 target_fox->type = tswap32(fox.type);
6879 target_fox->pid = tswap32(fox.pid);
6880 unlock_user_struct(target_fox, arg, 1);
6881 }
6882 break;
6883#endif
6884
6885#ifdef F_SETOWN_EX
6886 case TARGET_F_SETOWN_EX:
6887 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6888 return -TARGET_EFAULT;
6889 fox.type = tswap32(target_fox->type);
6890 fox.pid = tswap32(target_fox->pid);
6891 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006892 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006893 break;
6894#endif
6895
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006896 case TARGET_F_SETOWN:
6897 case TARGET_F_GETOWN:
6898 case TARGET_F_SETSIG:
6899 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006900 case TARGET_F_SETLEASE:
6901 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006902 case TARGET_F_SETPIPE_SZ:
6903 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006904 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006905 break;
6906
bellard7775e9e2003-05-14 22:46:48 +00006907 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006908 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006909 break;
6910 }
6911 return ret;
6912}
6913
bellard67867302003-11-23 17:05:30 +00006914#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006915
bellard67867302003-11-23 17:05:30 +00006916static inline int high2lowuid(int uid)
6917{
6918 if (uid > 65535)
6919 return 65534;
6920 else
6921 return uid;
6922}
6923
6924static inline int high2lowgid(int gid)
6925{
6926 if (gid > 65535)
6927 return 65534;
6928 else
6929 return gid;
6930}
6931
6932static inline int low2highuid(int uid)
6933{
6934 if ((int16_t)uid == -1)
6935 return -1;
6936 else
6937 return uid;
6938}
6939
6940static inline int low2highgid(int gid)
6941{
6942 if ((int16_t)gid == -1)
6943 return -1;
6944 else
6945 return gid;
6946}
Riku Voipio0c866a72011-04-18 15:23:06 +03006947static inline int tswapid(int id)
6948{
6949 return tswap16(id);
6950}
Peter Maydell76ca3102014-03-02 19:36:41 +00006951
6952#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6953
Riku Voipio0c866a72011-04-18 15:23:06 +03006954#else /* !USE_UID16 */
6955static inline int high2lowuid(int uid)
6956{
6957 return uid;
6958}
6959static inline int high2lowgid(int gid)
6960{
6961 return gid;
6962}
6963static inline int low2highuid(int uid)
6964{
6965 return uid;
6966}
6967static inline int low2highgid(int gid)
6968{
6969 return gid;
6970}
6971static inline int tswapid(int id)
6972{
6973 return tswap32(id);
6974}
Peter Maydell76ca3102014-03-02 19:36:41 +00006975
6976#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6977
bellard67867302003-11-23 17:05:30 +00006978#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006979
Peter Maydellfd6f7792016-03-01 16:33:02 +00006980/* We must do direct syscalls for setting UID/GID, because we want to
6981 * implement the Linux system call semantics of "change only for this thread",
6982 * not the libc/POSIX semantics of "change for all threads in process".
6983 * (See http://ewontfix.com/17/ for more details.)
6984 * We use the 32-bit version of the syscalls if present; if it is not
6985 * then either the host architecture supports 32-bit UIDs natively with
6986 * the standard syscall, or the 16-bit UID is the best we can do.
6987 */
6988#ifdef __NR_setuid32
6989#define __NR_sys_setuid __NR_setuid32
6990#else
6991#define __NR_sys_setuid __NR_setuid
6992#endif
6993#ifdef __NR_setgid32
6994#define __NR_sys_setgid __NR_setgid32
6995#else
6996#define __NR_sys_setgid __NR_setgid
6997#endif
6998#ifdef __NR_setresuid32
6999#define __NR_sys_setresuid __NR_setresuid32
7000#else
7001#define __NR_sys_setresuid __NR_setresuid
7002#endif
7003#ifdef __NR_setresgid32
7004#define __NR_sys_setresgid __NR_setresgid32
7005#else
7006#define __NR_sys_setresgid __NR_setresgid
7007#endif
7008
7009_syscall1(int, sys_setuid, uid_t, uid)
7010_syscall1(int, sys_setgid, gid_t, gid)
7011_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
7012_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
7013
bellard31e31b82003-02-18 22:55:36 +00007014void syscall_init(void)
7015{
bellard2ab83ea2003-06-15 19:56:46 +00007016 IOCTLEntry *ie;
7017 const argtype *arg_type;
7018 int size;
thsb92c47c2007-11-01 00:07:38 +00007019 int i;
bellard2ab83ea2003-06-15 19:56:46 +00007020
Alexander Graf8be656b2015-05-06 23:47:32 +02007021 thunk_init(STRUCT_MAX);
7022
Blue Swirl001faf32009-05-13 17:53:17 +00007023#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00007024#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00007025#include "syscall_types.h"
7026#undef STRUCT
7027#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00007028
Peter Maydelldd6e9572012-07-23 08:07:22 +00007029 /* Build target_to_host_errno_table[] table from
7030 * host_to_target_errno_table[]. */
7031 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
7032 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
7033 }
7034
bellard2ab83ea2003-06-15 19:56:46 +00007035 /* we patch the ioctl size if necessary. We rely on the fact that
7036 no ioctl has all the bits at '1' in the size field */
7037 ie = ioctl_entries;
7038 while (ie->target_cmd != 0) {
7039 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
7040 TARGET_IOC_SIZEMASK) {
7041 arg_type = ie->arg_type;
7042 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00007043 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00007044 ie->target_cmd);
7045 exit(1);
7046 }
7047 arg_type++;
7048 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00007049 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00007050 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
7051 (size << TARGET_IOC_SIZESHIFT);
7052 }
thsb92c47c2007-11-01 00:07:38 +00007053
bellard2ab83ea2003-06-15 19:56:46 +00007054 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00007055#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7056 (defined(__x86_64__) && defined(TARGET_X86_64))
7057 if (unlikely(ie->target_cmd != ie->host_cmd)) {
7058 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
7059 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00007060 }
7061#endif
7062 ie++;
7063 }
bellard31e31b82003-02-18 22:55:36 +00007064}
bellardc573ff62004-01-04 15:51:36 +00007065
blueswir1992f48a2007-10-14 16:27:31 +00007066#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00007067static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
7068{
thsaf325d32008-06-10 15:29:15 +00007069#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00007070 return ((uint64_t)word0 << 32) | word1;
7071#else
7072 return ((uint64_t)word1 << 32) | word0;
7073#endif
7074}
blueswir1992f48a2007-10-14 16:27:31 +00007075#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00007076static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
7077{
7078 return word0;
7079}
blueswir1992f48a2007-10-14 16:27:31 +00007080#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00007081
7082#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00007083static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
7084 abi_long arg2,
7085 abi_long arg3,
7086 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007087{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007088 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007089 arg2 = arg3;
7090 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007091 }
pbrookce4defa2006-02-09 16:49:55 +00007092 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
7093}
7094#endif
7095
7096#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00007097static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
7098 abi_long arg2,
7099 abi_long arg3,
7100 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00007101{
James Clarke8bf8e9d2017-09-15 20:33:13 +01007102 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00007103 arg2 = arg3;
7104 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03007105 }
pbrookce4defa2006-02-09 16:49:55 +00007106 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
7107}
7108#endif
7109
bellard579a97f2007-11-11 14:26:47 +00007110static inline abi_long target_to_host_timespec(struct timespec *host_ts,
7111 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00007112{
7113 struct target_timespec *target_ts;
7114
bellard579a97f2007-11-11 14:26:47 +00007115 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
7116 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01007117 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
7118 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00007119 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00007120 return 0;
pbrook53a59602006-03-25 19:31:22 +00007121}
7122
bellard579a97f2007-11-11 14:26:47 +00007123static inline abi_long host_to_target_timespec(abi_ulong target_addr,
7124 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00007125{
7126 struct target_timespec *target_ts;
7127
bellard579a97f2007-11-11 14:26:47 +00007128 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
7129 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01007130 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
7131 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00007132 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00007133 return 0;
pbrook53a59602006-03-25 19:31:22 +00007134}
7135
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007136static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
7137 abi_ulong target_addr)
7138{
7139 struct target_itimerspec *target_itspec;
7140
7141 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
7142 return -TARGET_EFAULT;
7143 }
7144
7145 host_itspec->it_interval.tv_sec =
7146 tswapal(target_itspec->it_interval.tv_sec);
7147 host_itspec->it_interval.tv_nsec =
7148 tswapal(target_itspec->it_interval.tv_nsec);
7149 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
7150 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
7151
7152 unlock_user_struct(target_itspec, target_addr, 1);
7153 return 0;
7154}
7155
7156static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
7157 struct itimerspec *host_its)
7158{
7159 struct target_itimerspec *target_itspec;
7160
7161 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
7162 return -TARGET_EFAULT;
7163 }
7164
7165 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
7166 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
7167
7168 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
7169 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
7170
7171 unlock_user_struct(target_itspec, target_addr, 0);
7172 return 0;
7173}
7174
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007175static inline abi_long target_to_host_timex(struct timex *host_tx,
7176 abi_long target_addr)
7177{
7178 struct target_timex *target_tx;
7179
7180 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7181 return -TARGET_EFAULT;
7182 }
7183
7184 __get_user(host_tx->modes, &target_tx->modes);
7185 __get_user(host_tx->offset, &target_tx->offset);
7186 __get_user(host_tx->freq, &target_tx->freq);
7187 __get_user(host_tx->maxerror, &target_tx->maxerror);
7188 __get_user(host_tx->esterror, &target_tx->esterror);
7189 __get_user(host_tx->status, &target_tx->status);
7190 __get_user(host_tx->constant, &target_tx->constant);
7191 __get_user(host_tx->precision, &target_tx->precision);
7192 __get_user(host_tx->tolerance, &target_tx->tolerance);
7193 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7194 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7195 __get_user(host_tx->tick, &target_tx->tick);
7196 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7197 __get_user(host_tx->jitter, &target_tx->jitter);
7198 __get_user(host_tx->shift, &target_tx->shift);
7199 __get_user(host_tx->stabil, &target_tx->stabil);
7200 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7201 __get_user(host_tx->calcnt, &target_tx->calcnt);
7202 __get_user(host_tx->errcnt, &target_tx->errcnt);
7203 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7204 __get_user(host_tx->tai, &target_tx->tai);
7205
7206 unlock_user_struct(target_tx, target_addr, 0);
7207 return 0;
7208}
7209
7210static inline abi_long host_to_target_timex(abi_long target_addr,
7211 struct timex *host_tx)
7212{
7213 struct target_timex *target_tx;
7214
7215 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7216 return -TARGET_EFAULT;
7217 }
7218
7219 __put_user(host_tx->modes, &target_tx->modes);
7220 __put_user(host_tx->offset, &target_tx->offset);
7221 __put_user(host_tx->freq, &target_tx->freq);
7222 __put_user(host_tx->maxerror, &target_tx->maxerror);
7223 __put_user(host_tx->esterror, &target_tx->esterror);
7224 __put_user(host_tx->status, &target_tx->status);
7225 __put_user(host_tx->constant, &target_tx->constant);
7226 __put_user(host_tx->precision, &target_tx->precision);
7227 __put_user(host_tx->tolerance, &target_tx->tolerance);
7228 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7229 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7230 __put_user(host_tx->tick, &target_tx->tick);
7231 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7232 __put_user(host_tx->jitter, &target_tx->jitter);
7233 __put_user(host_tx->shift, &target_tx->shift);
7234 __put_user(host_tx->stabil, &target_tx->stabil);
7235 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7236 __put_user(host_tx->calcnt, &target_tx->calcnt);
7237 __put_user(host_tx->errcnt, &target_tx->errcnt);
7238 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7239 __put_user(host_tx->tai, &target_tx->tai);
7240
7241 unlock_user_struct(target_tx, target_addr, 1);
7242 return 0;
7243}
7244
7245
Peter Maydellc0659762014-08-09 15:42:32 +01007246static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7247 abi_ulong target_addr)
7248{
7249 struct target_sigevent *target_sevp;
7250
7251 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7252 return -TARGET_EFAULT;
7253 }
7254
7255 /* This union is awkward on 64 bit systems because it has a 32 bit
7256 * integer and a pointer in it; we follow the conversion approach
7257 * used for handling sigval types in signal.c so the guest should get
7258 * the correct value back even if we did a 64 bit byteswap and it's
7259 * using the 32 bit integer.
7260 */
7261 host_sevp->sigev_value.sival_ptr =
7262 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7263 host_sevp->sigev_signo =
7264 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7265 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7266 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7267
7268 unlock_user_struct(target_sevp, target_addr, 1);
7269 return 0;
7270}
7271
Tom Musta6f6a4032014-08-12 13:53:42 -05007272#if defined(TARGET_NR_mlockall)
7273static inline int target_to_host_mlockall_arg(int arg)
7274{
7275 int result = 0;
7276
7277 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7278 result |= MCL_CURRENT;
7279 }
7280 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7281 result |= MCL_FUTURE;
7282 }
7283 return result;
7284}
7285#endif
7286
balrog6a24a772008-09-20 02:23:36 +00007287static inline abi_long host_to_target_stat64(void *cpu_env,
7288 abi_ulong target_addr,
7289 struct stat *host_st)
7290{
Alexander Graf09701192013-09-03 20:12:15 +01007291#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007292 if (((CPUARMState *)cpu_env)->eabi) {
7293 struct target_eabi_stat64 *target_st;
7294
7295 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7296 return -TARGET_EFAULT;
7297 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7298 __put_user(host_st->st_dev, &target_st->st_dev);
7299 __put_user(host_st->st_ino, &target_st->st_ino);
7300#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7301 __put_user(host_st->st_ino, &target_st->__st_ino);
7302#endif
7303 __put_user(host_st->st_mode, &target_st->st_mode);
7304 __put_user(host_st->st_nlink, &target_st->st_nlink);
7305 __put_user(host_st->st_uid, &target_st->st_uid);
7306 __put_user(host_st->st_gid, &target_st->st_gid);
7307 __put_user(host_st->st_rdev, &target_st->st_rdev);
7308 __put_user(host_st->st_size, &target_st->st_size);
7309 __put_user(host_st->st_blksize, &target_st->st_blksize);
7310 __put_user(host_st->st_blocks, &target_st->st_blocks);
7311 __put_user(host_st->st_atime, &target_st->target_st_atime);
7312 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7313 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7314 unlock_user_struct(target_st, target_addr, 1);
7315 } else
7316#endif
7317 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007318#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007319 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007320#else
7321 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007322#endif
balrog6a24a772008-09-20 02:23:36 +00007323
7324 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7325 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007326 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007327 __put_user(host_st->st_dev, &target_st->st_dev);
7328 __put_user(host_st->st_ino, &target_st->st_ino);
7329#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7330 __put_user(host_st->st_ino, &target_st->__st_ino);
7331#endif
7332 __put_user(host_st->st_mode, &target_st->st_mode);
7333 __put_user(host_st->st_nlink, &target_st->st_nlink);
7334 __put_user(host_st->st_uid, &target_st->st_uid);
7335 __put_user(host_st->st_gid, &target_st->st_gid);
7336 __put_user(host_st->st_rdev, &target_st->st_rdev);
7337 /* XXX: better use of kernel struct */
7338 __put_user(host_st->st_size, &target_st->st_size);
7339 __put_user(host_st->st_blksize, &target_st->st_blksize);
7340 __put_user(host_st->st_blocks, &target_st->st_blocks);
7341 __put_user(host_st->st_atime, &target_st->target_st_atime);
7342 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7343 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7344 unlock_user_struct(target_st, target_addr, 1);
7345 }
7346
7347 return 0;
7348}
balrog6a24a772008-09-20 02:23:36 +00007349
pbrookbd0c5662008-05-29 14:34:11 +00007350/* ??? Using host futex calls even when target atomic operations
7351 are not really atomic probably breaks things. However implementing
7352 futexes locally would make futexes shared between multiple processes
7353 tricky. However they're probably useless because guest atomic
7354 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007355static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7356 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007357{
7358 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007359 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007360
7361 /* ??? We assume FUTEX_* constants are the same on both host
7362 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007363#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007364 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007365#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007366 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007367#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007368 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007369 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007370 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007371 if (timeout) {
7372 pts = &ts;
7373 target_to_host_timespec(pts, timeout);
7374 } else {
7375 pts = NULL;
7376 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007377 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007378 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007379 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007380 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007381 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007382 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007383 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007384 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007385 case FUTEX_WAKE_OP:
7386 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7387 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7388 But the prototype takes a `struct timespec *'; insert casts
7389 to satisfy the compiler. We do not need to tswap TIMEOUT
7390 since it's not compared to guest memory. */
7391 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007392 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7393 g2h(uaddr2),
7394 (base_op == FUTEX_CMP_REQUEUE
7395 ? tswap32(val3)
7396 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007397 default:
7398 return -TARGET_ENOSYS;
7399 }
7400}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007401#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7402static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7403 abi_long handle, abi_long mount_id,
7404 abi_long flags)
7405{
7406 struct file_handle *target_fh;
7407 struct file_handle *fh;
7408 int mid = 0;
7409 abi_long ret;
7410 char *name;
7411 unsigned int size, total_size;
7412
7413 if (get_user_s32(size, handle)) {
7414 return -TARGET_EFAULT;
7415 }
7416
7417 name = lock_user_string(pathname);
7418 if (!name) {
7419 return -TARGET_EFAULT;
7420 }
7421
7422 total_size = sizeof(struct file_handle) + size;
7423 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7424 if (!target_fh) {
7425 unlock_user(name, pathname, 0);
7426 return -TARGET_EFAULT;
7427 }
7428
7429 fh = g_malloc0(total_size);
7430 fh->handle_bytes = size;
7431
7432 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7433 unlock_user(name, pathname, 0);
7434
7435 /* man name_to_handle_at(2):
7436 * Other than the use of the handle_bytes field, the caller should treat
7437 * the file_handle structure as an opaque data type
7438 */
7439
7440 memcpy(target_fh, fh, total_size);
7441 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7442 target_fh->handle_type = tswap32(fh->handle_type);
7443 g_free(fh);
7444 unlock_user(target_fh, handle, total_size);
7445
7446 if (put_user_s32(mid, mount_id)) {
7447 return -TARGET_EFAULT;
7448 }
7449
7450 return ret;
7451
7452}
7453#endif
7454
7455#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7456static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7457 abi_long flags)
7458{
7459 struct file_handle *target_fh;
7460 struct file_handle *fh;
7461 unsigned int size, total_size;
7462 abi_long ret;
7463
7464 if (get_user_s32(size, handle)) {
7465 return -TARGET_EFAULT;
7466 }
7467
7468 total_size = sizeof(struct file_handle) + size;
7469 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7470 if (!target_fh) {
7471 return -TARGET_EFAULT;
7472 }
7473
Thomas Huthe9d49d52015-10-09 17:56:38 +02007474 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007475 fh->handle_bytes = size;
7476 fh->handle_type = tswap32(target_fh->handle_type);
7477
7478 ret = get_errno(open_by_handle_at(mount_fd, fh,
7479 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7480
7481 g_free(fh);
7482
7483 unlock_user(target_fh, handle, total_size);
7484
7485 return ret;
7486}
7487#endif
pbrookbd0c5662008-05-29 14:34:11 +00007488
Laurent Viviere36800c2015-10-02 14:48:09 +02007489#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7490
7491/* signalfd siginfo conversion */
7492
7493static void
7494host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7495 const struct signalfd_siginfo *info)
7496{
7497 int sig = host_to_target_signal(info->ssi_signo);
7498
7499 /* linux/signalfd.h defines a ssi_addr_lsb
7500 * not defined in sys/signalfd.h but used by some kernels
7501 */
7502
7503#ifdef BUS_MCEERR_AO
7504 if (tinfo->ssi_signo == SIGBUS &&
7505 (tinfo->ssi_code == BUS_MCEERR_AR ||
7506 tinfo->ssi_code == BUS_MCEERR_AO)) {
7507 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7508 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7509 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7510 }
7511#endif
7512
7513 tinfo->ssi_signo = tswap32(sig);
7514 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7515 tinfo->ssi_code = tswap32(info->ssi_code);
7516 tinfo->ssi_pid = tswap32(info->ssi_pid);
7517 tinfo->ssi_uid = tswap32(info->ssi_uid);
7518 tinfo->ssi_fd = tswap32(info->ssi_fd);
7519 tinfo->ssi_tid = tswap32(info->ssi_tid);
7520 tinfo->ssi_band = tswap32(info->ssi_band);
7521 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7522 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7523 tinfo->ssi_status = tswap32(info->ssi_status);
7524 tinfo->ssi_int = tswap32(info->ssi_int);
7525 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7526 tinfo->ssi_utime = tswap64(info->ssi_utime);
7527 tinfo->ssi_stime = tswap64(info->ssi_stime);
7528 tinfo->ssi_addr = tswap64(info->ssi_addr);
7529}
7530
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007531static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007532{
7533 int i;
7534
7535 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7536 host_to_target_signalfd_siginfo(buf + i, buf + i);
7537 }
7538
7539 return len;
7540}
7541
7542static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007543 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007544};
7545
7546static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7547{
7548 int host_flags;
7549 target_sigset_t *target_mask;
7550 sigset_t host_mask;
7551 abi_long ret;
7552
7553 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7554 return -TARGET_EINVAL;
7555 }
7556 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7557 return -TARGET_EFAULT;
7558 }
7559
7560 target_to_host_sigset(&host_mask, target_mask);
7561
7562 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7563
7564 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7565 if (ret >= 0) {
7566 fd_trans_register(ret, &target_signalfd_trans);
7567 }
7568
7569 unlock_user_struct(target_mask, mask, 0);
7570
7571 return ret;
7572}
7573#endif
7574
pbrook1d9d8b52009-04-16 15:17:02 +00007575/* Map host to target signal numbers for the wait family of syscalls.
7576 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007577int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007578{
7579 if (WIFSIGNALED(status)) {
7580 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7581 }
7582 if (WIFSTOPPED(status)) {
7583 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7584 | (status & 0xff);
7585 }
7586 return status;
7587}
7588
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007589static int open_self_cmdline(void *cpu_env, int fd)
7590{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007591 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7592 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7593 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007594
Andreas Schwab58de8b92017-03-20 12:31:55 +01007595 for (i = 0; i < bprm->argc; i++) {
7596 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007597
Andreas Schwab58de8b92017-03-20 12:31:55 +01007598 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007599 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007600 }
7601 }
7602
Andreas Schwab58de8b92017-03-20 12:31:55 +01007603 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007604}
7605
Alexander Graf36c08d42011-11-02 20:23:24 +01007606static int open_self_maps(void *cpu_env, int fd)
7607{
Andreas Färber0429a972013-08-26 18:14:44 +02007608 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7609 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007610 FILE *fp;
7611 char *line = NULL;
7612 size_t len = 0;
7613 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007614
Alexander Graf1a49ef22012-05-01 16:30:28 +01007615 fp = fopen("/proc/self/maps", "r");
7616 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007617 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007618 }
7619
7620 while ((read = getline(&line, &len, fp)) != -1) {
7621 int fields, dev_maj, dev_min, inode;
7622 uint64_t min, max, offset;
7623 char flag_r, flag_w, flag_x, flag_p;
7624 char path[512] = "";
7625 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7626 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7627 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7628
7629 if ((fields < 10) || (fields > 11)) {
7630 continue;
7631 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007632 if (h2g_valid(min)) {
7633 int flags = page_get_flags(h2g(min));
Max Filippovebf9a362018-03-07 13:50:10 -08007634 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007635 if (page_check_range(h2g(min), max - min, flags) == -1) {
7636 continue;
7637 }
7638 if (h2g(min) == ts->info->stack_limit) {
7639 pstrcpy(path, sizeof(path), " [stack]");
7640 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007641 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007642 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007643 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007644 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007645 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007646 }
7647 }
7648
7649 free(line);
7650 fclose(fp);
7651
Alexander Graf36c08d42011-11-02 20:23:24 +01007652 return 0;
7653}
7654
Alexander Graf480b8e72011-11-02 20:23:25 +01007655static int open_self_stat(void *cpu_env, int fd)
7656{
Andreas Färber0429a972013-08-26 18:14:44 +02007657 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7658 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007659 abi_ulong start_stack = ts->info->start_stack;
7660 int i;
7661
7662 for (i = 0; i < 44; i++) {
7663 char buf[128];
7664 int len;
7665 uint64_t val = 0;
7666
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007667 if (i == 0) {
7668 /* pid */
7669 val = getpid();
7670 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7671 } else if (i == 1) {
7672 /* app name */
7673 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7674 } else if (i == 27) {
7675 /* stack bottom */
7676 val = start_stack;
7677 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7678 } else {
7679 /* for the rest, there is MasterCard */
7680 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007681 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007682
Alexander Graf480b8e72011-11-02 20:23:25 +01007683 len = strlen(buf);
7684 if (write(fd, buf, len) != len) {
7685 return -1;
7686 }
7687 }
7688
7689 return 0;
7690}
7691
Alexander Graf257450e2011-11-02 20:23:26 +01007692static int open_self_auxv(void *cpu_env, int fd)
7693{
Andreas Färber0429a972013-08-26 18:14:44 +02007694 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7695 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007696 abi_ulong auxv = ts->info->saved_auxv;
7697 abi_ulong len = ts->info->auxv_len;
7698 char *ptr;
7699
7700 /*
7701 * Auxiliary vector is stored in target process stack.
7702 * read in whole auxv vector and copy it to file
7703 */
7704 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7705 if (ptr != NULL) {
7706 while (len > 0) {
7707 ssize_t r;
7708 r = write(fd, ptr, len);
7709 if (r <= 0) {
7710 break;
7711 }
7712 len -= r;
7713 ptr += r;
7714 }
7715 lseek(fd, 0, SEEK_SET);
7716 unlock_user(ptr, auxv, len);
7717 }
7718
7719 return 0;
7720}
7721
Andreas Schwab463d8e72013-07-02 14:04:12 +01007722static int is_proc_myself(const char *filename, const char *entry)
7723{
7724 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7725 filename += strlen("/proc/");
7726 if (!strncmp(filename, "self/", strlen("self/"))) {
7727 filename += strlen("self/");
7728 } else if (*filename >= '1' && *filename <= '9') {
7729 char myself[80];
7730 snprintf(myself, sizeof(myself), "%d/", getpid());
7731 if (!strncmp(filename, myself, strlen(myself))) {
7732 filename += strlen(myself);
7733 } else {
7734 return 0;
7735 }
7736 } else {
7737 return 0;
7738 }
7739 if (!strcmp(filename, entry)) {
7740 return 1;
7741 }
7742 }
7743 return 0;
7744}
7745
Laurent Vivierde6b9932013-08-30 01:46:40 +02007746#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7747static int is_proc(const char *filename, const char *entry)
7748{
7749 return strcmp(filename, entry) == 0;
7750}
7751
7752static int open_net_route(void *cpu_env, int fd)
7753{
7754 FILE *fp;
7755 char *line = NULL;
7756 size_t len = 0;
7757 ssize_t read;
7758
7759 fp = fopen("/proc/net/route", "r");
7760 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007761 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007762 }
7763
7764 /* read header */
7765
7766 read = getline(&line, &len, fp);
7767 dprintf(fd, "%s", line);
7768
7769 /* read routes */
7770
7771 while ((read = getline(&line, &len, fp)) != -1) {
7772 char iface[16];
7773 uint32_t dest, gw, mask;
7774 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7775 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7776 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7777 &mask, &mtu, &window, &irtt);
7778 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7779 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7780 metric, tswap32(mask), mtu, window, irtt);
7781 }
7782
7783 free(line);
7784 fclose(fp);
7785
7786 return 0;
7787}
7788#endif
7789
Riku Voipio0b2effd2014-08-06 10:36:37 +03007790static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007791{
7792 struct fake_open {
7793 const char *filename;
7794 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007795 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007796 };
7797 const struct fake_open *fake_open;
7798 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007799 { "maps", open_self_maps, is_proc_myself },
7800 { "stat", open_self_stat, is_proc_myself },
7801 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007802 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007803#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7804 { "/proc/net/route", open_net_route, is_proc },
7805#endif
7806 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007807 };
7808
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007809 if (is_proc_myself(pathname, "exe")) {
7810 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007811 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007812 }
7813
Alexander Graf3be14d02011-11-02 20:23:23 +01007814 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007815 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007816 break;
7817 }
7818 }
7819
7820 if (fake_open->filename) {
7821 const char *tmpdir;
7822 char filename[PATH_MAX];
7823 int fd, r;
7824
7825 /* create temporary file to map stat to */
7826 tmpdir = getenv("TMPDIR");
7827 if (!tmpdir)
7828 tmpdir = "/tmp";
7829 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7830 fd = mkstemp(filename);
7831 if (fd < 0) {
7832 return fd;
7833 }
7834 unlink(filename);
7835
7836 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007837 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007838 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007839 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007840 return r;
7841 }
7842 lseek(fd, 0, SEEK_SET);
7843
7844 return fd;
7845 }
7846
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007847 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007848}
7849
Alexander Grafaecc8862014-11-10 21:33:03 +01007850#define TIMER_MAGIC 0x0caf0000
7851#define TIMER_MAGIC_MASK 0xffff0000
7852
7853/* Convert QEMU provided timer ID back to internal 16bit index format */
7854static target_timer_t get_timer_id(abi_long arg)
7855{
7856 target_timer_t timerid = arg;
7857
7858 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7859 return -TARGET_EINVAL;
7860 }
7861
7862 timerid &= 0xffff;
7863
7864 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7865 return -TARGET_EINVAL;
7866 }
7867
7868 return timerid;
7869}
7870
Laurent Vivier562a20b2017-03-01 10:37:48 +01007871static abi_long swap_data_eventfd(void *buf, size_t len)
7872{
7873 uint64_t *counter = buf;
7874 int i;
7875
7876 if (len < sizeof(uint64_t)) {
7877 return -EINVAL;
7878 }
7879
7880 for (i = 0; i < len; i += sizeof(uint64_t)) {
7881 *counter = tswap64(*counter);
7882 counter++;
7883 }
7884
7885 return len;
7886}
7887
7888static TargetFdTrans target_eventfd_trans = {
7889 .host_to_target_data = swap_data_eventfd,
7890 .target_to_host_data = swap_data_eventfd,
7891};
7892
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007893#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7894 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7895 defined(__NR_inotify_init1))
7896static abi_long host_to_target_data_inotify(void *buf, size_t len)
7897{
7898 struct inotify_event *ev;
7899 int i;
7900 uint32_t name_len;
7901
7902 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7903 ev = (struct inotify_event *)((char *)buf + i);
7904 name_len = ev->len;
7905
7906 ev->wd = tswap32(ev->wd);
7907 ev->mask = tswap32(ev->mask);
7908 ev->cookie = tswap32(ev->cookie);
7909 ev->len = tswap32(name_len);
7910 }
7911
7912 return len;
7913}
7914
7915static TargetFdTrans target_inotify_trans = {
7916 .host_to_target_data = host_to_target_data_inotify,
7917};
7918#endif
7919
Samuel Thibault2e0a8712018-01-09 21:16:43 +01007920static int target_to_host_cpu_mask(unsigned long *host_mask,
7921 size_t host_size,
7922 abi_ulong target_addr,
7923 size_t target_size)
7924{
7925 unsigned target_bits = sizeof(abi_ulong) * 8;
7926 unsigned host_bits = sizeof(*host_mask) * 8;
7927 abi_ulong *target_mask;
7928 unsigned i, j;
7929
7930 assert(host_size >= target_size);
7931
7932 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7933 if (!target_mask) {
7934 return -TARGET_EFAULT;
7935 }
7936 memset(host_mask, 0, host_size);
7937
7938 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7939 unsigned bit = i * target_bits;
7940 abi_ulong val;
7941
7942 __get_user(val, &target_mask[i]);
7943 for (j = 0; j < target_bits; j++, bit++) {
7944 if (val & (1UL << j)) {
7945 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7946 }
7947 }
7948 }
7949
7950 unlock_user(target_mask, target_addr, 0);
7951 return 0;
7952}
7953
7954static int host_to_target_cpu_mask(const unsigned long *host_mask,
7955 size_t host_size,
7956 abi_ulong target_addr,
7957 size_t target_size)
7958{
7959 unsigned target_bits = sizeof(abi_ulong) * 8;
7960 unsigned host_bits = sizeof(*host_mask) * 8;
7961 abi_ulong *target_mask;
7962 unsigned i, j;
7963
7964 assert(host_size >= target_size);
7965
7966 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7967 if (!target_mask) {
7968 return -TARGET_EFAULT;
7969 }
7970
7971 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7972 unsigned bit = i * target_bits;
7973 abi_ulong val = 0;
7974
7975 for (j = 0; j < target_bits; j++, bit++) {
7976 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7977 val |= 1UL << j;
7978 }
7979 }
7980 __put_user(val, &target_mask[i]);
7981 }
7982
7983 unlock_user(target_mask, target_addr, target_size);
7984 return 0;
7985}
7986
ths0da46a62007-10-20 20:23:07 +00007987/* do_syscall() should always have a single exit point at the end so
7988 that actions, such as logging of syscall results, can be performed.
7989 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007990abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7991 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007992 abi_long arg5, abi_long arg6, abi_long arg7,
7993 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007994{
Andreas Färber182735e2013-05-29 22:29:20 +02007995 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007996 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007997 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007998 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007999 void *p;
ths3b46e622007-09-17 08:09:54 +00008000
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01008001#if defined(DEBUG_ERESTARTSYS)
8002 /* Debug-only code for exercising the syscall-restart code paths
8003 * in the per-architecture cpu main loops: restart every syscall
8004 * the guest makes once before letting it through.
8005 */
8006 {
8007 static int flag;
8008
8009 flag = !flag;
8010 if (flag) {
8011 return -TARGET_ERESTARTSYS;
8012 }
8013 }
8014#endif
8015
bellard72f03902003-02-18 23:33:18 +00008016#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00008017 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00008018#endif
Lluís Vilanova9c15e702016-06-21 15:52:04 +02008019 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00008020 if(do_strace)
8021 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
8022
bellard31e31b82003-02-18 22:55:36 +00008023 switch(num) {
8024 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02008025 /* In old applications this may be used to implement _exit(2).
8026 However in threaded applictions it is used for thread termination,
8027 and _exit_group is used for application termination.
8028 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01008029
8030 if (block_signals()) {
8031 ret = -TARGET_ERESTARTSYS;
8032 break;
8033 }
8034
Alex Bennéedd1f6342016-09-30 22:31:01 +01008035 cpu_list_lock();
8036
Andreas Färberbdc44642013-06-24 23:50:24 +02008037 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02008038 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00008039
Andreas Färber9b056fc2013-06-24 23:53:10 +02008040 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02008041 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01008042
Andreas Färber9b056fc2013-06-24 23:53:10 +02008043 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01008044
Andreas Färber0429a972013-08-26 18:14:44 +02008045 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02008046 if (ts->child_tidptr) {
8047 put_user_u32(0, ts->child_tidptr);
8048 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
8049 NULL, NULL, 0);
8050 }
Andreas Färbera2247f82013-06-09 19:47:04 +02008051 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02008052 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02008053 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04008054 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02008055 pthread_exit(NULL);
8056 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01008057
8058 cpu_list_unlock();
Alex Bennée708b6a62018-06-22 17:09:10 +01008059 preexit_cleanup(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00008060 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00008061 ret = 0; /* avoid warning */
8062 break;
8063 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00008064 if (arg3 == 0)
8065 ret = 0;
8066 else {
8067 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8068 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01008069 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008070 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01008071 fd_trans_host_to_target_data(arg1)) {
8072 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02008073 }
aurel3238d840e2009-01-30 19:48:17 +00008074 unlock_user(p, arg2, ret);
8075 }
bellard31e31b82003-02-18 22:55:36 +00008076 break;
8077 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00008078 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8079 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01008080 if (fd_trans_target_to_host_data(arg1)) {
8081 void *copy = g_malloc(arg3);
8082 memcpy(copy, p, arg3);
8083 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
8084 if (ret >= 0) {
8085 ret = get_errno(safe_write(arg1, copy, ret));
8086 }
8087 g_free(copy);
8088 } else {
8089 ret = get_errno(safe_write(arg1, p, arg3));
8090 }
pbrook53a59602006-03-25 19:31:22 +00008091 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00008092 break;
Chen Gang704eff62015-08-21 05:37:33 +08008093#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00008094 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00008095 if (!(p = lock_user_string(arg1)))
8096 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008097 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
8098 target_to_host_bitmask(arg2, fcntl_flags_tbl),
8099 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008100 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008101 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008102 break;
Chen Gang704eff62015-08-21 05:37:33 +08008103#endif
ths82424832007-09-24 09:21:55 +00008104 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00008105 if (!(p = lock_user_string(arg2)))
8106 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03008107 ret = get_errno(do_openat(cpu_env, arg1, p,
8108 target_to_host_bitmask(arg3, fcntl_flags_tbl),
8109 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02008110 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00008111 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00008112 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008113#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8114 case TARGET_NR_name_to_handle_at:
8115 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
8116 break;
8117#endif
8118#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8119 case TARGET_NR_open_by_handle_at:
8120 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008121 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008122 break;
8123#endif
bellard31e31b82003-02-18 22:55:36 +00008124 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02008125 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00008126 ret = get_errno(close(arg1));
8127 break;
8128 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00008129 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00008130 break;
Chen Gang704eff62015-08-21 05:37:33 +08008131#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00008132 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01008133 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008134 break;
Chen Gang704eff62015-08-21 05:37:33 +08008135#endif
thse5febef2007-04-01 18:31:35 +00008136#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00008137 case TARGET_NR_waitpid:
8138 {
pbrook53a59602006-03-25 19:31:22 +00008139 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008140 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01008141 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00008142 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00008143 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008144 }
8145 break;
thse5febef2007-04-01 18:31:35 +00008146#endif
pbrookf0cbb612008-05-30 18:20:05 +00008147#ifdef TARGET_NR_waitid
8148 case TARGET_NR_waitid:
8149 {
8150 siginfo_t info;
8151 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008152 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00008153 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008154 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00008155 goto efault;
8156 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05008157 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00008158 }
8159 }
8160 break;
8161#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008162#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008163 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00008164 if (!(p = lock_user_string(arg1)))
8165 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008166 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008167 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008168 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008169 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008170#endif
Chen Gang704eff62015-08-21 05:37:33 +08008171#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00008172 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00008173 {
8174 void * p2;
8175 p = lock_user_string(arg1);
8176 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008177 if (!p || !p2)
8178 ret = -TARGET_EFAULT;
8179 else
8180 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008181 unlock_user(p2, arg2, 0);
8182 unlock_user(p, arg1, 0);
8183 }
bellard31e31b82003-02-18 22:55:36 +00008184 break;
Chen Gang704eff62015-08-21 05:37:33 +08008185#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008186#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008187 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008188 {
8189 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008190 if (!arg2 || !arg4)
8191 goto efault;
ths64f0ce42007-09-24 09:25:06 +00008192 p = lock_user_string(arg2);
8193 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008194 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008195 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008196 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008197 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008198 unlock_user(p, arg2, 0);
8199 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008200 }
8201 break;
8202#endif
Chen Gang704eff62015-08-21 05:37:33 +08008203#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008204 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008205 if (!(p = lock_user_string(arg1)))
8206 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008207 ret = get_errno(unlink(p));
8208 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008209 break;
Chen Gang704eff62015-08-21 05:37:33 +08008210#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008211#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008212 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008213 if (!(p = lock_user_string(arg2)))
8214 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008215 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008216 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00008217 break;
balrogb7d35e62007-12-12 00:40:24 +00008218#endif
bellard31e31b82003-02-18 22:55:36 +00008219 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008220 {
8221 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008222 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008223 abi_ulong gp;
8224 abi_ulong guest_argp;
8225 abi_ulong guest_envp;
8226 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008227 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008228 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008229
bellardf7341ff2003-03-30 21:00:25 +00008230 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008231 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008232 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008233 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008234 goto efault;
ths03aa1972007-12-02 06:28:08 +00008235 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008236 break;
bellard7854b052003-03-29 17:22:23 +00008237 argc++;
bellard2f619692007-11-16 10:46:05 +00008238 }
bellardf7341ff2003-03-30 21:00:25 +00008239 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008240 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008241 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008242 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008243 goto efault;
ths03aa1972007-12-02 06:28:08 +00008244 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008245 break;
bellard7854b052003-03-29 17:22:23 +00008246 envc++;
bellard2f619692007-11-16 10:46:05 +00008247 }
bellard7854b052003-03-29 17:22:23 +00008248
Prasad J Panditb936cb52017-03-07 12:51:47 +05308249 argp = g_new0(char *, argc + 1);
8250 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008251
pbrookda94d262008-05-30 18:24:00 +00008252 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008253 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008254 if (get_user_ual(addr, gp))
8255 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008256 if (!addr)
8257 break;
bellard2f619692007-11-16 10:46:05 +00008258 if (!(*q = lock_user_string(addr)))
8259 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008260 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008261 }
bellardf7341ff2003-03-30 21:00:25 +00008262 *q = NULL;
8263
pbrookda94d262008-05-30 18:24:00 +00008264 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008265 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008266 if (get_user_ual(addr, gp))
8267 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008268 if (!addr)
8269 break;
bellard2f619692007-11-16 10:46:05 +00008270 if (!(*q = lock_user_string(addr)))
8271 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008272 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008273 }
bellardf7341ff2003-03-30 21:00:25 +00008274 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008275
bellard2f619692007-11-16 10:46:05 +00008276 if (!(p = lock_user_string(arg1)))
8277 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008278 /* Although execve() is not an interruptible syscall it is
8279 * a special case where we must use the safe_syscall wrapper:
8280 * if we allow a signal to happen before we make the host
8281 * syscall then we will 'lose' it, because at the point of
8282 * execve the process leaves QEMU's control. So we use the
8283 * safe syscall wrapper to ensure that we either take the
8284 * signal as a guest signal, or else it does not happen
8285 * before the execve completes and makes it the other
8286 * program's problem.
8287 */
8288 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008289 unlock_user(p, arg1, 0);
8290
bellard2f619692007-11-16 10:46:05 +00008291 goto execve_end;
8292
8293 execve_efault:
8294 ret = -TARGET_EFAULT;
8295
8296 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008297 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008298 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008299 if (get_user_ual(addr, gp)
8300 || !addr)
8301 break;
pbrook53a59602006-03-25 19:31:22 +00008302 unlock_user(*q, addr, 0);
8303 }
8304 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008305 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008306 if (get_user_ual(addr, gp)
8307 || !addr)
8308 break;
pbrook53a59602006-03-25 19:31:22 +00008309 unlock_user(*q, addr, 0);
8310 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308311
8312 g_free(argp);
8313 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008314 }
bellard31e31b82003-02-18 22:55:36 +00008315 break;
8316 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008317 if (!(p = lock_user_string(arg1)))
8318 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008319 ret = get_errno(chdir(p));
8320 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008321 break;
bellarda315a142005-01-30 22:59:18 +00008322#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008323 case TARGET_NR_time:
8324 {
pbrook53a59602006-03-25 19:31:22 +00008325 time_t host_time;
8326 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008327 if (!is_error(ret)
8328 && arg1
8329 && put_user_sal(host_time, arg1))
8330 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008331 }
8332 break;
bellarda315a142005-01-30 22:59:18 +00008333#endif
Chen Gang704eff62015-08-21 05:37:33 +08008334#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008335 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008336 if (!(p = lock_user_string(arg1)))
8337 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008338 ret = get_errno(mknod(p, arg2, arg3));
8339 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008340 break;
Chen Gang704eff62015-08-21 05:37:33 +08008341#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008342#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008343 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008344 if (!(p = lock_user_string(arg2)))
8345 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008346 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008347 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008348 break;
8349#endif
Chen Gang704eff62015-08-21 05:37:33 +08008350#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008351 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008352 if (!(p = lock_user_string(arg1)))
8353 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008354 ret = get_errno(chmod(p, arg2));
8355 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008356 break;
Chen Gang704eff62015-08-21 05:37:33 +08008357#endif
bellardebc05482003-09-30 21:08:41 +00008358#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008359 case TARGET_NR_break:
8360 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008361#endif
8362#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008363 case TARGET_NR_oldstat:
8364 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008365#endif
bellard31e31b82003-02-18 22:55:36 +00008366 case TARGET_NR_lseek:
8367 ret = get_errno(lseek(arg1, arg2, arg3));
8368 break;
Richard Henderson92317332010-05-03 10:07:53 -07008369#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8370 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008371 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008372 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008373 ret = get_errno(getpid());
8374 break;
Richard Henderson92317332010-05-03 10:07:53 -07008375#endif
8376#ifdef TARGET_NR_getpid
8377 case TARGET_NR_getpid:
8378 ret = get_errno(getpid());
8379 break;
8380#endif
bellard31e31b82003-02-18 22:55:36 +00008381 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008382 {
8383 /* need to look at the data field */
8384 void *p2, *p3;
8385
8386 if (arg1) {
8387 p = lock_user_string(arg1);
8388 if (!p) {
8389 goto efault;
8390 }
8391 } else {
8392 p = NULL;
8393 }
8394
8395 p2 = lock_user_string(arg2);
8396 if (!p2) {
8397 if (arg1) {
8398 unlock_user(p, arg1, 0);
8399 }
8400 goto efault;
8401 }
8402
8403 if (arg3) {
8404 p3 = lock_user_string(arg3);
8405 if (!p3) {
8406 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008407 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008408 }
8409 unlock_user(p2, arg2, 0);
8410 goto efault;
8411 }
8412 } else {
8413 p3 = NULL;
8414 }
8415
8416 /* FIXME - arg5 should be locked, but it isn't clear how to
8417 * do that since it's not guaranteed to be a NULL-terminated
8418 * string.
8419 */
8420 if (!arg5) {
8421 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8422 } else {
8423 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8424 }
8425 ret = get_errno(ret);
8426
8427 if (arg1) {
8428 unlock_user(p, arg1, 0);
8429 }
8430 unlock_user(p2, arg2, 0);
8431 if (arg3) {
8432 unlock_user(p3, arg3, 0);
8433 }
8434 }
8435 break;
thse5febef2007-04-01 18:31:35 +00008436#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008437 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008438 if (!(p = lock_user_string(arg1)))
8439 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008440 ret = get_errno(umount(p));
8441 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008442 break;
thse5febef2007-04-01 18:31:35 +00008443#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008444#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008445 case TARGET_NR_stime:
8446 {
pbrook53a59602006-03-25 19:31:22 +00008447 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008448 if (get_user_sal(host_time, arg1))
8449 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008450 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008451 }
8452 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008453#endif
bellard31e31b82003-02-18 22:55:36 +00008454 case TARGET_NR_ptrace:
8455 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008456#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008457 case TARGET_NR_alarm:
8458 ret = alarm(arg1);
8459 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008460#endif
bellardebc05482003-09-30 21:08:41 +00008461#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008462 case TARGET_NR_oldfstat:
8463 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008464#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008465#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008466 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008467 if (!block_signals()) {
8468 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8469 }
8470 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008471 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008472#endif
thse5febef2007-04-01 18:31:35 +00008473#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008474 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008475 {
pbrook53a59602006-03-25 19:31:22 +00008476 struct utimbuf tbuf, *host_tbuf;
8477 struct target_utimbuf *target_tbuf;
8478 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008479 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8480 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008481 tbuf.actime = tswapal(target_tbuf->actime);
8482 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008483 unlock_user_struct(target_tbuf, arg2, 0);
8484 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008485 } else {
pbrook53a59602006-03-25 19:31:22 +00008486 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008487 }
bellard579a97f2007-11-11 14:26:47 +00008488 if (!(p = lock_user_string(arg1)))
8489 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008490 ret = get_errno(utime(p, host_tbuf));
8491 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008492 }
8493 break;
thse5febef2007-04-01 18:31:35 +00008494#endif
Chen Gang704eff62015-08-21 05:37:33 +08008495#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008496 case TARGET_NR_utimes:
8497 {
bellard978a66f2004-12-06 22:58:05 +00008498 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008499 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008500 if (copy_from_user_timeval(&tv[0], arg2)
8501 || copy_from_user_timeval(&tv[1],
8502 arg2 + sizeof(struct target_timeval)))
8503 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008504 tvp = tv;
8505 } else {
8506 tvp = NULL;
8507 }
bellard579a97f2007-11-11 14:26:47 +00008508 if (!(p = lock_user_string(arg1)))
8509 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008510 ret = get_errno(utimes(p, tvp));
8511 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008512 }
8513 break;
Chen Gang704eff62015-08-21 05:37:33 +08008514#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008515#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008516 case TARGET_NR_futimesat:
8517 {
8518 struct timeval *tvp, tv[2];
8519 if (arg3) {
8520 if (copy_from_user_timeval(&tv[0], arg3)
8521 || copy_from_user_timeval(&tv[1],
8522 arg3 + sizeof(struct target_timeval)))
8523 goto efault;
8524 tvp = tv;
8525 } else {
8526 tvp = NULL;
8527 }
8528 if (!(p = lock_user_string(arg2)))
8529 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008530 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008531 unlock_user(p, arg2, 0);
8532 }
8533 break;
8534#endif
bellardebc05482003-09-30 21:08:41 +00008535#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008536 case TARGET_NR_stty:
8537 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008538#endif
8539#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008540 case TARGET_NR_gtty:
8541 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008542#endif
Chen Gang704eff62015-08-21 05:37:33 +08008543#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008544 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008545 if (!(p = lock_user_string(arg1)))
8546 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008547 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008548 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008549 break;
Chen Gang704eff62015-08-21 05:37:33 +08008550#endif
ths92a34c12007-09-24 09:27:49 +00008551#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8552 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008553 if (!(p = lock_user_string(arg2)))
8554 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008555 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008556 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008557 break;
8558#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008559#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008560 case TARGET_NR_nice:
8561 ret = get_errno(nice(arg1));
8562 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008563#endif
bellardebc05482003-09-30 21:08:41 +00008564#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008565 case TARGET_NR_ftime:
8566 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008567#endif
bellard31e31b82003-02-18 22:55:36 +00008568 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008569 sync();
8570 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008571 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008572#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8573 case TARGET_NR_syncfs:
8574 ret = get_errno(syncfs(arg1));
8575 break;
8576#endif
bellard31e31b82003-02-18 22:55:36 +00008577 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008578 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008579 break;
Chen Gang704eff62015-08-21 05:37:33 +08008580#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008581 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008582 {
8583 void *p2;
8584 p = lock_user_string(arg1);
8585 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008586 if (!p || !p2)
8587 ret = -TARGET_EFAULT;
8588 else
8589 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008590 unlock_user(p2, arg2, 0);
8591 unlock_user(p, arg1, 0);
8592 }
bellard31e31b82003-02-18 22:55:36 +00008593 break;
Chen Gang704eff62015-08-21 05:37:33 +08008594#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008595#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008596 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008597 {
bellard579a97f2007-11-11 14:26:47 +00008598 void *p2;
ths722183f2007-09-24 09:24:37 +00008599 p = lock_user_string(arg2);
8600 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008601 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008602 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008603 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008604 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008605 unlock_user(p2, arg4, 0);
8606 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008607 }
8608 break;
8609#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01008610#if defined(TARGET_NR_renameat2)
8611 case TARGET_NR_renameat2:
8612 {
8613 void *p2;
8614 p = lock_user_string(arg2);
8615 p2 = lock_user_string(arg4);
8616 if (!p || !p2) {
8617 ret = -TARGET_EFAULT;
8618 } else {
8619 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
8620 }
8621 unlock_user(p2, arg4, 0);
8622 unlock_user(p, arg2, 0);
8623 }
8624 break;
8625#endif
Chen Gang704eff62015-08-21 05:37:33 +08008626#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008627 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008628 if (!(p = lock_user_string(arg1)))
8629 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008630 ret = get_errno(mkdir(p, arg2));
8631 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008632 break;
Chen Gang704eff62015-08-21 05:37:33 +08008633#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008634#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008635 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008636 if (!(p = lock_user_string(arg2)))
8637 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008638 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008639 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008640 break;
8641#endif
Chen Gang704eff62015-08-21 05:37:33 +08008642#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008643 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008644 if (!(p = lock_user_string(arg1)))
8645 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008646 ret = get_errno(rmdir(p));
8647 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008648 break;
Chen Gang704eff62015-08-21 05:37:33 +08008649#endif
bellard31e31b82003-02-18 22:55:36 +00008650 case TARGET_NR_dup:
8651 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008652 if (ret >= 0) {
8653 fd_trans_dup(arg1, ret);
8654 }
bellard31e31b82003-02-18 22:55:36 +00008655 break;
Chen Gang704eff62015-08-21 05:37:33 +08008656#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008657 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008658 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008659 break;
Chen Gang704eff62015-08-21 05:37:33 +08008660#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008661#ifdef TARGET_NR_pipe2
8662 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008663 ret = do_pipe(cpu_env, arg1,
8664 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008665 break;
8666#endif
bellard31e31b82003-02-18 22:55:36 +00008667 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008668 {
pbrook53a59602006-03-25 19:31:22 +00008669 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008670 struct tms tms;
8671 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008672 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008673 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8674 if (!tmsp)
8675 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008676 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8677 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8678 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8679 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008680 }
bellardc596ed12003-07-13 17:32:31 +00008681 if (!is_error(ret))
8682 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008683 }
8684 break;
bellardebc05482003-09-30 21:08:41 +00008685#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008686 case TARGET_NR_prof:
8687 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008688#endif
thse5febef2007-04-01 18:31:35 +00008689#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008690 case TARGET_NR_signal:
8691 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008692#endif
bellard31e31b82003-02-18 22:55:36 +00008693 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008694 if (arg1 == 0) {
8695 ret = get_errno(acct(NULL));
8696 } else {
8697 if (!(p = lock_user_string(arg1)))
8698 goto efault;
8699 ret = get_errno(acct(path(p)));
8700 unlock_user(p, arg1, 0);
8701 }
pbrook24836682006-04-16 14:14:53 +00008702 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008703#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008704 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008705 if (!(p = lock_user_string(arg1)))
8706 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008707 ret = get_errno(umount2(p, arg2));
8708 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008709 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008710#endif
bellardebc05482003-09-30 21:08:41 +00008711#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008712 case TARGET_NR_lock:
8713 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008714#endif
bellard31e31b82003-02-18 22:55:36 +00008715 case TARGET_NR_ioctl:
8716 ret = do_ioctl(arg1, arg2, arg3);
8717 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008718#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00008719 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008720 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008721 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008722#endif
bellardebc05482003-09-30 21:08:41 +00008723#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008724 case TARGET_NR_mpx:
8725 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008726#endif
bellard31e31b82003-02-18 22:55:36 +00008727 case TARGET_NR_setpgid:
8728 ret = get_errno(setpgid(arg1, arg2));
8729 break;
bellardebc05482003-09-30 21:08:41 +00008730#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008731 case TARGET_NR_ulimit:
8732 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008733#endif
8734#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008735 case TARGET_NR_oldolduname:
8736 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008737#endif
bellard31e31b82003-02-18 22:55:36 +00008738 case TARGET_NR_umask:
8739 ret = get_errno(umask(arg1));
8740 break;
8741 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008742 if (!(p = lock_user_string(arg1)))
8743 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008744 ret = get_errno(chroot(p));
8745 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008746 break;
Chen Gang704eff62015-08-21 05:37:33 +08008747#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008748 case TARGET_NR_ustat:
8749 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008750#endif
8751#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008752 case TARGET_NR_dup2:
8753 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008754 if (ret >= 0) {
8755 fd_trans_dup(arg1, arg2);
8756 }
bellard31e31b82003-02-18 22:55:36 +00008757 break;
Chen Gang704eff62015-08-21 05:37:33 +08008758#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008759#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8760 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008761 {
8762 int host_flags;
8763
8764 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8765 return -EINVAL;
8766 }
8767 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8768 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008769 if (ret >= 0) {
8770 fd_trans_dup(arg1, arg2);
8771 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008772 break;
Peter Maydell10fa9932017-12-15 15:18:00 +00008773 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008774#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008775#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008776 case TARGET_NR_getppid:
8777 ret = get_errno(getppid());
8778 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008779#endif
Chen Gang704eff62015-08-21 05:37:33 +08008780#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008781 case TARGET_NR_getpgrp:
8782 ret = get_errno(getpgrp());
8783 break;
Chen Gang704eff62015-08-21 05:37:33 +08008784#endif
bellard31e31b82003-02-18 22:55:36 +00008785 case TARGET_NR_setsid:
8786 ret = get_errno(setsid());
8787 break;
thse5febef2007-04-01 18:31:35 +00008788#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008789 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008790 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008791#if defined(TARGET_ALPHA)
8792 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008793 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008794 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008795 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8796 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008797 act._sa_handler = old_act->_sa_handler;
8798 target_siginitset(&act.sa_mask, old_act->sa_mask);
8799 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008800 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008801 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008802 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008803 }
8804 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008805 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008806 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8807 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008808 old_act->_sa_handler = oact._sa_handler;
8809 old_act->sa_mask = oact.sa_mask.sig[0];
8810 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008811 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008812 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008813#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008814 struct target_sigaction act, oact, *pact, *old_act;
8815
8816 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008817 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8818 goto efault;
bellard106ec872006-06-27 21:08:10 +00008819 act._sa_handler = old_act->_sa_handler;
8820 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8821 act.sa_flags = old_act->sa_flags;
8822 unlock_user_struct(old_act, arg2, 0);
8823 pact = &act;
8824 } else {
8825 pact = NULL;
8826 }
8827
8828 ret = get_errno(do_sigaction(arg1, pact, &oact));
8829
8830 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008831 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8832 goto efault;
bellard106ec872006-06-27 21:08:10 +00008833 old_act->_sa_handler = oact._sa_handler;
8834 old_act->sa_flags = oact.sa_flags;
8835 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8836 old_act->sa_mask.sig[1] = 0;
8837 old_act->sa_mask.sig[2] = 0;
8838 old_act->sa_mask.sig[3] = 0;
8839 unlock_user_struct(old_act, arg3, 1);
8840 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008841#else
8842 struct target_old_sigaction *old_act;
8843 struct target_sigaction act, oact, *pact;
8844 if (arg2) {
8845 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8846 goto efault;
8847 act._sa_handler = old_act->_sa_handler;
8848 target_siginitset(&act.sa_mask, old_act->sa_mask);
8849 act.sa_flags = old_act->sa_flags;
8850 act.sa_restorer = old_act->sa_restorer;
Laurent Vivier5de154e2018-04-02 12:24:52 +02008851#ifdef TARGET_ARCH_HAS_KA_RESTORER
8852 act.ka_restorer = 0;
8853#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08008854 unlock_user_struct(old_act, arg2, 0);
8855 pact = &act;
8856 } else {
8857 pact = NULL;
8858 }
8859 ret = get_errno(do_sigaction(arg1, pact, &oact));
8860 if (!is_error(ret) && arg3) {
8861 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8862 goto efault;
8863 old_act->_sa_handler = oact._sa_handler;
8864 old_act->sa_mask = oact.sa_mask.sig[0];
8865 old_act->sa_flags = oact.sa_flags;
8866 old_act->sa_restorer = oact.sa_restorer;
8867 unlock_user_struct(old_act, arg3, 1);
8868 }
ths388bb212007-05-13 13:58:00 +00008869#endif
bellard31e31b82003-02-18 22:55:36 +00008870 }
8871 break;
thse5febef2007-04-01 18:31:35 +00008872#endif
bellard66fb9762003-03-23 01:06:05 +00008873 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008874 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008875#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008876 /* For Alpha and SPARC this is a 5 argument syscall, with
8877 * a 'restorer' parameter which must be copied into the
8878 * sa_restorer field of the sigaction struct.
8879 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8880 * and arg5 is the sigsetsize.
8881 * Alpha also has a separate rt_sigaction struct that it uses
8882 * here; SPARC uses the usual sigaction struct.
8883 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008884 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008885 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008886
8887 if (arg4 != sizeof(target_sigset_t)) {
8888 ret = -TARGET_EINVAL;
8889 break;
8890 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008891 if (arg2) {
8892 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8893 goto efault;
8894 act._sa_handler = rt_act->_sa_handler;
8895 act.sa_mask = rt_act->sa_mask;
8896 act.sa_flags = rt_act->sa_flags;
8897 act.sa_restorer = arg5;
8898 unlock_user_struct(rt_act, arg2, 0);
8899 pact = &act;
8900 }
8901 ret = get_errno(do_sigaction(arg1, pact, &oact));
8902 if (!is_error(ret) && arg3) {
8903 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8904 goto efault;
8905 rt_act->_sa_handler = oact._sa_handler;
8906 rt_act->sa_mask = oact.sa_mask;
8907 rt_act->sa_flags = oact.sa_flags;
8908 unlock_user_struct(rt_act, arg3, 1);
8909 }
8910#else
Peter Maydell78bfef72017-11-06 18:33:26 +00008911#ifdef TARGET_SPARC
8912 target_ulong restorer = arg4;
8913 target_ulong sigsetsize = arg5;
8914#else
8915 target_ulong sigsetsize = arg4;
8916#endif
pbrook53a59602006-03-25 19:31:22 +00008917 struct target_sigaction *act;
8918 struct target_sigaction *oact;
8919
Peter Maydell78bfef72017-11-06 18:33:26 +00008920 if (sigsetsize != sizeof(target_sigset_t)) {
Peter Maydellc8157012016-06-30 14:23:24 +01008921 ret = -TARGET_EINVAL;
8922 break;
8923 }
bellard579a97f2007-11-11 14:26:47 +00008924 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00008925 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
bellard579a97f2007-11-11 14:26:47 +00008926 goto efault;
Peter Maydell78bfef72017-11-06 18:33:26 +00008927 }
Laurent Vivier5de154e2018-04-02 12:24:52 +02008928#ifdef TARGET_ARCH_HAS_KA_RESTORER
8929 act->ka_restorer = restorer;
Peter Maydell78bfef72017-11-06 18:33:26 +00008930#endif
8931 } else {
pbrook53a59602006-03-25 19:31:22 +00008932 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00008933 }
bellard579a97f2007-11-11 14:26:47 +00008934 if (arg3) {
8935 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8936 ret = -TARGET_EFAULT;
8937 goto rt_sigaction_fail;
8938 }
8939 } else
pbrook53a59602006-03-25 19:31:22 +00008940 oact = NULL;
8941 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008942 rt_sigaction_fail:
8943 if (act)
pbrook53a59602006-03-25 19:31:22 +00008944 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008945 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008946 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008947#endif
pbrook53a59602006-03-25 19:31:22 +00008948 }
bellard66fb9762003-03-23 01:06:05 +00008949 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008950#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008951 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008952 {
8953 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008954 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008955 ret = do_sigprocmask(0, NULL, &cur_set);
8956 if (!ret) {
8957 host_to_target_old_sigset(&target_set, &cur_set);
8958 ret = target_set;
8959 }
bellard66fb9762003-03-23 01:06:05 +00008960 }
8961 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008962#endif
8963#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008964 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008965 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02008966 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00008967 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00008968 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008969 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8970 if (!ret) {
8971 host_to_target_old_sigset(&target_set, &oset);
8972 ret = target_set;
8973 }
bellard66fb9762003-03-23 01:06:05 +00008974 }
8975 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008976#endif
thse5febef2007-04-01 18:31:35 +00008977#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008978 case TARGET_NR_sigprocmask:
8979 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008980#if defined(TARGET_ALPHA)
8981 sigset_t set, oldset;
8982 abi_ulong mask;
8983 int how;
8984
8985 switch (arg1) {
8986 case TARGET_SIG_BLOCK:
8987 how = SIG_BLOCK;
8988 break;
8989 case TARGET_SIG_UNBLOCK:
8990 how = SIG_UNBLOCK;
8991 break;
8992 case TARGET_SIG_SETMASK:
8993 how = SIG_SETMASK;
8994 break;
8995 default:
8996 ret = -TARGET_EINVAL;
8997 goto fail;
8998 }
8999 mask = arg2;
9000 target_to_host_old_sigset(&set, &mask);
9001
Peter Maydell3d3efba2016-05-27 15:51:49 +01009002 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07009003 if (!is_error(ret)) {
9004 host_to_target_old_sigset(&mask, &oldset);
9005 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07009006 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07009007 }
9008#else
bellard66fb9762003-03-23 01:06:05 +00009009 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07009010 int how;
ths3b46e622007-09-17 08:09:54 +00009011
pbrook53a59602006-03-25 19:31:22 +00009012 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07009013 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00009014 case TARGET_SIG_BLOCK:
9015 how = SIG_BLOCK;
9016 break;
9017 case TARGET_SIG_UNBLOCK:
9018 how = SIG_UNBLOCK;
9019 break;
9020 case TARGET_SIG_SETMASK:
9021 how = SIG_SETMASK;
9022 break;
9023 default:
ths0da46a62007-10-20 20:23:07 +00009024 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009025 goto fail;
9026 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009027 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009028 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009029 target_to_host_old_sigset(&set, p);
9030 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009031 set_ptr = &set;
9032 } else {
9033 how = 0;
9034 set_ptr = NULL;
9035 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009036 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009037 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009038 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009039 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009040 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009041 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009042 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07009043#endif
bellard66fb9762003-03-23 01:06:05 +00009044 }
9045 break;
thse5febef2007-04-01 18:31:35 +00009046#endif
bellard66fb9762003-03-23 01:06:05 +00009047 case TARGET_NR_rt_sigprocmask:
9048 {
9049 int how = arg1;
9050 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00009051
Peter Maydellc8157012016-06-30 14:23:24 +01009052 if (arg4 != sizeof(target_sigset_t)) {
9053 ret = -TARGET_EINVAL;
9054 break;
9055 }
9056
pbrook53a59602006-03-25 19:31:22 +00009057 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009058 switch(how) {
9059 case TARGET_SIG_BLOCK:
9060 how = SIG_BLOCK;
9061 break;
9062 case TARGET_SIG_UNBLOCK:
9063 how = SIG_UNBLOCK;
9064 break;
9065 case TARGET_SIG_SETMASK:
9066 how = SIG_SETMASK;
9067 break;
9068 default:
ths0da46a62007-10-20 20:23:07 +00009069 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00009070 goto fail;
9071 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009072 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009073 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009074 target_to_host_sigset(&set, p);
9075 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00009076 set_ptr = &set;
9077 } else {
9078 how = 0;
9079 set_ptr = NULL;
9080 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01009081 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00009082 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009083 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009084 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009085 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05009086 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009087 }
9088 }
9089 break;
thse5febef2007-04-01 18:31:35 +00009090#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00009091 case TARGET_NR_sigpending:
9092 {
9093 sigset_t set;
9094 ret = get_errno(sigpending(&set));
9095 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009096 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009097 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009098 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009099 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009100 }
9101 }
9102 break;
thse5febef2007-04-01 18:31:35 +00009103#endif
bellard66fb9762003-03-23 01:06:05 +00009104 case TARGET_NR_rt_sigpending:
9105 {
9106 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01009107
9108 /* Yes, this check is >, not != like most. We follow the kernel's
9109 * logic and it does it like this because it implements
9110 * NR_sigpending through the same code path, and in that case
9111 * the old_sigset_t is smaller in size.
9112 */
9113 if (arg2 > sizeof(target_sigset_t)) {
9114 ret = -TARGET_EINVAL;
9115 break;
9116 }
9117
bellard66fb9762003-03-23 01:06:05 +00009118 ret = get_errno(sigpending(&set));
9119 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009120 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009121 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009122 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009123 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009124 }
9125 }
9126 break;
thse5febef2007-04-01 18:31:35 +00009127#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00009128 case TARGET_NR_sigsuspend:
9129 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009130 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07009131#if defined(TARGET_ALPHA)
9132 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009133 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009134#else
Anthony Liguoric227f092009-10-01 16:12:16 -05009135 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009136 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009137 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009138 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009139#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01009140 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9141 SIGSET_T_SIZE));
9142 if (ret != -TARGET_ERESTARTSYS) {
9143 ts->in_sigsuspend = 1;
9144 }
bellard66fb9762003-03-23 01:06:05 +00009145 }
9146 break;
thse5febef2007-04-01 18:31:35 +00009147#endif
bellard66fb9762003-03-23 01:06:05 +00009148 case TARGET_NR_rt_sigsuspend:
9149 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009150 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01009151
9152 if (arg2 != sizeof(target_sigset_t)) {
9153 ret = -TARGET_EINVAL;
9154 break;
9155 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009156 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009157 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009158 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009159 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009160 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9161 SIGSET_T_SIZE));
9162 if (ret != -TARGET_ERESTARTSYS) {
9163 ts->in_sigsuspend = 1;
9164 }
bellard66fb9762003-03-23 01:06:05 +00009165 }
9166 break;
9167 case TARGET_NR_rt_sigtimedwait:
9168 {
bellard66fb9762003-03-23 01:06:05 +00009169 sigset_t set;
9170 struct timespec uts, *puts;
9171 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00009172
Peter Maydellc8157012016-06-30 14:23:24 +01009173 if (arg4 != sizeof(target_sigset_t)) {
9174 ret = -TARGET_EINVAL;
9175 break;
9176 }
9177
Anthony Liguoric227f092009-10-01 16:12:16 -05009178 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009179 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009180 target_to_host_sigset(&set, p);
9181 unlock_user(p, arg1, 0);
9182 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00009183 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00009184 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00009185 } else {
9186 puts = NULL;
9187 }
Peter Maydellb3f82332016-06-06 19:58:08 +01009188 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9189 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01009190 if (!is_error(ret)) {
9191 if (arg2) {
9192 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
9193 0);
9194 if (!p) {
9195 goto efault;
9196 }
9197 host_to_target_siginfo(p, &uinfo);
9198 unlock_user(p, arg2, sizeof(target_siginfo_t));
9199 }
9200 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00009201 }
9202 }
9203 break;
9204 case TARGET_NR_rt_sigqueueinfo:
9205 {
9206 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009207
9208 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9209 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00009210 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01009211 }
pbrook53a59602006-03-25 19:31:22 +00009212 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009213 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009214 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9215 }
9216 break;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009217 case TARGET_NR_rt_tgsigqueueinfo:
9218 {
9219 siginfo_t uinfo;
9220
9221 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9222 if (!p) {
9223 goto efault;
9224 }
9225 target_to_host_siginfo(&uinfo, p);
9226 unlock_user(p, arg4, 0);
9227 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9228 }
9229 break;
thse5febef2007-04-01 18:31:35 +00009230#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009231 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009232 if (block_signals()) {
9233 ret = -TARGET_ERESTARTSYS;
9234 } else {
9235 ret = do_sigreturn(cpu_env);
9236 }
bellard66fb9762003-03-23 01:06:05 +00009237 break;
thse5febef2007-04-01 18:31:35 +00009238#endif
bellard66fb9762003-03-23 01:06:05 +00009239 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009240 if (block_signals()) {
9241 ret = -TARGET_ERESTARTSYS;
9242 } else {
9243 ret = do_rt_sigreturn(cpu_env);
9244 }
bellard66fb9762003-03-23 01:06:05 +00009245 break;
bellard31e31b82003-02-18 22:55:36 +00009246 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009247 if (!(p = lock_user_string(arg1)))
9248 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009249 ret = get_errno(sethostname(p, arg2));
9250 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009251 break;
9252 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009253 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009254 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009255 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009256 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009257 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
9258 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009259 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9260 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009261 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00009262 ret = get_errno(setrlimit(resource, &rlim));
9263 }
9264 break;
bellard31e31b82003-02-18 22:55:36 +00009265 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009266 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009267 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009268 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009269 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009270
bellard9de5e442003-03-23 16:49:39 +00009271 ret = get_errno(getrlimit(resource, &rlim));
9272 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009273 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9274 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009275 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9276 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009277 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009278 }
9279 }
9280 break;
bellard31e31b82003-02-18 22:55:36 +00009281 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009282 {
9283 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009284 ret = get_errno(getrusage(arg1, &rusage));
9285 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009286 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009287 }
9288 }
9289 break;
bellard31e31b82003-02-18 22:55:36 +00009290 case TARGET_NR_gettimeofday:
9291 {
bellard31e31b82003-02-18 22:55:36 +00009292 struct timeval tv;
9293 ret = get_errno(gettimeofday(&tv, NULL));
9294 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00009295 if (copy_to_user_timeval(arg1, &tv))
9296 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009297 }
9298 }
9299 break;
9300 case TARGET_NR_settimeofday:
9301 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009302 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009303 struct timezone tz, *ptz = NULL;
9304
Paul Burtonb67d8032014-06-22 11:25:41 +01009305 if (arg1) {
9306 if (copy_from_user_timeval(&tv, arg1)) {
9307 goto efault;
9308 }
9309 ptv = &tv;
9310 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009311
9312 if (arg2) {
9313 if (copy_from_user_timezone(&tz, arg2)) {
9314 goto efault;
9315 }
9316 ptz = &tz;
9317 }
9318
Paul Burtonb67d8032014-06-22 11:25:41 +01009319 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009320 }
9321 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009322#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009323 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009324#if defined(TARGET_WANT_NI_OLD_SELECT)
9325 /* some architectures used to have old_select here
9326 * but now ENOSYS it.
9327 */
9328 ret = -TARGET_ENOSYS;
9329#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9330 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009331#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009332 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009333#endif
bellardf2674e32003-07-09 12:26:09 +00009334 break;
bellard048f6b42005-11-26 18:47:20 +00009335#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009336#ifdef TARGET_NR_pselect6
9337 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04009338 {
9339 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
9340 fd_set rfds, wfds, efds;
9341 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
9342 struct timespec ts, *ts_ptr;
9343
9344 /*
9345 * The 6th arg is actually two args smashed together,
9346 * so we cannot use the C library.
9347 */
9348 sigset_t set;
9349 struct {
9350 sigset_t *set;
9351 size_t size;
9352 } sig, *sig_ptr;
9353
9354 abi_ulong arg_sigset, arg_sigsize, *arg7;
9355 target_sigset_t *target_sigset;
9356
9357 n = arg1;
9358 rfd_addr = arg2;
9359 wfd_addr = arg3;
9360 efd_addr = arg4;
9361 ts_addr = arg5;
9362
9363 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9364 if (ret) {
9365 goto fail;
9366 }
9367 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9368 if (ret) {
9369 goto fail;
9370 }
9371 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9372 if (ret) {
9373 goto fail;
9374 }
9375
9376 /*
9377 * This takes a timespec, and not a timeval, so we cannot
9378 * use the do_select() helper ...
9379 */
9380 if (ts_addr) {
9381 if (target_to_host_timespec(&ts, ts_addr)) {
9382 goto efault;
9383 }
9384 ts_ptr = &ts;
9385 } else {
9386 ts_ptr = NULL;
9387 }
9388
9389 /* Extract the two packed args for the sigset */
9390 if (arg6) {
9391 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009392 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009393
9394 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9395 if (!arg7) {
9396 goto efault;
9397 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009398 arg_sigset = tswapal(arg7[0]);
9399 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009400 unlock_user(arg7, arg6, 0);
9401
9402 if (arg_sigset) {
9403 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009404 if (arg_sigsize != sizeof(*target_sigset)) {
9405 /* Like the kernel, we enforce correct size sigsets */
9406 ret = -TARGET_EINVAL;
9407 goto fail;
9408 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009409 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9410 sizeof(*target_sigset), 1);
9411 if (!target_sigset) {
9412 goto efault;
9413 }
9414 target_to_host_sigset(&set, target_sigset);
9415 unlock_user(target_sigset, arg_sigset, 0);
9416 } else {
9417 sig.set = NULL;
9418 }
9419 } else {
9420 sig_ptr = NULL;
9421 }
9422
Peter Maydell6df9d382016-05-12 18:47:51 +01009423 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9424 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009425
9426 if (!is_error(ret)) {
9427 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9428 goto efault;
9429 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9430 goto efault;
9431 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9432 goto efault;
9433
9434 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9435 goto efault;
9436 }
9437 }
9438 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009439#endif
Chen Gang704eff62015-08-21 05:37:33 +08009440#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009441 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009442 {
9443 void *p2;
9444 p = lock_user_string(arg1);
9445 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009446 if (!p || !p2)
9447 ret = -TARGET_EFAULT;
9448 else
9449 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009450 unlock_user(p2, arg2, 0);
9451 unlock_user(p, arg1, 0);
9452 }
bellard31e31b82003-02-18 22:55:36 +00009453 break;
Chen Gang704eff62015-08-21 05:37:33 +08009454#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009455#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009456 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009457 {
bellard579a97f2007-11-11 14:26:47 +00009458 void *p2;
thsf0b62432007-09-24 09:25:40 +00009459 p = lock_user_string(arg1);
9460 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009461 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009462 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009463 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009464 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009465 unlock_user(p2, arg3, 0);
9466 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009467 }
9468 break;
9469#endif
bellardebc05482003-09-30 21:08:41 +00009470#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009471 case TARGET_NR_oldlstat:
9472 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009473#endif
Chen Gang704eff62015-08-21 05:37:33 +08009474#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009475 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009476 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009477 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009478 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009479 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009480 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009481 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009482 } else if (!arg3) {
9483 /* Short circuit this for the magic exe check. */
9484 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009485 } else if (is_proc_myself((const char *)p, "exe")) {
9486 char real[PATH_MAX], *temp;
9487 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009488 /* Return value is # of bytes that we wrote to the buffer. */
9489 if (temp == NULL) {
9490 ret = get_errno(-1);
9491 } else {
9492 /* Don't worry about sign mismatch as earlier mapping
9493 * logic would have thrown a bad address error. */
9494 ret = MIN(strlen(real), arg3);
9495 /* We cannot NUL terminate the string. */
9496 memcpy(p2, real, ret);
9497 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009498 } else {
9499 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009500 }
pbrook53a59602006-03-25 19:31:22 +00009501 unlock_user(p2, arg2, ret);
9502 unlock_user(p, arg1, 0);
9503 }
bellard31e31b82003-02-18 22:55:36 +00009504 break;
Chen Gang704eff62015-08-21 05:37:33 +08009505#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009506#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009507 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009508 {
bellard579a97f2007-11-11 14:26:47 +00009509 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009510 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009511 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009512 if (!p || !p2) {
9513 ret = -TARGET_EFAULT;
9514 } else if (is_proc_myself((const char *)p, "exe")) {
9515 char real[PATH_MAX], *temp;
9516 temp = realpath(exec_path, real);
9517 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9518 snprintf((char *)p2, arg4, "%s", real);
9519 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009520 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009521 }
bellard579a97f2007-11-11 14:26:47 +00009522 unlock_user(p2, arg3, ret);
9523 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009524 }
9525 break;
9526#endif
thse5febef2007-04-01 18:31:35 +00009527#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009528 case TARGET_NR_uselib:
9529 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009530#endif
9531#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009532 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009533 if (!(p = lock_user_string(arg1)))
9534 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009535 ret = get_errno(swapon(p, arg2));
9536 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009537 break;
thse5febef2007-04-01 18:31:35 +00009538#endif
bellard31e31b82003-02-18 22:55:36 +00009539 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009540 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9541 /* arg4 must be ignored in all other cases */
9542 p = lock_user_string(arg4);
9543 if (!p) {
9544 goto efault;
9545 }
9546 ret = get_errno(reboot(arg1, arg2, arg3, p));
9547 unlock_user(p, arg4, 0);
9548 } else {
9549 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9550 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009551 break;
thse5febef2007-04-01 18:31:35 +00009552#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009553 case TARGET_NR_readdir:
9554 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009555#endif
9556#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009557 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009558#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9559 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009560 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9561 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009562 {
blueswir1992f48a2007-10-14 16:27:31 +00009563 abi_ulong *v;
9564 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009565 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9566 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009567 v1 = tswapal(v[0]);
9568 v2 = tswapal(v[1]);
9569 v3 = tswapal(v[2]);
9570 v4 = tswapal(v[3]);
9571 v5 = tswapal(v[4]);
9572 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009573 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009574 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009575 target_to_host_bitmask(v4, mmap_flags_tbl),
9576 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009577 }
bellard31e31b82003-02-18 22:55:36 +00009578#else
ths5fafdf22007-09-16 21:08:06 +00009579 ret = get_errno(target_mmap(arg1, arg2, arg3,
9580 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009581 arg5,
9582 arg6));
bellard31e31b82003-02-18 22:55:36 +00009583#endif
bellard6fb883e2003-07-09 17:12:39 +00009584 break;
thse5febef2007-04-01 18:31:35 +00009585#endif
bellarda315a142005-01-30 22:59:18 +00009586#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009587 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009588#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009589#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009590#endif
ths5fafdf22007-09-16 21:08:06 +00009591 ret = get_errno(target_mmap(arg1, arg2, arg3,
9592 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009593 arg5,
bellardc573ff62004-01-04 15:51:36 +00009594 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009595 break;
bellarda315a142005-01-30 22:59:18 +00009596#endif
bellard31e31b82003-02-18 22:55:36 +00009597 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009598 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009599 break;
bellard9de5e442003-03-23 16:49:39 +00009600 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009601 {
Andreas Färber0429a972013-08-26 18:14:44 +02009602 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009603 /* Special hack to detect libc making the stack executable. */
9604 if ((arg3 & PROT_GROWSDOWN)
9605 && arg1 >= ts->info->stack_limit
9606 && arg1 <= ts->info->start_stack) {
9607 arg3 &= ~PROT_GROWSDOWN;
9608 arg2 = arg2 + arg1 - ts->info->stack_limit;
9609 arg1 = ts->info->stack_limit;
9610 }
9611 }
bellard54936002003-05-13 00:25:15 +00009612 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009613 break;
thse5febef2007-04-01 18:31:35 +00009614#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009615 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009616 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009617 break;
thse5febef2007-04-01 18:31:35 +00009618#endif
pbrook53a59602006-03-25 19:31:22 +00009619 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009620#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009621 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009622 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009623 break;
thse5febef2007-04-01 18:31:35 +00009624#endif
9625#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009626 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009627 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009628 break;
thse5febef2007-04-01 18:31:35 +00009629#endif
9630#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009631 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009632 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009633 break;
thse5febef2007-04-01 18:31:35 +00009634#endif
9635#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009636 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009637 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009638 break;
thse5febef2007-04-01 18:31:35 +00009639#endif
9640#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009641 case TARGET_NR_munlockall:
9642 ret = get_errno(munlockall());
9643 break;
thse5febef2007-04-01 18:31:35 +00009644#endif
bellard31e31b82003-02-18 22:55:36 +00009645 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009646 if (!(p = lock_user_string(arg1)))
9647 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009648 ret = get_errno(truncate(p, arg2));
9649 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009650 break;
9651 case TARGET_NR_ftruncate:
9652 ret = get_errno(ftruncate(arg1, arg2));
9653 break;
9654 case TARGET_NR_fchmod:
9655 ret = get_errno(fchmod(arg1, arg2));
9656 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009657#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009658 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009659 if (!(p = lock_user_string(arg2)))
9660 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009661 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009662 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009663 break;
9664#endif
bellard31e31b82003-02-18 22:55:36 +00009665 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009666 /* Note that negative values are valid for getpriority, so we must
9667 differentiate based on errno settings. */
9668 errno = 0;
9669 ret = getpriority(arg1, arg2);
9670 if (ret == -1 && errno != 0) {
9671 ret = -host_to_target_errno(errno);
9672 break;
9673 }
9674#ifdef TARGET_ALPHA
9675 /* Return value is the unbiased priority. Signal no error. */
9676 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9677#else
9678 /* Return value is a biased priority to avoid negative numbers. */
9679 ret = 20 - ret;
9680#endif
bellard31e31b82003-02-18 22:55:36 +00009681 break;
9682 case TARGET_NR_setpriority:
9683 ret = get_errno(setpriority(arg1, arg2, arg3));
9684 break;
bellardebc05482003-09-30 21:08:41 +00009685#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009686 case TARGET_NR_profil:
9687 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009688#endif
bellard31e31b82003-02-18 22:55:36 +00009689 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009690 if (!(p = lock_user_string(arg1)))
9691 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009692 ret = get_errno(statfs(path(p), &stfs));
9693 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009694 convert_statfs:
9695 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009696 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009697
bellard579a97f2007-11-11 14:26:47 +00009698 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9699 goto efault;
9700 __put_user(stfs.f_type, &target_stfs->f_type);
9701 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9702 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9703 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9704 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9705 __put_user(stfs.f_files, &target_stfs->f_files);
9706 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9707 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9708 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9709 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009710 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05009711#ifdef _STATFS_F_FLAGS
9712 __put_user(stfs.f_flags, &target_stfs->f_flags);
9713#else
9714 __put_user(0, &target_stfs->f_flags);
9715#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009716 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009717 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009718 }
9719 break;
9720 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009721 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009722 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009723#ifdef TARGET_NR_statfs64
9724 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009725 if (!(p = lock_user_string(arg1)))
9726 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009727 ret = get_errno(statfs(path(p), &stfs));
9728 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009729 convert_statfs64:
9730 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009731 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009732
bellard579a97f2007-11-11 14:26:47 +00009733 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9734 goto efault;
9735 __put_user(stfs.f_type, &target_stfs->f_type);
9736 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9737 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9738 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9739 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9740 __put_user(stfs.f_files, &target_stfs->f_files);
9741 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9742 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9743 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9744 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009745 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9746 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009747 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009748 }
9749 break;
9750 case TARGET_NR_fstatfs64:
9751 ret = get_errno(fstatfs(arg1, &stfs));
9752 goto convert_statfs64;
9753#endif
bellardebc05482003-09-30 21:08:41 +00009754#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009755 case TARGET_NR_ioperm:
9756 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009757#endif
thse5febef2007-04-01 18:31:35 +00009758#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009759 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009760 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009761 break;
thse5febef2007-04-01 18:31:35 +00009762#endif
bellard3532fa72006-06-24 15:06:03 +00009763#ifdef TARGET_NR_accept
9764 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009765 ret = do_accept4(arg1, arg2, arg3, 0);
9766 break;
9767#endif
9768#ifdef TARGET_NR_accept4
9769 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009770 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009771 break;
9772#endif
9773#ifdef TARGET_NR_bind
9774 case TARGET_NR_bind:
9775 ret = do_bind(arg1, arg2, arg3);
9776 break;
9777#endif
9778#ifdef TARGET_NR_connect
9779 case TARGET_NR_connect:
9780 ret = do_connect(arg1, arg2, arg3);
9781 break;
9782#endif
9783#ifdef TARGET_NR_getpeername
9784 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009785 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009786 break;
9787#endif
9788#ifdef TARGET_NR_getsockname
9789 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009790 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009791 break;
9792#endif
9793#ifdef TARGET_NR_getsockopt
9794 case TARGET_NR_getsockopt:
9795 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9796 break;
9797#endif
9798#ifdef TARGET_NR_listen
9799 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009800 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009801 break;
9802#endif
9803#ifdef TARGET_NR_recv
9804 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009805 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009806 break;
9807#endif
9808#ifdef TARGET_NR_recvfrom
9809 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009810 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009811 break;
9812#endif
9813#ifdef TARGET_NR_recvmsg
9814 case TARGET_NR_recvmsg:
9815 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9816 break;
9817#endif
9818#ifdef TARGET_NR_send
9819 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009820 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009821 break;
9822#endif
9823#ifdef TARGET_NR_sendmsg
9824 case TARGET_NR_sendmsg:
9825 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9826 break;
9827#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009828#ifdef TARGET_NR_sendmmsg
9829 case TARGET_NR_sendmmsg:
9830 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9831 break;
9832 case TARGET_NR_recvmmsg:
9833 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9834 break;
9835#endif
bellard3532fa72006-06-24 15:06:03 +00009836#ifdef TARGET_NR_sendto
9837 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009838 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009839 break;
9840#endif
9841#ifdef TARGET_NR_shutdown
9842 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009843 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009844 break;
9845#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009846#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9847 case TARGET_NR_getrandom:
9848 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9849 if (!p) {
9850 goto efault;
9851 }
9852 ret = get_errno(getrandom(p, arg2, arg3));
9853 unlock_user(p, arg1, ret);
9854 break;
9855#endif
bellard3532fa72006-06-24 15:06:03 +00009856#ifdef TARGET_NR_socket
9857 case TARGET_NR_socket:
9858 ret = do_socket(arg1, arg2, arg3);
9859 break;
9860#endif
9861#ifdef TARGET_NR_socketpair
9862 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009863 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009864 break;
9865#endif
9866#ifdef TARGET_NR_setsockopt
9867 case TARGET_NR_setsockopt:
9868 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9869 break;
9870#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009871#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009872 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009873 {
9874 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009875
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009876 switch (arg1) {
9877 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9878 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9879 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9880 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9881 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9882 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9883 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9884 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9885 {
9886 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9887 }
9888 break;
9889 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9890 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9891 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9892 {
9893 ret = -TARGET_EINVAL;
9894 if (len < 0) {
9895 goto fail;
9896 }
9897 ret = 0;
9898 if (len == 0) {
9899 break;
9900 }
9901 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9902 if (!p) {
9903 ret = -TARGET_EFAULT;
9904 goto fail;
9905 }
9906 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9907 unlock_user(p, arg2, arg3);
9908 }
9909 break;
9910 default:
9911 ret = -EINVAL;
9912 break;
9913 }
9914 }
9915 break;
9916#endif
bellard31e31b82003-02-18 22:55:36 +00009917 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009918 {
bellard66fb9762003-03-23 01:06:05 +00009919 struct itimerval value, ovalue, *pvalue;
9920
pbrook53a59602006-03-25 19:31:22 +00009921 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009922 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009923 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9924 || copy_from_user_timeval(&pvalue->it_value,
9925 arg2 + sizeof(struct target_timeval)))
9926 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009927 } else {
9928 pvalue = NULL;
9929 }
9930 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009931 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009932 if (copy_to_user_timeval(arg3,
9933 &ovalue.it_interval)
9934 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9935 &ovalue.it_value))
9936 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009937 }
9938 }
9939 break;
bellard31e31b82003-02-18 22:55:36 +00009940 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009941 {
bellard66fb9762003-03-23 01:06:05 +00009942 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009943
bellard66fb9762003-03-23 01:06:05 +00009944 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009945 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009946 if (copy_to_user_timeval(arg2,
9947 &value.it_interval)
9948 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9949 &value.it_value))
9950 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009951 }
9952 }
9953 break;
Chen Gang704eff62015-08-21 05:37:33 +08009954#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009955 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009956 if (!(p = lock_user_string(arg1)))
9957 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009958 ret = get_errno(stat(path(p), &st));
9959 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009960 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009961#endif
9962#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009963 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009964 if (!(p = lock_user_string(arg1)))
9965 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009966 ret = get_errno(lstat(path(p), &st));
9967 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009968 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009969#endif
bellard31e31b82003-02-18 22:55:36 +00009970 case TARGET_NR_fstat:
9971 {
9972 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009973#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009974 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009975#endif
bellard31e31b82003-02-18 22:55:36 +00009976 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009977 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009978
bellard579a97f2007-11-11 14:26:47 +00009979 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9980 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009981 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009982 __put_user(st.st_dev, &target_st->st_dev);
9983 __put_user(st.st_ino, &target_st->st_ino);
9984 __put_user(st.st_mode, &target_st->st_mode);
9985 __put_user(st.st_uid, &target_st->st_uid);
9986 __put_user(st.st_gid, &target_st->st_gid);
9987 __put_user(st.st_nlink, &target_st->st_nlink);
9988 __put_user(st.st_rdev, &target_st->st_rdev);
9989 __put_user(st.st_size, &target_st->st_size);
9990 __put_user(st.st_blksize, &target_st->st_blksize);
9991 __put_user(st.st_blocks, &target_st->st_blocks);
9992 __put_user(st.st_atime, &target_st->target_st_atime);
9993 __put_user(st.st_mtime, &target_st->target_st_mtime);
9994 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009995 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009996 }
9997 }
9998 break;
bellardebc05482003-09-30 21:08:41 +00009999#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +000010000 case TARGET_NR_olduname:
10001 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010002#endif
10003#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +000010004 case TARGET_NR_iopl:
10005 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010006#endif
bellard31e31b82003-02-18 22:55:36 +000010007 case TARGET_NR_vhangup:
10008 ret = get_errno(vhangup());
10009 break;
bellardebc05482003-09-30 21:08:41 +000010010#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +000010011 case TARGET_NR_idle:
10012 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010013#endif
bellard42ad6ae2005-01-03 22:48:11 +000010014#ifdef TARGET_NR_syscall
10015 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +010010016 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
10017 arg6, arg7, arg8, 0);
10018 break;
bellard42ad6ae2005-01-03 22:48:11 +000010019#endif
bellard31e31b82003-02-18 22:55:36 +000010020 case TARGET_NR_wait4:
10021 {
10022 int status;
blueswir1992f48a2007-10-14 16:27:31 +000010023 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +000010024 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +000010025 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +020010026 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +000010027 if (target_rusage)
10028 rusage_ptr = &rusage;
10029 else
10030 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +010010031 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +000010032 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +010010033 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +000010034 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +000010035 if (put_user_s32(status, status_ptr))
10036 goto efault;
bellard31e31b82003-02-18 22:55:36 +000010037 }
Petar Jovanovica39fb272014-04-08 19:24:30 +020010038 if (target_rusage) {
10039 rusage_err = host_to_target_rusage(target_rusage, &rusage);
10040 if (rusage_err) {
10041 ret = rusage_err;
10042 }
10043 }
bellard31e31b82003-02-18 22:55:36 +000010044 }
10045 }
10046 break;
thse5febef2007-04-01 18:31:35 +000010047#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +000010048 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +000010049 if (!(p = lock_user_string(arg1)))
10050 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010051 ret = get_errno(swapoff(p));
10052 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010053 break;
thse5febef2007-04-01 18:31:35 +000010054#endif
bellard31e31b82003-02-18 22:55:36 +000010055 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +000010056 {
pbrook53a59602006-03-25 19:31:22 +000010057 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +000010058 struct sysinfo value;
10059 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +000010060 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +000010061 {
bellard579a97f2007-11-11 14:26:47 +000010062 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
10063 goto efault;
bellarda5448a72004-06-19 16:59:03 +000010064 __put_user(value.uptime, &target_value->uptime);
10065 __put_user(value.loads[0], &target_value->loads[0]);
10066 __put_user(value.loads[1], &target_value->loads[1]);
10067 __put_user(value.loads[2], &target_value->loads[2]);
10068 __put_user(value.totalram, &target_value->totalram);
10069 __put_user(value.freeram, &target_value->freeram);
10070 __put_user(value.sharedram, &target_value->sharedram);
10071 __put_user(value.bufferram, &target_value->bufferram);
10072 __put_user(value.totalswap, &target_value->totalswap);
10073 __put_user(value.freeswap, &target_value->freeswap);
10074 __put_user(value.procs, &target_value->procs);
10075 __put_user(value.totalhigh, &target_value->totalhigh);
10076 __put_user(value.freehigh, &target_value->freehigh);
10077 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +000010078 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +000010079 }
10080 }
10081 break;
thse5febef2007-04-01 18:31:35 +000010082#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +000010083 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +010010084 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
10085 break;
thse5febef2007-04-01 18:31:35 +000010086#endif
aurel32e5289082009-04-18 16:16:12 +000010087#ifdef TARGET_NR_semget
10088 case TARGET_NR_semget:
10089 ret = get_errno(semget(arg1, arg2, arg3));
10090 break;
10091#endif
10092#ifdef TARGET_NR_semop
10093 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +000010094 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +000010095 break;
10096#endif
10097#ifdef TARGET_NR_semctl
10098 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +010010099 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +000010100 break;
10101#endif
aurel32eeb438c2008-10-13 21:08:55 +000010102#ifdef TARGET_NR_msgctl
10103 case TARGET_NR_msgctl:
10104 ret = do_msgctl(arg1, arg2, arg3);
10105 break;
10106#endif
10107#ifdef TARGET_NR_msgget
10108 case TARGET_NR_msgget:
10109 ret = get_errno(msgget(arg1, arg2));
10110 break;
10111#endif
10112#ifdef TARGET_NR_msgrcv
10113 case TARGET_NR_msgrcv:
10114 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
10115 break;
10116#endif
10117#ifdef TARGET_NR_msgsnd
10118 case TARGET_NR_msgsnd:
10119 ret = do_msgsnd(arg1, arg2, arg3, arg4);
10120 break;
10121#endif
Riku Voipio88a8c982009-04-03 10:42:00 +030010122#ifdef TARGET_NR_shmget
10123 case TARGET_NR_shmget:
10124 ret = get_errno(shmget(arg1, arg2, arg3));
10125 break;
10126#endif
10127#ifdef TARGET_NR_shmctl
10128 case TARGET_NR_shmctl:
10129 ret = do_shmctl(arg1, arg2, arg3);
10130 break;
10131#endif
10132#ifdef TARGET_NR_shmat
10133 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +010010134 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030010135 break;
10136#endif
10137#ifdef TARGET_NR_shmdt
10138 case TARGET_NR_shmdt:
10139 ret = do_shmdt(arg1);
10140 break;
10141#endif
bellard31e31b82003-02-18 22:55:36 +000010142 case TARGET_NR_fsync:
10143 ret = get_errno(fsync(arg1));
10144 break;
bellard31e31b82003-02-18 22:55:36 +000010145 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +010010146 /* Linux manages to have three different orderings for its
10147 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
10148 * match the kernel's CONFIG_CLONE_* settings.
10149 * Microblaze is further special in that it uses a sixth
10150 * implicit argument to clone for the TLS pointer.
10151 */
10152#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020010153 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010010154#elif defined(TARGET_CLONE_BACKWARDS)
10155 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
10156#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010157 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010158#else
Peter Maydell4ce62432013-07-16 18:44:57 +010010159 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010160#endif
bellard1b6b0292003-03-22 17:31:38 +000010161 break;
bellardec86b0f2003-04-11 00:15:04 +000010162#ifdef __NR_exit_group
10163 /* new thread calls */
10164 case TARGET_NR_exit_group:
Alex Bennée708b6a62018-06-22 17:09:10 +010010165 preexit_cleanup(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +000010166 ret = get_errno(exit_group(arg1));
10167 break;
10168#endif
bellard31e31b82003-02-18 22:55:36 +000010169 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000010170 if (!(p = lock_user_string(arg1)))
10171 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010172 ret = get_errno(setdomainname(p, arg2));
10173 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010174 break;
10175 case TARGET_NR_uname:
10176 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000010177 {
10178 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000010179
bellard579a97f2007-11-11 14:26:47 +000010180 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
10181 goto efault;
bellard29e619b2004-09-13 21:41:04 +000010182 ret = get_errno(sys_uname(buf));
10183 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010010184 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000010185 emulated. */
Philippe Mathieu-Daudé871f95c2017-07-24 15:27:47 -030010186 g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
10187 sizeof(buf->machine));
pbrookc5937222006-05-14 11:30:38 +000010188 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010010189 if (qemu_uname_release && *qemu_uname_release) {
10190 g_strlcpy(buf->release, qemu_uname_release,
10191 sizeof(buf->release));
10192 }
bellard29e619b2004-09-13 21:41:04 +000010193 }
pbrook53a59602006-03-25 19:31:22 +000010194 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000010195 }
bellard31e31b82003-02-18 22:55:36 +000010196 break;
bellard6dbad632003-03-16 18:05:05 +000010197#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000010198 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +000010199 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +000010200 break;
j_mayer84409dd2007-04-06 08:56:50 +000010201#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000010202 case TARGET_NR_vm86old:
10203 goto unimplemented;
10204 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +000010205 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000010206 break;
10207#endif
j_mayer84409dd2007-04-06 08:56:50 +000010208#endif
bellard31e31b82003-02-18 22:55:36 +000010209 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010210 {
10211 struct timex host_buf;
10212
10213 if (target_to_host_timex(&host_buf, arg1) != 0) {
10214 goto efault;
10215 }
10216 ret = get_errno(adjtimex(&host_buf));
10217 if (!is_error(ret)) {
10218 if (host_to_target_timex(arg1, &host_buf) != 0) {
10219 goto efault;
10220 }
10221 }
10222 }
10223 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010224#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10225 case TARGET_NR_clock_adjtime:
10226 {
10227 struct timex htx, *phtx = &htx;
10228
10229 if (target_to_host_timex(phtx, arg2) != 0) {
10230 goto efault;
10231 }
10232 ret = get_errno(clock_adjtime(arg1, phtx));
10233 if (!is_error(ret) && phtx) {
10234 if (host_to_target_timex(arg2, phtx) != 0) {
10235 goto efault;
10236 }
10237 }
10238 }
10239 break;
10240#endif
thse5febef2007-04-01 18:31:35 +000010241#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +000010242 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +000010243#endif
bellard31e31b82003-02-18 22:55:36 +000010244 case TARGET_NR_init_module:
10245 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +000010246#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +000010247 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +000010248#endif
bellard31e31b82003-02-18 22:55:36 +000010249 goto unimplemented;
10250 case TARGET_NR_quotactl:
10251 goto unimplemented;
10252 case TARGET_NR_getpgid:
10253 ret = get_errno(getpgid(arg1));
10254 break;
10255 case TARGET_NR_fchdir:
10256 ret = get_errno(fchdir(arg1));
10257 break;
j_mayer84409dd2007-04-06 08:56:50 +000010258#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +000010259 case TARGET_NR_bdflush:
10260 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +000010261#endif
thse5febef2007-04-01 18:31:35 +000010262#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +000010263 case TARGET_NR_sysfs:
10264 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010265#endif
bellard31e31b82003-02-18 22:55:36 +000010266 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +000010267 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +000010268 break;
thse5febef2007-04-01 18:31:35 +000010269#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +000010270 case TARGET_NR_afs_syscall:
10271 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010272#endif
j_mayer7a3148a2007-04-05 07:13:51 +000010273#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010274 case TARGET_NR__llseek:
10275 {
10276 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010277#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010278 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010279 if (res == -1) {
10280 ret = get_errno(res);
10281 } else {
10282 ret = 0;
10283 }
10284#else
bellard31e31b82003-02-18 22:55:36 +000010285 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010286#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010287 if ((ret == 0) && put_user_s64(res, arg4)) {
10288 goto efault;
10289 }
bellard31e31b82003-02-18 22:55:36 +000010290 }
10291 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010292#endif
Chen Gang704eff62015-08-21 05:37:33 +080010293#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010294 case TARGET_NR_getdents:
Peter Maydell2b3f64c2018-04-19 13:57:40 +010010295#ifdef EMULATE_GETDENTS_WITH_GETDENTS
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010296#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010297 {
pbrook53a59602006-03-25 19:31:22 +000010298 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010299 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010300 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010301
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010302 dirp = g_try_malloc(count);
10303 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +000010304 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010305 goto fail;
10306 }
ths3b46e622007-09-17 08:09:54 +000010307
bellard4add45b2003-06-05 01:52:59 +000010308 ret = get_errno(sys_getdents(arg1, dirp, count));
10309 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010310 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010311 struct target_dirent *tde;
10312 int len = ret;
10313 int reclen, treclen;
10314 int count1, tnamelen;
10315
10316 count1 = 0;
10317 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010318 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10319 goto efault;
bellard4add45b2003-06-05 01:52:59 +000010320 tde = target_dirp;
10321 while (len > 0) {
10322 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010323 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10324 assert(tnamelen >= 0);
10325 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10326 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010327 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010328 tde->d_ino = tswapal(de->d_ino);
10329 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010330 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010331 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010332 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010333 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010334 count1 += treclen;
10335 }
10336 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010337 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010338 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010339 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010340 }
10341#else
bellard31e31b82003-02-18 22:55:36 +000010342 {
aurel326556a832008-10-13 21:08:17 +000010343 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010344 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010345
bellard579a97f2007-11-11 14:26:47 +000010346 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10347 goto efault;
bellard72f03902003-02-18 23:33:18 +000010348 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010349 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010350 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010351 int len = ret;
10352 int reclen;
10353 de = dirp;
10354 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010355 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010356 if (reclen > len)
10357 break;
bellard8083a3e2003-03-24 23:12:16 +000010358 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010359 tswapls(&de->d_ino);
10360 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010361 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010362 len -= reclen;
10363 }
10364 }
pbrook53a59602006-03-25 19:31:22 +000010365 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010366 }
bellard4add45b2003-06-05 01:52:59 +000010367#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010368#else
10369 /* Implement getdents in terms of getdents64 */
10370 {
10371 struct linux_dirent64 *dirp;
10372 abi_long count = arg3;
10373
10374 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10375 if (!dirp) {
10376 goto efault;
10377 }
10378 ret = get_errno(sys_getdents64(arg1, dirp, count));
10379 if (!is_error(ret)) {
10380 /* Convert the dirent64 structs to target dirent. We do this
10381 * in-place, since we can guarantee that a target_dirent is no
10382 * larger than a dirent64; however this means we have to be
10383 * careful to read everything before writing in the new format.
10384 */
10385 struct linux_dirent64 *de;
10386 struct target_dirent *tde;
10387 int len = ret;
10388 int tlen = 0;
10389
10390 de = dirp;
10391 tde = (struct target_dirent *)dirp;
10392 while (len > 0) {
10393 int namelen, treclen;
10394 int reclen = de->d_reclen;
10395 uint64_t ino = de->d_ino;
10396 int64_t off = de->d_off;
10397 uint8_t type = de->d_type;
10398
10399 namelen = strlen(de->d_name);
10400 treclen = offsetof(struct target_dirent, d_name)
10401 + namelen + 2;
10402 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10403
10404 memmove(tde->d_name, de->d_name, namelen + 1);
10405 tde->d_ino = tswapal(ino);
10406 tde->d_off = tswapal(off);
10407 tde->d_reclen = tswap16(treclen);
10408 /* The target_dirent type is in what was formerly a padding
10409 * byte at the end of the structure:
10410 */
10411 *(((char *)tde) + treclen - 1) = type;
10412
10413 de = (struct linux_dirent64 *)((char *)de + reclen);
10414 tde = (struct target_dirent *)((char *)tde + treclen);
10415 len -= reclen;
10416 tlen += treclen;
10417 }
10418 ret = tlen;
10419 }
10420 unlock_user(dirp, arg2, ret);
10421 }
10422#endif
bellard31e31b82003-02-18 22:55:36 +000010423 break;
Chen Gang704eff62015-08-21 05:37:33 +080010424#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010425#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010426 case TARGET_NR_getdents64:
10427 {
aurel326556a832008-10-13 21:08:17 +000010428 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010429 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010430 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10431 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010432 ret = get_errno(sys_getdents64(arg1, dirp, count));
10433 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010434 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010435 int len = ret;
10436 int reclen;
10437 de = dirp;
10438 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010439 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010440 if (reclen > len)
10441 break;
bellard8083a3e2003-03-24 23:12:16 +000010442 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010443 tswap64s((uint64_t *)&de->d_ino);
10444 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010445 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010446 len -= reclen;
10447 }
10448 }
pbrook53a59602006-03-25 19:31:22 +000010449 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010450 }
10451 break;
bellarda541f292004-04-12 20:39:29 +000010452#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010453#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010454 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010455 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010456 break;
thse5febef2007-04-01 18:31:35 +000010457#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010458#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10459# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010460 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010461# endif
10462# ifdef TARGET_NR_ppoll
10463 case TARGET_NR_ppoll:
10464# endif
bellard9de5e442003-03-23 16:49:39 +000010465 {
pbrook53a59602006-03-25 19:31:22 +000010466 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010467 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010468 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010469 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010470
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010471 pfd = NULL;
10472 target_pfd = NULL;
10473 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010474 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10475 ret = -TARGET_EINVAL;
10476 break;
10477 }
10478
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010479 target_pfd = lock_user(VERIFY_WRITE, arg1,
10480 sizeof(struct target_pollfd) * nfds, 1);
10481 if (!target_pfd) {
10482 goto efault;
10483 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010484
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010485 pfd = alloca(sizeof(struct pollfd) * nfds);
10486 for (i = 0; i < nfds; i++) {
10487 pfd[i].fd = tswap32(target_pfd[i].fd);
10488 pfd[i].events = tswap16(target_pfd[i].events);
10489 }
bellard9de5e442003-03-23 16:49:39 +000010490 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010491
Peter Maydella6130232016-06-06 19:58:10 +010010492 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010493# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010494 case TARGET_NR_ppoll:
10495 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010496 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10497 target_sigset_t *target_set;
10498 sigset_t _set, *set = &_set;
10499
10500 if (arg3) {
10501 if (target_to_host_timespec(timeout_ts, arg3)) {
10502 unlock_user(target_pfd, arg1, 0);
10503 goto efault;
10504 }
10505 } else {
10506 timeout_ts = NULL;
10507 }
10508
10509 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010510 if (arg5 != sizeof(target_sigset_t)) {
10511 unlock_user(target_pfd, arg1, 0);
10512 ret = -TARGET_EINVAL;
10513 break;
10514 }
10515
Mike Frysingerd8035d42011-02-07 01:05:51 -050010516 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10517 if (!target_set) {
10518 unlock_user(target_pfd, arg1, 0);
10519 goto efault;
10520 }
10521 target_to_host_sigset(set, target_set);
10522 } else {
10523 set = NULL;
10524 }
10525
Peter Maydella6130232016-06-06 19:58:10 +010010526 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10527 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010528
10529 if (!is_error(ret) && arg3) {
10530 host_to_target_timespec(arg3, timeout_ts);
10531 }
10532 if (arg4) {
10533 unlock_user(target_set, arg4, 0);
10534 }
Peter Maydella6130232016-06-06 19:58:10 +010010535 break;
10536 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010537# endif
Peter Maydella6130232016-06-06 19:58:10 +010010538# ifdef TARGET_NR_poll
10539 case TARGET_NR_poll:
10540 {
10541 struct timespec ts, *pts;
10542
10543 if (arg3 >= 0) {
10544 /* Convert ms to secs, ns */
10545 ts.tv_sec = arg3 / 1000;
10546 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10547 pts = &ts;
10548 } else {
10549 /* -ve poll() timeout means "infinite" */
10550 pts = NULL;
10551 }
10552 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10553 break;
10554 }
10555# endif
10556 default:
10557 g_assert_not_reached();
10558 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010559
bellard9de5e442003-03-23 16:49:39 +000010560 if (!is_error(ret)) {
10561 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010562 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010563 }
10564 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010565 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010566 }
10567 break;
thse5febef2007-04-01 18:31:35 +000010568#endif
bellard31e31b82003-02-18 22:55:36 +000010569 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010570 /* NOTE: the flock constant seems to be the same for every
10571 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010572 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010573 break;
10574 case TARGET_NR_readv:
10575 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010576 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10577 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010578 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010579 unlock_iovec(vec, arg2, arg3, 1);
10580 } else {
10581 ret = -host_to_target_errno(errno);
10582 }
bellard31e31b82003-02-18 22:55:36 +000010583 }
10584 break;
10585 case TARGET_NR_writev:
10586 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010587 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10588 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010589 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010590 unlock_iovec(vec, arg2, arg3, 0);
10591 } else {
10592 ret = -host_to_target_errno(errno);
10593 }
bellard31e31b82003-02-18 22:55:36 +000010594 }
10595 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010596#if defined(TARGET_NR_preadv)
10597 case TARGET_NR_preadv:
10598 {
10599 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10600 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010601 unsigned long low, high;
10602
10603 target_to_host_low_high(arg4, arg5, &low, &high);
10604 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010605 unlock_iovec(vec, arg2, arg3, 1);
10606 } else {
10607 ret = -host_to_target_errno(errno);
10608 }
10609 }
10610 break;
10611#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010612#if defined(TARGET_NR_pwritev)
10613 case TARGET_NR_pwritev:
10614 {
10615 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10616 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010617 unsigned long low, high;
10618
10619 target_to_host_low_high(arg4, arg5, &low, &high);
10620 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010621 unlock_iovec(vec, arg2, arg3, 0);
10622 } else {
10623 ret = -host_to_target_errno(errno);
10624 }
10625 }
10626 break;
10627#endif
bellard31e31b82003-02-18 22:55:36 +000010628 case TARGET_NR_getsid:
10629 ret = get_errno(getsid(arg1));
10630 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010631#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010632 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010633 ret = get_errno(fdatasync(arg1));
10634 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010635#endif
Chen Gang704eff62015-08-21 05:37:33 +080010636#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010637 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010638 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010639 return value. */
ths0da46a62007-10-20 20:23:07 +000010640 ret = -TARGET_ENOTDIR;
10641 break;
Chen Gang704eff62015-08-21 05:37:33 +080010642#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010643 case TARGET_NR_sched_getaffinity:
10644 {
10645 unsigned int mask_size;
10646 unsigned long *mask;
10647
10648 /*
10649 * sched_getaffinity needs multiples of ulong, so need to take
10650 * care of mismatches between target ulong and host ulong sizes.
10651 */
10652 if (arg2 & (sizeof(abi_ulong) - 1)) {
10653 ret = -TARGET_EINVAL;
10654 break;
10655 }
10656 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10657
10658 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010659 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010660 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10661
10662 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010663 if (ret > arg2) {
10664 /* More data returned than the caller's buffer will fit.
10665 * This only happens if sizeof(abi_long) < sizeof(long)
10666 * and the caller passed us a buffer holding an odd number
10667 * of abi_longs. If the host kernel is actually using the
10668 * extra 4 bytes then fail EINVAL; otherwise we can just
10669 * ignore them and only copy the interesting part.
10670 */
10671 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10672 if (numcpus > arg2 * 8) {
10673 ret = -TARGET_EINVAL;
10674 break;
10675 }
10676 ret = arg2;
10677 }
10678
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010679 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
10680 goto efault;
10681 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010682 }
10683 }
10684 break;
10685 case TARGET_NR_sched_setaffinity:
10686 {
10687 unsigned int mask_size;
10688 unsigned long *mask;
10689
10690 /*
10691 * sched_setaffinity needs multiples of ulong, so need to take
10692 * care of mismatches between target ulong and host ulong sizes.
10693 */
10694 if (arg2 & (sizeof(abi_ulong) - 1)) {
10695 ret = -TARGET_EINVAL;
10696 break;
10697 }
10698 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010699 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010700
10701 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10702 if (ret) {
10703 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010704 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010705
10706 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10707 }
10708 break;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010709 case TARGET_NR_getcpu:
10710 {
10711 unsigned cpu, node;
10712 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
10713 arg2 ? &node : NULL,
10714 NULL));
10715 if (is_error(ret)) {
10716 goto fail;
10717 }
10718 if (arg1 && put_user_u32(cpu, arg1)) {
10719 goto efault;
10720 }
10721 if (arg2 && put_user_u32(node, arg2)) {
10722 goto efault;
10723 }
10724 }
10725 break;
bellard31e31b82003-02-18 22:55:36 +000010726 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010727 {
pbrook53a59602006-03-25 19:31:22 +000010728 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010729 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010730
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010731 if (arg2 == 0) {
10732 return -TARGET_EINVAL;
10733 }
bellard579a97f2007-11-11 14:26:47 +000010734 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10735 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010736 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010737 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010738 ret = get_errno(sched_setparam(arg1, &schp));
10739 }
10740 break;
bellard31e31b82003-02-18 22:55:36 +000010741 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010742 {
pbrook53a59602006-03-25 19:31:22 +000010743 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010744 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010745
10746 if (arg2 == 0) {
10747 return -TARGET_EINVAL;
10748 }
bellard5cd43932003-03-29 16:54:36 +000010749 ret = get_errno(sched_getparam(arg1, &schp));
10750 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010751 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10752 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010753 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010754 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010755 }
10756 }
10757 break;
bellard31e31b82003-02-18 22:55:36 +000010758 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010759 {
pbrook53a59602006-03-25 19:31:22 +000010760 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010761 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010762 if (arg3 == 0) {
10763 return -TARGET_EINVAL;
10764 }
bellard579a97f2007-11-11 14:26:47 +000010765 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10766 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010767 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010768 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010769 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10770 }
10771 break;
bellard31e31b82003-02-18 22:55:36 +000010772 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010773 ret = get_errno(sched_getscheduler(arg1));
10774 break;
bellard31e31b82003-02-18 22:55:36 +000010775 case TARGET_NR_sched_yield:
10776 ret = get_errno(sched_yield());
10777 break;
10778 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010779 ret = get_errno(sched_get_priority_max(arg1));
10780 break;
bellard31e31b82003-02-18 22:55:36 +000010781 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010782 ret = get_errno(sched_get_priority_min(arg1));
10783 break;
bellard31e31b82003-02-18 22:55:36 +000010784 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010785 {
bellard5cd43932003-03-29 16:54:36 +000010786 struct timespec ts;
10787 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10788 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010789 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010790 }
10791 }
10792 break;
bellard31e31b82003-02-18 22:55:36 +000010793 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010794 {
bellard1b6b0292003-03-22 17:31:38 +000010795 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010796 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010797 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010798 if (is_error(ret) && arg2) {
10799 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010800 }
10801 }
10802 break;
thse5febef2007-04-01 18:31:35 +000010803#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010804 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010805 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010806#endif
10807#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010808 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010809 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010810#endif
bellard31e31b82003-02-18 22:55:36 +000010811 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010812 switch (arg1) {
10813 case PR_GET_PDEATHSIG:
10814 {
10815 int deathsig;
10816 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10817 if (!is_error(ret) && arg2
10818 && put_user_ual(deathsig, arg2)) {
10819 goto efault;
thse5574482007-02-11 20:03:13 +000010820 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010821 break;
10822 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010823#ifdef PR_GET_NAME
10824 case PR_GET_NAME:
10825 {
10826 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10827 if (!name) {
10828 goto efault;
10829 }
10830 ret = get_errno(prctl(arg1, (unsigned long)name,
10831 arg3, arg4, arg5));
10832 unlock_user(name, arg2, 16);
10833 break;
10834 }
10835 case PR_SET_NAME:
10836 {
10837 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10838 if (!name) {
10839 goto efault;
10840 }
10841 ret = get_errno(prctl(arg1, (unsigned long)name,
10842 arg3, arg4, arg5));
10843 unlock_user(name, arg2, 0);
10844 break;
10845 }
10846#endif
Richard Henderson85fc7162018-03-09 17:09:43 +000010847#ifdef TARGET_AARCH64
10848 case TARGET_PR_SVE_SET_VL:
10849 /* We cannot support either PR_SVE_SET_VL_ONEXEC
10850 or PR_SVE_VL_INHERIT. Therefore, anything above
10851 ARM_MAX_VQ results in EINVAL. */
10852 ret = -TARGET_EINVAL;
10853 if (arm_feature(cpu_env, ARM_FEATURE_SVE)
10854 && arg2 >= 0 && arg2 <= ARM_MAX_VQ * 16 && !(arg2 & 15)) {
10855 CPUARMState *env = cpu_env;
10856 int old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
10857 int vq = MAX(arg2 / 16, 1);
10858
10859 if (vq < old_vq) {
10860 aarch64_sve_narrow_vq(env, vq);
10861 }
10862 env->vfp.zcr_el[1] = vq - 1;
10863 ret = vq * 16;
10864 }
10865 break;
10866 case TARGET_PR_SVE_GET_VL:
10867 ret = -TARGET_EINVAL;
10868 if (arm_feature(cpu_env, ARM_FEATURE_SVE)) {
10869 CPUARMState *env = cpu_env;
10870 ret = ((env->vfp.zcr_el[1] & 0xf) + 1) * 16;
10871 }
10872 break;
10873#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +000010874 case PR_GET_SECCOMP:
10875 case PR_SET_SECCOMP:
10876 /* Disable seccomp to prevent the target disabling syscalls we
10877 * need. */
10878 ret = -TARGET_EINVAL;
10879 break;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010880 default:
10881 /* Most prctl options have no pointer arguments */
10882 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10883 break;
10884 }
ths39b9aae2007-02-11 18:36:44 +000010885 break;
bellardd2fd1af2007-11-14 18:08:56 +000010886#ifdef TARGET_NR_arch_prctl
10887 case TARGET_NR_arch_prctl:
10888#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10889 ret = do_arch_prctl(cpu_env, arg1, arg2);
10890 break;
10891#else
10892 goto unimplemented;
10893#endif
10894#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010895#ifdef TARGET_NR_pread64
10896 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010897 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010898 arg4 = arg5;
10899 arg5 = arg6;
10900 }
aurel32f2c7ba12008-03-28 22:32:06 +000010901 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10902 goto efault;
10903 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10904 unlock_user(p, arg2, ret);
10905 break;
10906 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010907 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010908 arg4 = arg5;
10909 arg5 = arg6;
10910 }
aurel32f2c7ba12008-03-28 22:32:06 +000010911 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10912 goto efault;
10913 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10914 unlock_user(p, arg2, 0);
10915 break;
10916#endif
bellard31e31b82003-02-18 22:55:36 +000010917 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010918 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10919 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010920 ret = get_errno(sys_getcwd1(p, arg2));
10921 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010922 break;
10923 case TARGET_NR_capget:
10924 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010925 {
10926 struct target_user_cap_header *target_header;
10927 struct target_user_cap_data *target_data = NULL;
10928 struct __user_cap_header_struct header;
10929 struct __user_cap_data_struct data[2];
10930 struct __user_cap_data_struct *dataptr = NULL;
10931 int i, target_datalen;
10932 int data_items = 1;
10933
10934 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10935 goto efault;
10936 }
10937 header.version = tswap32(target_header->version);
10938 header.pid = tswap32(target_header->pid);
10939
Peter Maydellec864872014-03-19 16:07:30 +000010940 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010941 /* Version 2 and up takes pointer to two user_data structs */
10942 data_items = 2;
10943 }
10944
10945 target_datalen = sizeof(*target_data) * data_items;
10946
10947 if (arg2) {
10948 if (num == TARGET_NR_capget) {
10949 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10950 } else {
10951 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10952 }
10953 if (!target_data) {
10954 unlock_user_struct(target_header, arg1, 0);
10955 goto efault;
10956 }
10957
10958 if (num == TARGET_NR_capset) {
10959 for (i = 0; i < data_items; i++) {
10960 data[i].effective = tswap32(target_data[i].effective);
10961 data[i].permitted = tswap32(target_data[i].permitted);
10962 data[i].inheritable = tswap32(target_data[i].inheritable);
10963 }
10964 }
10965
10966 dataptr = data;
10967 }
10968
10969 if (num == TARGET_NR_capget) {
10970 ret = get_errno(capget(&header, dataptr));
10971 } else {
10972 ret = get_errno(capset(&header, dataptr));
10973 }
10974
10975 /* The kernel always updates version for both capget and capset */
10976 target_header->version = tswap32(header.version);
10977 unlock_user_struct(target_header, arg1, 1);
10978
10979 if (arg2) {
10980 if (num == TARGET_NR_capget) {
10981 for (i = 0; i < data_items; i++) {
10982 target_data[i].effective = tswap32(data[i].effective);
10983 target_data[i].permitted = tswap32(data[i].permitted);
10984 target_data[i].inheritable = tswap32(data[i].inheritable);
10985 }
10986 unlock_user(target_data, arg2, target_datalen);
10987 } else {
10988 unlock_user(target_data, arg2, 0);
10989 }
10990 }
10991 break;
10992 }
bellard31e31b82003-02-18 22:55:36 +000010993 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010994 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010995 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010996
10997#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010998 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010999 {
11000 off_t *offp = NULL;
11001 off_t off;
11002 if (arg3) {
11003 ret = get_user_sal(off, arg3);
11004 if (is_error(ret)) {
11005 break;
11006 }
11007 offp = &off;
11008 }
11009 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11010 if (!is_error(ret) && arg3) {
11011 abi_long ret2 = put_user_sal(off, arg3);
11012 if (is_error(ret2)) {
11013 ret = ret2;
11014 }
11015 }
11016 break;
11017 }
11018#ifdef TARGET_NR_sendfile64
11019 case TARGET_NR_sendfile64:
11020 {
11021 off_t *offp = NULL;
11022 off_t off;
11023 if (arg3) {
11024 ret = get_user_s64(off, arg3);
11025 if (is_error(ret)) {
11026 break;
11027 }
11028 offp = &off;
11029 }
11030 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
11031 if (!is_error(ret) && arg3) {
11032 abi_long ret2 = put_user_s64(off, arg3);
11033 if (is_error(ret2)) {
11034 ret = ret2;
11035 }
11036 }
11037 break;
11038 }
11039#endif
11040#else
11041 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010011042#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011043 case TARGET_NR_sendfile64:
11044#endif
bellard5cd43932003-03-29 16:54:36 +000011045 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000011046#endif
11047
bellardebc05482003-09-30 21:08:41 +000011048#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000011049 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000011050 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011051#endif
11052#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000011053 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000011054 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011055#endif
bellard048f6b42005-11-26 18:47:20 +000011056#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000011057 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010011058 ret = get_errno(do_fork(cpu_env,
11059 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000011060 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000011061 break;
bellard048f6b42005-11-26 18:47:20 +000011062#endif
bellardebc05482003-09-30 21:08:41 +000011063#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000011064 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000011065 {
11066 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030011067 int resource = target_to_host_resource(arg1);
11068 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000011069 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000011070 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000011071 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
11072 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090011073 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
11074 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000011075 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000011076 }
11077 break;
11078 }
bellardebc05482003-09-30 21:08:41 +000011079#endif
bellarda315a142005-01-30 22:59:18 +000011080#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000011081 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000011082 if (!(p = lock_user_string(arg1)))
11083 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011084 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
11085 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000011086 break;
bellarda315a142005-01-30 22:59:18 +000011087#endif
11088#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000011089 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000011090 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000011091 break;
bellarda315a142005-01-30 22:59:18 +000011092#endif
11093#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000011094 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000011095 if (!(p = lock_user_string(arg1)))
11096 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011097 ret = get_errno(stat(path(p), &st));
11098 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011099 if (!is_error(ret))
11100 ret = host_to_target_stat64(cpu_env, arg2, &st);
11101 break;
bellarda315a142005-01-30 22:59:18 +000011102#endif
11103#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000011104 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000011105 if (!(p = lock_user_string(arg1)))
11106 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011107 ret = get_errno(lstat(path(p), &st));
11108 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000011109 if (!is_error(ret))
11110 ret = host_to_target_stat64(cpu_env, arg2, &st);
11111 break;
bellarda315a142005-01-30 22:59:18 +000011112#endif
11113#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000011114 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000011115 ret = get_errno(fstat(arg1, &st));
11116 if (!is_error(ret))
11117 ret = host_to_target_stat64(cpu_env, arg2, &st);
11118 break;
bellardec86b0f2003-04-11 00:15:04 +000011119#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010011120#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000011121#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000011122 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000011123#endif
11124#ifdef TARGET_NR_newfstatat
11125 case TARGET_NR_newfstatat:
11126#endif
balrog6a24a772008-09-20 02:23:36 +000011127 if (!(p = lock_user_string(arg2)))
11128 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011129 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000011130 if (!is_error(ret))
11131 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000011132 break;
bellarda315a142005-01-30 22:59:18 +000011133#endif
Chen Gang704eff62015-08-21 05:37:33 +080011134#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000011135 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000011136 if (!(p = lock_user_string(arg1)))
11137 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011138 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
11139 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011140 break;
Chen Gang704eff62015-08-21 05:37:33 +080011141#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030011142#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000011143 case TARGET_NR_getuid:
11144 ret = get_errno(high2lowuid(getuid()));
11145 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011146#endif
11147#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000011148 case TARGET_NR_getgid:
11149 ret = get_errno(high2lowgid(getgid()));
11150 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011151#endif
11152#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000011153 case TARGET_NR_geteuid:
11154 ret = get_errno(high2lowuid(geteuid()));
11155 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011156#endif
11157#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011158 case TARGET_NR_getegid:
11159 ret = get_errno(high2lowgid(getegid()));
11160 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011161#endif
bellard67867302003-11-23 17:05:30 +000011162 case TARGET_NR_setreuid:
11163 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
11164 break;
11165 case TARGET_NR_setregid:
11166 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
11167 break;
11168 case TARGET_NR_getgroups:
11169 {
11170 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011171 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000011172 gid_t *grouplist;
11173 int i;
11174
11175 grouplist = alloca(gidsetsize * sizeof(gid_t));
11176 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011177 if (gidsetsize == 0)
11178 break;
bellard67867302003-11-23 17:05:30 +000011179 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000011180 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000011181 if (!target_grouplist)
11182 goto efault;
balroga2155fc2008-09-20 02:12:08 +000011183 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030011184 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011185 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000011186 }
11187 }
11188 break;
11189 case TARGET_NR_setgroups:
11190 {
11191 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011192 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011193 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011194 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011195 if (gidsetsize) {
11196 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011197 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011198 if (!target_grouplist) {
11199 ret = -TARGET_EFAULT;
11200 goto fail;
11201 }
11202 for (i = 0; i < gidsetsize; i++) {
11203 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11204 }
11205 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000011206 }
bellard67867302003-11-23 17:05:30 +000011207 ret = get_errno(setgroups(gidsetsize, grouplist));
11208 }
11209 break;
11210 case TARGET_NR_fchown:
11211 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
11212 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011213#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011214 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011215 if (!(p = lock_user_string(arg2)))
11216 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011217 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11218 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011219 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000011220 break;
11221#endif
bellard67867302003-11-23 17:05:30 +000011222#ifdef TARGET_NR_setresuid
11223 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011224 ret = get_errno(sys_setresuid(low2highuid(arg1),
11225 low2highuid(arg2),
11226 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011227 break;
11228#endif
11229#ifdef TARGET_NR_getresuid
11230 case TARGET_NR_getresuid:
11231 {
pbrook53a59602006-03-25 19:31:22 +000011232 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011233 ret = get_errno(getresuid(&ruid, &euid, &suid));
11234 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011235 if (put_user_id(high2lowuid(ruid), arg1)
11236 || put_user_id(high2lowuid(euid), arg2)
11237 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000011238 goto efault;
bellard67867302003-11-23 17:05:30 +000011239 }
11240 }
11241 break;
11242#endif
11243#ifdef TARGET_NR_getresgid
11244 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011245 ret = get_errno(sys_setresgid(low2highgid(arg1),
11246 low2highgid(arg2),
11247 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011248 break;
11249#endif
11250#ifdef TARGET_NR_getresgid
11251 case TARGET_NR_getresgid:
11252 {
pbrook53a59602006-03-25 19:31:22 +000011253 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011254 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11255 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011256 if (put_user_id(high2lowgid(rgid), arg1)
11257 || put_user_id(high2lowgid(egid), arg2)
11258 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000011259 goto efault;
bellard67867302003-11-23 17:05:30 +000011260 }
11261 }
11262 break;
11263#endif
Chen Gang704eff62015-08-21 05:37:33 +080011264#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011265 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011266 if (!(p = lock_user_string(arg1)))
11267 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011268 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11269 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011270 break;
Chen Gang704eff62015-08-21 05:37:33 +080011271#endif
bellard67867302003-11-23 17:05:30 +000011272 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011273 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011274 break;
11275 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011276 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011277 break;
11278 case TARGET_NR_setfsuid:
11279 ret = get_errno(setfsuid(arg1));
11280 break;
11281 case TARGET_NR_setfsgid:
11282 ret = get_errno(setfsgid(arg1));
11283 break;
bellard67867302003-11-23 17:05:30 +000011284
bellarda315a142005-01-30 22:59:18 +000011285#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011286 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011287 if (!(p = lock_user_string(arg1)))
11288 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011289 ret = get_errno(lchown(p, arg2, arg3));
11290 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011291 break;
bellarda315a142005-01-30 22:59:18 +000011292#endif
11293#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011294 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000011295 ret = get_errno(getuid());
11296 break;
bellarda315a142005-01-30 22:59:18 +000011297#endif
aurel3264b4d282008-11-14 17:20:15 +000011298
11299#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11300 /* Alpha specific */
11301 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011302 {
11303 uid_t euid;
11304 euid=geteuid();
11305 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11306 }
aurel3264b4d282008-11-14 17:20:15 +000011307 ret = get_errno(getuid());
11308 break;
11309#endif
11310#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11311 /* Alpha specific */
11312 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011313 {
11314 uid_t egid;
11315 egid=getegid();
11316 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11317 }
aurel3264b4d282008-11-14 17:20:15 +000011318 ret = get_errno(getgid());
11319 break;
11320#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011321#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11322 /* Alpha specific */
11323 case TARGET_NR_osf_getsysinfo:
11324 ret = -TARGET_EOPNOTSUPP;
11325 switch (arg1) {
11326 case TARGET_GSI_IEEE_FP_CONTROL:
11327 {
11328 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
11329
11330 /* Copied from linux ieee_fpcr_to_swcr. */
11331 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
11332 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
11333 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
11334 | SWCR_TRAP_ENABLE_DZE
11335 | SWCR_TRAP_ENABLE_OVF);
11336 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
11337 | SWCR_TRAP_ENABLE_INE);
11338 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
11339 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
11340
11341 if (put_user_u64 (swcr, arg2))
11342 goto efault;
11343 ret = 0;
11344 }
11345 break;
11346
11347 /* case GSI_IEEE_STATE_AT_SIGNAL:
11348 -- Not implemented in linux kernel.
11349 case GSI_UACPROC:
11350 -- Retrieves current unaligned access state; not much used.
11351 case GSI_PROC_TYPE:
11352 -- Retrieves implver information; surely not used.
11353 case GSI_GET_HWRPB:
11354 -- Grabs a copy of the HWRPB; surely not used.
11355 */
11356 }
11357 break;
11358#endif
11359#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11360 /* Alpha specific */
11361 case TARGET_NR_osf_setsysinfo:
11362 ret = -TARGET_EOPNOTSUPP;
11363 switch (arg1) {
11364 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011365 {
11366 uint64_t swcr, fpcr, orig_fpcr;
11367
Richard Henderson6e06d512012-06-01 09:08:21 -070011368 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080011369 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070011370 }
11371 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011372 fpcr = orig_fpcr & FPCR_DYN_MASK;
11373
11374 /* Copied from linux ieee_swcr_to_fpcr. */
11375 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
11376 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
11377 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
11378 | SWCR_TRAP_ENABLE_DZE
11379 | SWCR_TRAP_ENABLE_OVF)) << 48;
11380 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
11381 | SWCR_TRAP_ENABLE_INE)) << 57;
11382 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
11383 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
11384
Richard Henderson6e06d512012-06-01 09:08:21 -070011385 cpu_alpha_store_fpcr(cpu_env, fpcr);
11386 ret = 0;
11387 }
11388 break;
11389
11390 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11391 {
11392 uint64_t exc, fpcr, orig_fpcr;
11393 int si_code;
11394
11395 if (get_user_u64(exc, arg2)) {
11396 goto efault;
11397 }
11398
11399 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
11400
11401 /* We only add to the exception status here. */
11402 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
11403
11404 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011405 ret = 0;
11406
Richard Henderson6e06d512012-06-01 09:08:21 -070011407 /* Old exceptions are not signaled. */
11408 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011409
Richard Henderson6e06d512012-06-01 09:08:21 -070011410 /* If any exceptions set by this call,
11411 and are unmasked, send a signal. */
11412 si_code = 0;
11413 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11414 si_code = TARGET_FPE_FLTRES;
11415 }
11416 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11417 si_code = TARGET_FPE_FLTUND;
11418 }
11419 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11420 si_code = TARGET_FPE_FLTOVF;
11421 }
11422 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11423 si_code = TARGET_FPE_FLTDIV;
11424 }
11425 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11426 si_code = TARGET_FPE_FLTINV;
11427 }
11428 if (si_code != 0) {
11429 target_siginfo_t info;
11430 info.si_signo = SIGFPE;
11431 info.si_errno = 0;
11432 info.si_code = si_code;
11433 info._sifields._sigfault._addr
11434 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011435 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11436 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011437 }
11438 }
11439 break;
11440
11441 /* case SSI_NVPAIRS:
11442 -- Used with SSIN_UACPROC to enable unaligned accesses.
11443 case SSI_IEEE_STATE_AT_SIGNAL:
11444 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11445 -- Not implemented in linux kernel
11446 */
11447 }
11448 break;
11449#endif
11450#ifdef TARGET_NR_osf_sigprocmask
11451 /* Alpha specific. */
11452 case TARGET_NR_osf_sigprocmask:
11453 {
11454 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011455 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011456 sigset_t set, oldset;
11457
11458 switch(arg1) {
11459 case TARGET_SIG_BLOCK:
11460 how = SIG_BLOCK;
11461 break;
11462 case TARGET_SIG_UNBLOCK:
11463 how = SIG_UNBLOCK;
11464 break;
11465 case TARGET_SIG_SETMASK:
11466 how = SIG_SETMASK;
11467 break;
11468 default:
11469 ret = -TARGET_EINVAL;
11470 goto fail;
11471 }
11472 mask = arg2;
11473 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011474 ret = do_sigprocmask(how, &set, &oldset);
11475 if (!ret) {
11476 host_to_target_old_sigset(&mask, &oldset);
11477 ret = mask;
11478 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011479 }
11480 break;
11481#endif
aurel3264b4d282008-11-14 17:20:15 +000011482
bellarda315a142005-01-30 22:59:18 +000011483#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011484 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011485 ret = get_errno(getgid());
11486 break;
bellarda315a142005-01-30 22:59:18 +000011487#endif
11488#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011489 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011490 ret = get_errno(geteuid());
11491 break;
bellarda315a142005-01-30 22:59:18 +000011492#endif
11493#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011494 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011495 ret = get_errno(getegid());
11496 break;
bellarda315a142005-01-30 22:59:18 +000011497#endif
11498#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011499 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011500 ret = get_errno(setreuid(arg1, arg2));
11501 break;
bellarda315a142005-01-30 22:59:18 +000011502#endif
11503#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011504 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011505 ret = get_errno(setregid(arg1, arg2));
11506 break;
bellarda315a142005-01-30 22:59:18 +000011507#endif
11508#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011509 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011510 {
11511 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011512 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011513 gid_t *grouplist;
11514 int i;
11515
11516 grouplist = alloca(gidsetsize * sizeof(gid_t));
11517 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011518 if (gidsetsize == 0)
11519 break;
bellard99c475a2005-01-31 20:45:13 +000011520 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011521 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11522 if (!target_grouplist) {
11523 ret = -TARGET_EFAULT;
11524 goto fail;
11525 }
balroga2155fc2008-09-20 02:12:08 +000011526 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011527 target_grouplist[i] = tswap32(grouplist[i]);
11528 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011529 }
11530 }
11531 break;
bellarda315a142005-01-30 22:59:18 +000011532#endif
11533#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011534 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011535 {
11536 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011537 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011538 gid_t *grouplist;
11539 int i;
ths3b46e622007-09-17 08:09:54 +000011540
bellard99c475a2005-01-31 20:45:13 +000011541 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011542 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11543 if (!target_grouplist) {
11544 ret = -TARGET_EFAULT;
11545 goto fail;
11546 }
bellard99c475a2005-01-31 20:45:13 +000011547 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011548 grouplist[i] = tswap32(target_grouplist[i]);
11549 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011550 ret = get_errno(setgroups(gidsetsize, grouplist));
11551 }
11552 break;
bellarda315a142005-01-30 22:59:18 +000011553#endif
11554#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011555 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011556 ret = get_errno(fchown(arg1, arg2, arg3));
11557 break;
bellarda315a142005-01-30 22:59:18 +000011558#endif
11559#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011560 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011561 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011562 break;
bellarda315a142005-01-30 22:59:18 +000011563#endif
11564#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011565 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011566 {
pbrook53a59602006-03-25 19:31:22 +000011567 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011568 ret = get_errno(getresuid(&ruid, &euid, &suid));
11569 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011570 if (put_user_u32(ruid, arg1)
11571 || put_user_u32(euid, arg2)
11572 || put_user_u32(suid, arg3))
11573 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011574 }
11575 }
11576 break;
bellarda315a142005-01-30 22:59:18 +000011577#endif
11578#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011579 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011580 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011581 break;
bellarda315a142005-01-30 22:59:18 +000011582#endif
11583#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011584 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011585 {
pbrook53a59602006-03-25 19:31:22 +000011586 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011587 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11588 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011589 if (put_user_u32(rgid, arg1)
11590 || put_user_u32(egid, arg2)
11591 || put_user_u32(sgid, arg3))
11592 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011593 }
11594 }
11595 break;
bellarda315a142005-01-30 22:59:18 +000011596#endif
11597#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011598 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011599 if (!(p = lock_user_string(arg1)))
11600 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011601 ret = get_errno(chown(p, arg2, arg3));
11602 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011603 break;
bellarda315a142005-01-30 22:59:18 +000011604#endif
11605#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011606 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011607 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011608 break;
bellarda315a142005-01-30 22:59:18 +000011609#endif
11610#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011611 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011612 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011613 break;
bellarda315a142005-01-30 22:59:18 +000011614#endif
11615#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011616 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011617 ret = get_errno(setfsuid(arg1));
11618 break;
bellarda315a142005-01-30 22:59:18 +000011619#endif
11620#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011621 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011622 ret = get_errno(setfsgid(arg1));
11623 break;
bellarda315a142005-01-30 22:59:18 +000011624#endif
bellard67867302003-11-23 17:05:30 +000011625
bellard31e31b82003-02-18 22:55:36 +000011626 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011627 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011628#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011629 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011630 {
11631 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011632 ret = -TARGET_ENOMEM;
11633 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11634 if (!a) {
11635 goto fail;
11636 }
aurel3204bb9ac2008-10-01 21:46:41 +000011637 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011638 p = lock_user_string(arg3);
11639 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011640 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011641 }
aurel3204bb9ac2008-10-01 21:46:41 +000011642 ret = get_errno(mincore(a, arg2, p));
11643 unlock_user(p, arg3, ret);
11644 mincore_fail:
11645 unlock_user(a, arg1, 0);
11646 }
11647 break;
bellardffa65c32004-01-04 23:57:22 +000011648#endif
aurel32408321b2008-10-01 21:46:32 +000011649#ifdef TARGET_NR_arm_fadvise64_64
11650 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011651 /* arm_fadvise64_64 looks like fadvise64_64 but
11652 * with different argument order: fd, advice, offset, len
11653 * rather than the usual fd, offset, len, advice.
11654 * Note that offset and len are both 64-bit so appear as
11655 * pairs of 32-bit registers.
11656 */
11657 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11658 target_offset64(arg5, arg6), arg2);
11659 ret = -host_to_target_errno(ret);
11660 break;
aurel32408321b2008-10-01 21:46:32 +000011661#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011662
11663#if TARGET_ABI_BITS == 32
11664
11665#ifdef TARGET_NR_fadvise64_64
11666 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070011667#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010011668 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11669 ret = arg2;
11670 arg2 = arg3;
11671 arg3 = arg4;
11672 arg4 = arg5;
11673 arg5 = arg6;
11674 arg6 = ret;
11675#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011676 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011677 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011678 /* offset is in (3,4), len in (5,6) and advice in 7 */
11679 arg2 = arg3;
11680 arg3 = arg4;
11681 arg4 = arg5;
11682 arg5 = arg6;
11683 arg6 = arg7;
11684 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011685#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011686 ret = -host_to_target_errno(posix_fadvise(arg1,
11687 target_offset64(arg2, arg3),
11688 target_offset64(arg4, arg5),
11689 arg6));
11690 break;
11691#endif
11692
11693#ifdef TARGET_NR_fadvise64
11694 case TARGET_NR_fadvise64:
11695 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011696 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011697 /* offset is in (3,4), len in 5 and advice in 6 */
11698 arg2 = arg3;
11699 arg3 = arg4;
11700 arg4 = arg5;
11701 arg5 = arg6;
11702 }
11703 ret = -host_to_target_errno(posix_fadvise(arg1,
11704 target_offset64(arg2, arg3),
11705 arg4, arg5));
11706 break;
11707#endif
11708
11709#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011710#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011711#ifdef TARGET_NR_fadvise64_64
11712 case TARGET_NR_fadvise64_64:
11713#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011714#ifdef TARGET_NR_fadvise64
11715 case TARGET_NR_fadvise64:
11716#endif
11717#ifdef TARGET_S390X
11718 switch (arg4) {
11719 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11720 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11721 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11722 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11723 default: break;
11724 }
11725#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011726 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11727 break;
aurel32408321b2008-10-01 21:46:32 +000011728#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011729#endif /* end of 64-bit ABI fadvise handling */
11730
bellardffa65c32004-01-04 23:57:22 +000011731#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011732 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011733 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011734 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011735 This will break MADV_DONTNEED.
11736 This is a hint, so ignoring and returning success is ok. */
11737 ret = get_errno(0);
11738 break;
bellardffa65c32004-01-04 23:57:22 +000011739#endif
blueswir1992f48a2007-10-14 16:27:31 +000011740#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011741 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011742 {
thsb1e341e2007-03-20 21:50:52 +000011743 int cmd;
bellard77e46722003-04-29 20:39:06 +000011744 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011745 from_flock64_fn *copyfrom = copy_from_user_flock64;
11746 to_flock64_fn *copyto = copy_to_user_flock64;
11747
pbrookce4defa2006-02-09 16:49:55 +000011748#ifdef TARGET_ARM
Laurent Vivier7f254c52018-05-02 23:57:30 +020011749 if (!((CPUARMState *)cpu_env)->eabi) {
11750 copyfrom = copy_from_user_oabi_flock64;
11751 copyto = copy_to_user_oabi_flock64;
Peter Maydell213d3e92016-06-13 11:22:05 +010011752 }
pbrookce4defa2006-02-09 16:49:55 +000011753#endif
bellard77e46722003-04-29 20:39:06 +000011754
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011755 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011756 if (cmd == -TARGET_EINVAL) {
11757 ret = cmd;
11758 break;
11759 }
thsb1e341e2007-03-20 21:50:52 +000011760
bellard60cd49d2003-03-16 22:53:56 +000011761 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011762 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011763 ret = copyfrom(&fl, arg3);
11764 if (ret) {
11765 break;
ths58134272007-03-31 18:59:32 +000011766 }
thsb1e341e2007-03-20 21:50:52 +000011767 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011768 if (ret == 0) {
11769 ret = copyto(arg3, &fl);
11770 }
bellard77e46722003-04-29 20:39:06 +000011771 break;
11772
thsb1e341e2007-03-20 21:50:52 +000011773 case TARGET_F_SETLK64:
11774 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011775 ret = copyfrom(&fl, arg3);
11776 if (ret) {
11777 break;
pbrookce4defa2006-02-09 16:49:55 +000011778 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011779 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011780 break;
bellard60cd49d2003-03-16 22:53:56 +000011781 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011782 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011783 break;
11784 }
bellard77e46722003-04-29 20:39:06 +000011785 break;
11786 }
bellard60cd49d2003-03-16 22:53:56 +000011787#endif
ths7d600c82006-12-08 01:32:58 +000011788#ifdef TARGET_NR_cacheflush
11789 case TARGET_NR_cacheflush:
11790 /* self-modifying code is handled automatically, so nothing needed */
11791 ret = 0;
11792 break;
11793#endif
bellardebc05482003-09-30 21:08:41 +000011794#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011795 case TARGET_NR_security:
11796 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011797#endif
bellardc573ff62004-01-04 15:51:36 +000011798#ifdef TARGET_NR_getpagesize
11799 case TARGET_NR_getpagesize:
11800 ret = TARGET_PAGE_SIZE;
11801 break;
11802#endif
bellard31e31b82003-02-18 22:55:36 +000011803 case TARGET_NR_gettid:
11804 ret = get_errno(gettid());
11805 break;
thse5febef2007-04-01 18:31:35 +000011806#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011807 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011808#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011809 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011810 arg2 = arg3;
11811 arg3 = arg4;
11812 arg4 = arg5;
11813 }
Lena Djokic77c68502016-11-24 17:08:56 +010011814 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011815#else
11816 ret = get_errno(readahead(arg1, arg2, arg3));
11817#endif
11818 break;
thse5febef2007-04-01 18:31:35 +000011819#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011820#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011821#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011822 case TARGET_NR_listxattr:
11823 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011824 {
11825 void *p, *b = 0;
11826 if (arg2) {
11827 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11828 if (!b) {
11829 ret = -TARGET_EFAULT;
11830 break;
11831 }
11832 }
11833 p = lock_user_string(arg1);
11834 if (p) {
11835 if (num == TARGET_NR_listxattr) {
11836 ret = get_errno(listxattr(p, b, arg3));
11837 } else {
11838 ret = get_errno(llistxattr(p, b, arg3));
11839 }
11840 } else {
11841 ret = -TARGET_EFAULT;
11842 }
11843 unlock_user(p, arg1, 0);
11844 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011845 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011846 }
11847 case TARGET_NR_flistxattr:
11848 {
11849 void *b = 0;
11850 if (arg2) {
11851 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11852 if (!b) {
11853 ret = -TARGET_EFAULT;
11854 break;
11855 }
11856 }
11857 ret = get_errno(flistxattr(arg1, b, arg3));
11858 unlock_user(b, arg2, arg3);
11859 break;
11860 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011861 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011862 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011863 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011864 void *p, *n, *v = 0;
11865 if (arg3) {
11866 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11867 if (!v) {
11868 ret = -TARGET_EFAULT;
11869 break;
11870 }
11871 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011872 p = lock_user_string(arg1);
11873 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011874 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011875 if (num == TARGET_NR_setxattr) {
11876 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11877 } else {
11878 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11879 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011880 } else {
11881 ret = -TARGET_EFAULT;
11882 }
11883 unlock_user(p, arg1, 0);
11884 unlock_user(n, arg2, 0);
11885 unlock_user(v, arg3, 0);
11886 }
11887 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011888 case TARGET_NR_fsetxattr:
11889 {
11890 void *n, *v = 0;
11891 if (arg3) {
11892 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11893 if (!v) {
11894 ret = -TARGET_EFAULT;
11895 break;
11896 }
11897 }
11898 n = lock_user_string(arg2);
11899 if (n) {
11900 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11901 } else {
11902 ret = -TARGET_EFAULT;
11903 }
11904 unlock_user(n, arg2, 0);
11905 unlock_user(v, arg3, 0);
11906 }
11907 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011908 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011909 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011910 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011911 void *p, *n, *v = 0;
11912 if (arg3) {
11913 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11914 if (!v) {
11915 ret = -TARGET_EFAULT;
11916 break;
11917 }
11918 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011919 p = lock_user_string(arg1);
11920 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011921 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011922 if (num == TARGET_NR_getxattr) {
11923 ret = get_errno(getxattr(p, n, v, arg4));
11924 } else {
11925 ret = get_errno(lgetxattr(p, n, v, arg4));
11926 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011927 } else {
11928 ret = -TARGET_EFAULT;
11929 }
11930 unlock_user(p, arg1, 0);
11931 unlock_user(n, arg2, 0);
11932 unlock_user(v, arg3, arg4);
11933 }
11934 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011935 case TARGET_NR_fgetxattr:
11936 {
11937 void *n, *v = 0;
11938 if (arg3) {
11939 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11940 if (!v) {
11941 ret = -TARGET_EFAULT;
11942 break;
11943 }
11944 }
11945 n = lock_user_string(arg2);
11946 if (n) {
11947 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11948 } else {
11949 ret = -TARGET_EFAULT;
11950 }
11951 unlock_user(n, arg2, 0);
11952 unlock_user(v, arg3, arg4);
11953 }
11954 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011955 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011956 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011957 {
11958 void *p, *n;
11959 p = lock_user_string(arg1);
11960 n = lock_user_string(arg2);
11961 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011962 if (num == TARGET_NR_removexattr) {
11963 ret = get_errno(removexattr(p, n));
11964 } else {
11965 ret = get_errno(lremovexattr(p, n));
11966 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011967 } else {
11968 ret = -TARGET_EFAULT;
11969 }
11970 unlock_user(p, arg1, 0);
11971 unlock_user(n, arg2, 0);
11972 }
11973 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011974 case TARGET_NR_fremovexattr:
11975 {
11976 void *n;
11977 n = lock_user_string(arg2);
11978 if (n) {
11979 ret = get_errno(fremovexattr(arg1, n));
11980 } else {
11981 ret = -TARGET_EFAULT;
11982 }
11983 unlock_user(n, arg2, 0);
11984 }
11985 break;
bellardebc05482003-09-30 21:08:41 +000011986#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011987#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011988#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011989 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011990#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011991 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011992 ret = 0;
11993 break;
edgar_iglef967792009-01-07 14:19:38 +000011994#elif defined(TARGET_CRIS)
11995 if (arg1 & 0xff)
11996 ret = -TARGET_EINVAL;
11997 else {
11998 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11999 ret = 0;
12000 }
12001 break;
bellard8d18e892007-11-14 15:18:40 +000012002#elif defined(TARGET_I386) && defined(TARGET_ABI32)
12003 ret = do_set_thread_area(cpu_env, arg1);
12004 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012005#elif defined(TARGET_M68K)
12006 {
Andreas Färber0429a972013-08-26 18:14:44 +020012007 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012008 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010012009 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012010 break;
12011 }
ths6f5b89a2007-03-02 20:48:00 +000012012#else
12013 goto unimplemented_nowarn;
12014#endif
12015#endif
12016#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000012017 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000012018#if defined(TARGET_I386) && defined(TARGET_ABI32)
12019 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010012020 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012021#elif defined(TARGET_M68K)
12022 {
Andreas Färber0429a972013-08-26 18:14:44 +020012023 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010012024 ret = ts->tp_value;
12025 break;
12026 }
bellard8d18e892007-11-14 15:18:40 +000012027#else
bellard5cd43932003-03-29 16:54:36 +000012028 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000012029#endif
bellard8d18e892007-11-14 15:18:40 +000012030#endif
bellard48dc41e2006-06-21 18:15:50 +000012031#ifdef TARGET_NR_getdomainname
12032 case TARGET_NR_getdomainname:
12033 goto unimplemented_nowarn;
12034#endif
ths6f5b89a2007-03-02 20:48:00 +000012035
Max Filippov12e33402018-04-01 13:13:49 -070012036#ifdef TARGET_NR_clock_settime
12037 case TARGET_NR_clock_settime:
12038 {
12039 struct timespec ts;
12040
12041 ret = target_to_host_timespec(&ts, arg2);
12042 if (!is_error(ret)) {
12043 ret = get_errno(clock_settime(arg1, &ts));
12044 }
12045 break;
12046 }
12047#endif
thsb5906f92007-03-19 13:32:45 +000012048#ifdef TARGET_NR_clock_gettime
12049 case TARGET_NR_clock_gettime:
12050 {
12051 struct timespec ts;
12052 ret = get_errno(clock_gettime(arg1, &ts));
12053 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070012054 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000012055 }
12056 break;
12057 }
12058#endif
12059#ifdef TARGET_NR_clock_getres
12060 case TARGET_NR_clock_getres:
12061 {
12062 struct timespec ts;
12063 ret = get_errno(clock_getres(arg1, &ts));
12064 if (!is_error(ret)) {
12065 host_to_target_timespec(arg2, &ts);
12066 }
12067 break;
12068 }
12069#endif
pbrook63d76512008-05-29 13:43:29 +000012070#ifdef TARGET_NR_clock_nanosleep
12071 case TARGET_NR_clock_nanosleep:
12072 {
12073 struct timespec ts;
12074 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010012075 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
12076 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000012077 if (arg4)
12078 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012079
12080#if defined(TARGET_PPC)
12081 /* clock_nanosleep is odd in that it returns positive errno values.
12082 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010012083 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050012084 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
12085 }
12086#endif
pbrook63d76512008-05-29 13:43:29 +000012087 break;
12088 }
12089#endif
thsb5906f92007-03-19 13:32:45 +000012090
ths6f5b89a2007-03-02 20:48:00 +000012091#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
12092 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000012093 ret = get_errno(set_tid_address((int *)g2h(arg1)));
12094 break;
ths6f5b89a2007-03-02 20:48:00 +000012095#endif
12096
ths4cae1d12007-07-12 11:06:53 +000012097 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010012098 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000012099 break;
ths4cae1d12007-07-12 11:06:53 +000012100
ths71455572007-06-21 21:45:30 +000012101 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010012102 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000012103 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010012104 break;
ths71455572007-06-21 21:45:30 +000012105
ths4f2b1fe2007-06-21 21:57:12 +000012106#ifdef TARGET_NR_set_robust_list
12107 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000012108 case TARGET_NR_get_robust_list:
12109 /* The ABI for supporting robust futexes has userspace pass
12110 * the kernel a pointer to a linked list which is updated by
12111 * userspace after the syscall; the list is walked by the kernel
12112 * when the thread exits. Since the linked list in QEMU guest
12113 * memory isn't a valid linked list for the host and we have
12114 * no way to reliably intercept the thread-death event, we can't
12115 * support these. Silently return ENOSYS so that guest userspace
12116 * falls back to a non-robust futex implementation (which should
12117 * be OK except in the corner case of the guest crashing while
12118 * holding a mutex that is shared with another process via
12119 * shared memory).
12120 */
12121 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000012122#endif
12123
Peter Maydell1acae9f2013-07-02 14:04:12 +010012124#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000012125 case TARGET_NR_utimensat:
12126 {
Riku Voipioebc996f2009-04-21 15:01:51 +030012127 struct timespec *tsp, ts[2];
12128 if (!arg3) {
12129 tsp = NULL;
12130 } else {
12131 target_to_host_timespec(ts, arg3);
12132 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
12133 tsp = ts;
12134 }
ths9007f0e2007-09-25 17:50:37 +000012135 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030012136 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000012137 else {
bellard579a97f2007-11-11 14:26:47 +000012138 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000012139 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012140 goto fail;
12141 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012142 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000012143 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000012144 }
12145 }
12146 break;
12147#endif
pbrookbd0c5662008-05-29 14:34:11 +000012148 case TARGET_NR_futex:
12149 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
12150 break;
aurel32dbfe4c32009-04-08 21:29:30 +000012151#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000012152 case TARGET_NR_inotify_init:
12153 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012154 if (ret >= 0) {
12155 fd_trans_register(ret, &target_inotify_trans);
12156 }
aurel3239b59762008-10-01 21:46:50 +000012157 break;
12158#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012159#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000012160#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
12161 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010012162 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
12163 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012164 if (ret >= 0) {
12165 fd_trans_register(ret, &target_inotify_trans);
12166 }
Riku Voipioc05c7a72010-03-26 15:25:11 +000012167 break;
12168#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012169#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012170#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012171 case TARGET_NR_inotify_add_watch:
12172 p = lock_user_string(arg2);
12173 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
12174 unlock_user(p, arg2, 0);
12175 break;
12176#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012177#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012178 case TARGET_NR_inotify_rm_watch:
12179 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
12180 break;
12181#endif
ths9007f0e2007-09-25 17:50:37 +000012182
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012183#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012184 case TARGET_NR_mq_open:
12185 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012186 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012187 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012188 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012189
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012190 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012191 pposix_mq_attr = NULL;
12192 if (arg4) {
12193 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
12194 goto efault;
12195 }
12196 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012197 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012198 p = lock_user_string(arg1 - 1);
12199 if (!p) {
12200 goto efault;
12201 }
Lena Djokic26400772016-11-24 17:08:58 +010012202 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012203 unlock_user (p, arg1, 0);
12204 }
12205 break;
12206
12207 case TARGET_NR_mq_unlink:
12208 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012209 if (!p) {
12210 ret = -TARGET_EFAULT;
12211 break;
12212 }
aurel3224e10032009-04-15 16:11:43 +000012213 ret = get_errno(mq_unlink(p));
12214 unlock_user (p, arg1, 0);
12215 break;
12216
12217 case TARGET_NR_mq_timedsend:
12218 {
12219 struct timespec ts;
12220
12221 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12222 if (arg5 != 0) {
12223 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012224 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000012225 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012226 } else {
12227 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012228 }
aurel3224e10032009-04-15 16:11:43 +000012229 unlock_user (p, arg2, arg3);
12230 }
12231 break;
12232
12233 case TARGET_NR_mq_timedreceive:
12234 {
12235 struct timespec ts;
12236 unsigned int prio;
12237
12238 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12239 if (arg5 != 0) {
12240 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012241 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12242 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000012243 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012244 } else {
12245 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12246 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000012247 }
aurel3224e10032009-04-15 16:11:43 +000012248 unlock_user (p, arg2, arg3);
12249 if (arg4 != 0)
12250 put_user_u32(prio, arg4);
12251 }
12252 break;
12253
12254 /* Not implemented for now... */
12255/* case TARGET_NR_mq_notify: */
12256/* break; */
12257
12258 case TARGET_NR_mq_getsetattr:
12259 {
12260 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
12261 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000012262 if (arg2 != 0) {
12263 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070012264 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
12265 &posix_mq_attr_out));
12266 } else if (arg3 != 0) {
12267 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000012268 }
Max Filippova23ea402018-03-31 08:20:15 -070012269 if (ret == 0 && arg3 != 0) {
12270 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
12271 }
aurel3224e10032009-04-15 16:11:43 +000012272 }
12273 break;
12274#endif
12275
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012276#ifdef CONFIG_SPLICE
12277#ifdef TARGET_NR_tee
12278 case TARGET_NR_tee:
12279 {
12280 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12281 }
12282 break;
12283#endif
12284#ifdef TARGET_NR_splice
12285 case TARGET_NR_splice:
12286 {
12287 loff_t loff_in, loff_out;
12288 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012289 if (arg2) {
12290 if (get_user_u64(loff_in, arg2)) {
12291 goto efault;
12292 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012293 ploff_in = &loff_in;
12294 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012295 if (arg4) {
12296 if (get_user_u64(loff_out, arg4)) {
12297 goto efault;
12298 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012299 ploff_out = &loff_out;
12300 }
12301 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012302 if (arg2) {
12303 if (put_user_u64(loff_in, arg2)) {
12304 goto efault;
12305 }
12306 }
12307 if (arg4) {
12308 if (put_user_u64(loff_out, arg4)) {
12309 goto efault;
12310 }
12311 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012312 }
12313 break;
12314#endif
12315#ifdef TARGET_NR_vmsplice
12316 case TARGET_NR_vmsplice:
12317 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012318 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12319 if (vec != NULL) {
12320 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12321 unlock_iovec(vec, arg2, arg3, 0);
12322 } else {
12323 ret = -host_to_target_errno(errno);
12324 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012325 }
12326 break;
12327#endif
12328#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012329#ifdef CONFIG_EVENTFD
12330#if defined(TARGET_NR_eventfd)
12331 case TARGET_NR_eventfd:
12332 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012333 if (ret >= 0) {
12334 fd_trans_register(ret, &target_eventfd_trans);
12335 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012336 break;
12337#endif
12338#if defined(TARGET_NR_eventfd2)
12339 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012340 {
12341 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12342 if (arg2 & TARGET_O_NONBLOCK) {
12343 host_flags |= O_NONBLOCK;
12344 }
12345 if (arg2 & TARGET_O_CLOEXEC) {
12346 host_flags |= O_CLOEXEC;
12347 }
12348 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012349 if (ret >= 0) {
12350 fd_trans_register(ret, &target_eventfd_trans);
12351 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012352 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012353 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012354#endif
12355#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012356#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12357 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012358#if TARGET_ABI_BITS == 32
12359 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12360 target_offset64(arg5, arg6)));
12361#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012362 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012363#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030012364 break;
12365#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012366#if defined(CONFIG_SYNC_FILE_RANGE)
12367#if defined(TARGET_NR_sync_file_range)
12368 case TARGET_NR_sync_file_range:
12369#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012370#if defined(TARGET_MIPS)
12371 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12372 target_offset64(arg5, arg6), arg7));
12373#else
Peter Maydellc727f472011-01-06 11:05:10 +000012374 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12375 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012376#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012377#else
12378 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12379#endif
12380 break;
12381#endif
12382#if defined(TARGET_NR_sync_file_range2)
12383 case TARGET_NR_sync_file_range2:
12384 /* This is like sync_file_range but the arguments are reordered */
12385#if TARGET_ABI_BITS == 32
12386 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12387 target_offset64(arg5, arg6), arg2));
12388#else
12389 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12390#endif
12391 break;
12392#endif
12393#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012394#if defined(TARGET_NR_signalfd4)
12395 case TARGET_NR_signalfd4:
12396 ret = do_signalfd4(arg1, arg2, arg4);
12397 break;
12398#endif
12399#if defined(TARGET_NR_signalfd)
12400 case TARGET_NR_signalfd:
12401 ret = do_signalfd4(arg1, arg2, 0);
12402 break;
12403#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012404#if defined(CONFIG_EPOLL)
12405#if defined(TARGET_NR_epoll_create)
12406 case TARGET_NR_epoll_create:
12407 ret = get_errno(epoll_create(arg1));
12408 break;
12409#endif
12410#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12411 case TARGET_NR_epoll_create1:
12412 ret = get_errno(epoll_create1(arg1));
12413 break;
12414#endif
12415#if defined(TARGET_NR_epoll_ctl)
12416 case TARGET_NR_epoll_ctl:
12417 {
12418 struct epoll_event ep;
12419 struct epoll_event *epp = 0;
12420 if (arg4) {
12421 struct target_epoll_event *target_ep;
12422 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
12423 goto efault;
12424 }
12425 ep.events = tswap32(target_ep->events);
12426 /* The epoll_data_t union is just opaque data to the kernel,
12427 * so we transfer all 64 bits across and need not worry what
12428 * actual data type it is.
12429 */
12430 ep.data.u64 = tswap64(target_ep->data.u64);
12431 unlock_user_struct(target_ep, arg4, 0);
12432 epp = &ep;
12433 }
12434 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12435 break;
12436 }
12437#endif
12438
Peter Maydell227f0212016-06-06 19:58:11 +010012439#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012440#if defined(TARGET_NR_epoll_wait)
12441 case TARGET_NR_epoll_wait:
12442#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012443#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012444 case TARGET_NR_epoll_pwait:
12445#endif
12446 {
12447 struct target_epoll_event *target_ep;
12448 struct epoll_event *ep;
12449 int epfd = arg1;
12450 int maxevents = arg3;
12451 int timeout = arg4;
12452
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012453 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12454 ret = -TARGET_EINVAL;
12455 break;
12456 }
12457
Peter Maydell3b6edd12011-02-15 18:35:05 +000012458 target_ep = lock_user(VERIFY_WRITE, arg2,
12459 maxevents * sizeof(struct target_epoll_event), 1);
12460 if (!target_ep) {
12461 goto efault;
12462 }
12463
Peter Maydell04c95f42016-07-18 15:36:00 +010012464 ep = g_try_new(struct epoll_event, maxevents);
12465 if (!ep) {
12466 unlock_user(target_ep, arg2, 0);
12467 ret = -TARGET_ENOMEM;
12468 break;
12469 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012470
12471 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012472#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012473 case TARGET_NR_epoll_pwait:
12474 {
12475 target_sigset_t *target_set;
12476 sigset_t _set, *set = &_set;
12477
12478 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012479 if (arg6 != sizeof(target_sigset_t)) {
12480 ret = -TARGET_EINVAL;
12481 break;
12482 }
12483
Peter Maydell3b6edd12011-02-15 18:35:05 +000012484 target_set = lock_user(VERIFY_READ, arg5,
12485 sizeof(target_sigset_t), 1);
12486 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012487 ret = -TARGET_EFAULT;
12488 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012489 }
12490 target_to_host_sigset(set, target_set);
12491 unlock_user(target_set, arg5, 0);
12492 } else {
12493 set = NULL;
12494 }
12495
Peter Maydell227f0212016-06-06 19:58:11 +010012496 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12497 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012498 break;
12499 }
12500#endif
12501#if defined(TARGET_NR_epoll_wait)
12502 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012503 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12504 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012505 break;
12506#endif
12507 default:
12508 ret = -TARGET_ENOSYS;
12509 }
12510 if (!is_error(ret)) {
12511 int i;
12512 for (i = 0; i < ret; i++) {
12513 target_ep[i].events = tswap32(ep[i].events);
12514 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12515 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012516 unlock_user(target_ep, arg2,
12517 ret * sizeof(struct target_epoll_event));
12518 } else {
12519 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012520 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012521 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012522 break;
12523 }
12524#endif
12525#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012526#ifdef TARGET_NR_prlimit64
12527 case TARGET_NR_prlimit64:
12528 {
12529 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12530 struct target_rlimit64 *target_rnew, *target_rold;
12531 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012532 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012533 if (arg3) {
12534 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12535 goto efault;
12536 }
12537 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12538 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12539 unlock_user_struct(target_rnew, arg3, 0);
12540 rnewp = &rnew;
12541 }
12542
Felix Janda95018012014-12-02 22:11:17 +010012543 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012544 if (!is_error(ret) && arg4) {
12545 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12546 goto efault;
12547 }
12548 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12549 target_rold->rlim_max = tswap64(rold.rlim_max);
12550 unlock_user_struct(target_rold, arg4, 1);
12551 }
12552 break;
12553 }
12554#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012555#ifdef TARGET_NR_gethostname
12556 case TARGET_NR_gethostname:
12557 {
12558 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12559 if (name) {
12560 ret = get_errno(gethostname(name, arg2));
12561 unlock_user(name, arg1, arg2);
12562 } else {
12563 ret = -TARGET_EFAULT;
12564 }
12565 break;
12566 }
12567#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012568#ifdef TARGET_NR_atomic_cmpxchg_32
12569 case TARGET_NR_atomic_cmpxchg_32:
12570 {
12571 /* should use start_exclusive from main.c */
12572 abi_ulong mem_value;
12573 if (get_user_u32(mem_value, arg6)) {
12574 target_siginfo_t info;
12575 info.si_signo = SIGSEGV;
12576 info.si_errno = 0;
12577 info.si_code = TARGET_SEGV_MAPERR;
12578 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012579 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12580 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012581 ret = 0xdeadbeef;
12582
12583 }
12584 if (mem_value == arg2)
12585 put_user_u32(arg1, arg6);
12586 ret = mem_value;
12587 break;
12588 }
12589#endif
12590#ifdef TARGET_NR_atomic_barrier
12591 case TARGET_NR_atomic_barrier:
12592 {
12593 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012594 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012595 break;
12596 }
12597#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012598
12599#ifdef TARGET_NR_timer_create
12600 case TARGET_NR_timer_create:
12601 {
12602 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12603
12604 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012605
12606 int clkid = arg1;
12607 int timer_index = next_free_host_timer();
12608
12609 if (timer_index < 0) {
12610 ret = -TARGET_EAGAIN;
12611 } else {
12612 timer_t *phtimer = g_posix_timers + timer_index;
12613
12614 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012615 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012616 ret = target_to_host_sigevent(phost_sevp, arg2);
12617 if (ret != 0) {
12618 break;
12619 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012620 }
12621
12622 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12623 if (ret) {
12624 phtimer = NULL;
12625 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012626 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012627 goto efault;
12628 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012629 }
12630 }
12631 break;
12632 }
12633#endif
12634
12635#ifdef TARGET_NR_timer_settime
12636 case TARGET_NR_timer_settime:
12637 {
12638 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12639 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012640 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012641
Alexander Grafaecc8862014-11-10 21:33:03 +010012642 if (timerid < 0) {
12643 ret = timerid;
12644 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012645 ret = -TARGET_EINVAL;
12646 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012647 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012648 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12649
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012650 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12651 goto efault;
12652 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012653 ret = get_errno(
12654 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012655 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12656 goto efault;
12657 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012658 }
12659 break;
12660 }
12661#endif
12662
12663#ifdef TARGET_NR_timer_gettime
12664 case TARGET_NR_timer_gettime:
12665 {
12666 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012667 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012668
Alexander Grafaecc8862014-11-10 21:33:03 +010012669 if (timerid < 0) {
12670 ret = timerid;
12671 } else if (!arg2) {
12672 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012673 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012674 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012675 struct itimerspec hspec;
12676 ret = get_errno(timer_gettime(htimer, &hspec));
12677
12678 if (host_to_target_itimerspec(arg2, &hspec)) {
12679 ret = -TARGET_EFAULT;
12680 }
12681 }
12682 break;
12683 }
12684#endif
12685
12686#ifdef TARGET_NR_timer_getoverrun
12687 case TARGET_NR_timer_getoverrun:
12688 {
12689 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012690 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012691
Alexander Grafaecc8862014-11-10 21:33:03 +010012692 if (timerid < 0) {
12693 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012694 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012695 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012696 ret = get_errno(timer_getoverrun(htimer));
12697 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012698 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012699 break;
12700 }
12701#endif
12702
12703#ifdef TARGET_NR_timer_delete
12704 case TARGET_NR_timer_delete:
12705 {
12706 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012707 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012708
Alexander Grafaecc8862014-11-10 21:33:03 +010012709 if (timerid < 0) {
12710 ret = timerid;
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 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012714 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012715 }
12716 break;
12717 }
12718#endif
12719
Riku Voipio51834342014-06-22 11:25:42 +010012720#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12721 case TARGET_NR_timerfd_create:
12722 ret = get_errno(timerfd_create(arg1,
12723 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12724 break;
12725#endif
12726
12727#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12728 case TARGET_NR_timerfd_gettime:
12729 {
12730 struct itimerspec its_curr;
12731
12732 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12733
12734 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12735 goto efault;
12736 }
12737 }
12738 break;
12739#endif
12740
12741#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12742 case TARGET_NR_timerfd_settime:
12743 {
12744 struct itimerspec its_new, its_old, *p_new;
12745
12746 if (arg3) {
12747 if (target_to_host_itimerspec(&its_new, arg3)) {
12748 goto efault;
12749 }
12750 p_new = &its_new;
12751 } else {
12752 p_new = NULL;
12753 }
12754
12755 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12756
12757 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12758 goto efault;
12759 }
12760 }
12761 break;
12762#endif
12763
Paul Burtonab31cda2014-06-22 11:25:43 +010012764#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12765 case TARGET_NR_ioprio_get:
12766 ret = get_errno(ioprio_get(arg1, arg2));
12767 break;
12768#endif
12769
12770#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12771 case TARGET_NR_ioprio_set:
12772 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12773 break;
12774#endif
12775
Riku Voipio9af5c902014-08-12 15:58:57 +030012776#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12777 case TARGET_NR_setns:
12778 ret = get_errno(setns(arg1, arg2));
12779 break;
12780#endif
12781#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12782 case TARGET_NR_unshare:
12783 ret = get_errno(unshare(arg1));
12784 break;
12785#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012786#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12787 case TARGET_NR_kcmp:
12788 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12789 break;
12790#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012791
bellard31e31b82003-02-18 22:55:36 +000012792 default:
12793 unimplemented:
Philippe Mathieu-Daudé122f9c82018-07-06 12:51:25 -030012794 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012795#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 +000012796 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012797#endif
ths0da46a62007-10-20 20:23:07 +000012798 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012799 break;
12800 }
bellard579a97f2007-11-11 14:26:47 +000012801fail:
bellardc573ff62004-01-04 15:51:36 +000012802#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012803 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012804#endif
thsb92c47c2007-11-01 00:07:38 +000012805 if(do_strace)
12806 print_syscall_ret(num, ret);
Lluís Vilanova9c15e702016-06-21 15:52:04 +020012807 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012808 return ret;
bellard579a97f2007-11-11 14:26:47 +000012809efault:
12810 ret = -TARGET_EFAULT;
12811 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012812}