blob: 404be44ad55151008fe570615d4dffab1d4d22ae [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,
408 QEMU___IFLA_BR_MAX,
409};
410
411enum {
412 QEMU_IFLA_UNSPEC,
413 QEMU_IFLA_ADDRESS,
414 QEMU_IFLA_BROADCAST,
415 QEMU_IFLA_IFNAME,
416 QEMU_IFLA_MTU,
417 QEMU_IFLA_LINK,
418 QEMU_IFLA_QDISC,
419 QEMU_IFLA_STATS,
420 QEMU_IFLA_COST,
421 QEMU_IFLA_PRIORITY,
422 QEMU_IFLA_MASTER,
423 QEMU_IFLA_WIRELESS,
424 QEMU_IFLA_PROTINFO,
425 QEMU_IFLA_TXQLEN,
426 QEMU_IFLA_MAP,
427 QEMU_IFLA_WEIGHT,
428 QEMU_IFLA_OPERSTATE,
429 QEMU_IFLA_LINKMODE,
430 QEMU_IFLA_LINKINFO,
431 QEMU_IFLA_NET_NS_PID,
432 QEMU_IFLA_IFALIAS,
433 QEMU_IFLA_NUM_VF,
434 QEMU_IFLA_VFINFO_LIST,
435 QEMU_IFLA_STATS64,
436 QEMU_IFLA_VF_PORTS,
437 QEMU_IFLA_PORT_SELF,
438 QEMU_IFLA_AF_SPEC,
439 QEMU_IFLA_GROUP,
440 QEMU_IFLA_NET_NS_FD,
441 QEMU_IFLA_EXT_MASK,
442 QEMU_IFLA_PROMISCUITY,
443 QEMU_IFLA_NUM_TX_QUEUES,
444 QEMU_IFLA_NUM_RX_QUEUES,
445 QEMU_IFLA_CARRIER,
446 QEMU_IFLA_PHYS_PORT_ID,
447 QEMU_IFLA_CARRIER_CHANGES,
448 QEMU_IFLA_PHYS_SWITCH_ID,
449 QEMU_IFLA_LINK_NETNSID,
450 QEMU_IFLA_PHYS_PORT_NAME,
451 QEMU_IFLA_PROTO_DOWN,
452 QEMU_IFLA_GSO_MAX_SEGS,
453 QEMU_IFLA_GSO_MAX_SIZE,
454 QEMU_IFLA_PAD,
455 QEMU_IFLA_XDP,
456 QEMU___IFLA_MAX
457};
458
459enum {
460 QEMU_IFLA_BRPORT_UNSPEC,
461 QEMU_IFLA_BRPORT_STATE,
462 QEMU_IFLA_BRPORT_PRIORITY,
463 QEMU_IFLA_BRPORT_COST,
464 QEMU_IFLA_BRPORT_MODE,
465 QEMU_IFLA_BRPORT_GUARD,
466 QEMU_IFLA_BRPORT_PROTECT,
467 QEMU_IFLA_BRPORT_FAST_LEAVE,
468 QEMU_IFLA_BRPORT_LEARNING,
469 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
470 QEMU_IFLA_BRPORT_PROXYARP,
471 QEMU_IFLA_BRPORT_LEARNING_SYNC,
472 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
473 QEMU_IFLA_BRPORT_ROOT_ID,
474 QEMU_IFLA_BRPORT_BRIDGE_ID,
475 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
476 QEMU_IFLA_BRPORT_DESIGNATED_COST,
477 QEMU_IFLA_BRPORT_ID,
478 QEMU_IFLA_BRPORT_NO,
479 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
480 QEMU_IFLA_BRPORT_CONFIG_PENDING,
481 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
482 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
483 QEMU_IFLA_BRPORT_HOLD_TIMER,
484 QEMU_IFLA_BRPORT_FLUSH,
485 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
486 QEMU_IFLA_BRPORT_PAD,
487 QEMU___IFLA_BRPORT_MAX
488};
489
490enum {
491 QEMU_IFLA_INFO_UNSPEC,
492 QEMU_IFLA_INFO_KIND,
493 QEMU_IFLA_INFO_DATA,
494 QEMU_IFLA_INFO_XSTATS,
495 QEMU_IFLA_INFO_SLAVE_KIND,
496 QEMU_IFLA_INFO_SLAVE_DATA,
497 QEMU___IFLA_INFO_MAX,
498};
499
500enum {
501 QEMU_IFLA_INET_UNSPEC,
502 QEMU_IFLA_INET_CONF,
503 QEMU___IFLA_INET_MAX,
504};
505
506enum {
507 QEMU_IFLA_INET6_UNSPEC,
508 QEMU_IFLA_INET6_FLAGS,
509 QEMU_IFLA_INET6_CONF,
510 QEMU_IFLA_INET6_STATS,
511 QEMU_IFLA_INET6_MCAST,
512 QEMU_IFLA_INET6_CACHEINFO,
513 QEMU_IFLA_INET6_ICMP6STATS,
514 QEMU_IFLA_INET6_TOKEN,
515 QEMU_IFLA_INET6_ADDR_GEN_MODE,
516 QEMU___IFLA_INET6_MAX
517};
518
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100519typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100520typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200521typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100522 TargetFdDataFunc host_to_target_data;
523 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100524 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200525} TargetFdTrans;
526
527static TargetFdTrans **target_fd_trans;
528
529static unsigned int target_fd_max;
530
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200531static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
532{
533 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
534 return target_fd_trans[fd]->target_to_host_data;
535 }
536 return NULL;
537}
538
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100539static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200540{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100541 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100542 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200543 }
544 return NULL;
545}
546
Laurent Vivier7b36f782015-10-28 21:40:44 +0100547static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
548{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100549 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100550 return target_fd_trans[fd]->target_to_host_addr;
551 }
552 return NULL;
553}
554
Laurent Viviere36800c2015-10-02 14:48:09 +0200555static void fd_trans_register(int fd, TargetFdTrans *trans)
556{
557 unsigned int oldmax;
558
559 if (fd >= target_fd_max) {
560 oldmax = target_fd_max;
561 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100562 target_fd_trans = g_renew(TargetFdTrans *,
563 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200564 memset((void *)(target_fd_trans + oldmax), 0,
565 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
566 }
567 target_fd_trans[fd] = trans;
568}
569
570static void fd_trans_unregister(int fd)
571{
572 if (fd >= 0 && fd < target_fd_max) {
573 target_fd_trans[fd] = NULL;
574 }
575}
576
577static void fd_trans_dup(int oldfd, int newfd)
578{
579 fd_trans_unregister(newfd);
580 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
581 fd_trans_register(newfd, target_fd_trans[oldfd]);
582 }
583}
584
aurel323b3f24a2009-04-15 16:12:13 +0000585static int sys_getcwd1(char *buf, size_t size)
586{
587 if (getcwd(buf, size) == NULL) {
588 /* getcwd() sets errno */
589 return (-1);
590 }
aurel32aaf4ad32009-04-16 14:17:14 +0000591 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000592}
593
Peter Maydell1acae9f2013-07-02 14:04:12 +0100594#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100595#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100596#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000597_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
598 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100599#else
600static int sys_utimensat(int dirfd, const char *pathname,
601 const struct timespec times[2], int flags)
602{
603 errno = ENOSYS;
604 return -1;
605}
ths9007f0e2007-09-25 17:50:37 +0000606#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100607#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000608
Andreas Schwab95d03072018-01-23 11:53:31 +0100609#ifdef TARGET_NR_renameat2
610#if defined(__NR_renameat2)
611#define __NR_sys_renameat2 __NR_renameat2
612_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
613 const char *, new, unsigned int, flags)
614#else
615static int sys_renameat2(int oldfd, const char *old,
616 int newfd, const char *new, int flags)
617{
618 if (flags == 0) {
619 return renameat(oldfd, old, newfd, new);
620 }
621 errno = ENOSYS;
622 return -1;
623}
624#endif
625#endif /* TARGET_NR_renameat2 */
626
aurel323b3f24a2009-04-15 16:12:13 +0000627#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000628#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000629
aurel3239b59762008-10-01 21:46:50 +0000630#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000631static int sys_inotify_init(void)
632{
633 return (inotify_init());
634}
aurel3239b59762008-10-01 21:46:50 +0000635#endif
636#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000637static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
638{
639 return (inotify_add_watch(fd, pathname, mask));
640}
aurel3239b59762008-10-01 21:46:50 +0000641#endif
642#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000643static int sys_inotify_rm_watch(int fd, int32_t wd)
644{
aurel328690e422009-04-17 13:50:32 +0000645 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000646}
aurel3239b59762008-10-01 21:46:50 +0000647#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000648#ifdef CONFIG_INOTIFY1
649#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
650static int sys_inotify_init1(int flags)
651{
652 return (inotify_init1(flags));
653}
654#endif
655#endif
aurel323b3f24a2009-04-15 16:12:13 +0000656#else
657/* Userspace can usually survive runtime without inotify */
658#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000659#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000660#undef TARGET_NR_inotify_add_watch
661#undef TARGET_NR_inotify_rm_watch
662#endif /* CONFIG_INOTIFY */
663
Peter Maydell163a05a2011-06-27 17:44:52 +0100664#if defined(TARGET_NR_prlimit64)
665#ifndef __NR_prlimit64
666# define __NR_prlimit64 -1
667#endif
668#define __NR_sys_prlimit64 __NR_prlimit64
669/* The glibc rlimit structure may not be that used by the underlying syscall */
670struct host_rlimit64 {
671 uint64_t rlim_cur;
672 uint64_t rlim_max;
673};
674_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
675 const struct host_rlimit64 *, new_limit,
676 struct host_rlimit64 *, old_limit)
677#endif
678
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100679
680#if defined(TARGET_NR_timer_create)
681/* Maxiumum of 32 active POSIX timers allowed at any one time. */
682static timer_t g_posix_timers[32] = { 0, } ;
683
684static inline int next_free_host_timer(void)
685{
686 int k ;
687 /* FIXME: Does finding the next free slot require a lock? */
688 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
689 if (g_posix_timers[k] == 0) {
690 g_posix_timers[k] = (timer_t) 1;
691 return k;
692 }
693 }
694 return -1;
695}
696#endif
697
Riku Voipio48e515d2011-07-12 15:40:51 +0300698/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000699#ifdef TARGET_ARM
James Clarke8bf8e9d2017-09-15 20:33:13 +0100700static inline int regpairs_aligned(void *cpu_env, int num)
701{
Riku Voipio48e515d2011-07-12 15:40:51 +0300702 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
703}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200704#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
James Clarke8bf8e9d2017-09-15 20:33:13 +0100705static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000706#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
707/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
708 * of registers which translates to the same as ARM/MIPS, because we start with
709 * r3 as arg1 */
James Clarke8bf8e9d2017-09-15 20:33:13 +0100710static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
711#elif defined(TARGET_SH4)
712/* SH4 doesn't align register pairs, except for p{read,write}64 */
713static inline int regpairs_aligned(void *cpu_env, int num)
714{
715 switch (num) {
716 case TARGET_NR_pread64:
717 case TARGET_NR_pwrite64:
718 return 1;
719
720 default:
721 return 0;
722 }
723}
Max Filippovba7651f2017-01-25 10:54:11 -0800724#elif defined(TARGET_XTENSA)
725static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300726#else
James Clarke8bf8e9d2017-09-15 20:33:13 +0100727static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300728#endif
729
thsb92c47c2007-11-01 00:07:38 +0000730#define ERRNO_TABLE_SIZE 1200
731
732/* target_to_host_errno_table[] is initialized from
733 * host_to_target_errno_table[] in syscall_init(). */
734static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
735};
736
ths637947f2007-06-01 12:09:19 +0000737/*
thsfe8f0962007-07-12 10:59:21 +0000738 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000739 * minus the errnos that are not actually generic to all archs.
740 */
thsb92c47c2007-11-01 00:07:38 +0000741static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800742 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000743 [EIDRM] = TARGET_EIDRM,
744 [ECHRNG] = TARGET_ECHRNG,
745 [EL2NSYNC] = TARGET_EL2NSYNC,
746 [EL3HLT] = TARGET_EL3HLT,
747 [EL3RST] = TARGET_EL3RST,
748 [ELNRNG] = TARGET_ELNRNG,
749 [EUNATCH] = TARGET_EUNATCH,
750 [ENOCSI] = TARGET_ENOCSI,
751 [EL2HLT] = TARGET_EL2HLT,
752 [EDEADLK] = TARGET_EDEADLK,
753 [ENOLCK] = TARGET_ENOLCK,
754 [EBADE] = TARGET_EBADE,
755 [EBADR] = TARGET_EBADR,
756 [EXFULL] = TARGET_EXFULL,
757 [ENOANO] = TARGET_ENOANO,
758 [EBADRQC] = TARGET_EBADRQC,
759 [EBADSLT] = TARGET_EBADSLT,
760 [EBFONT] = TARGET_EBFONT,
761 [ENOSTR] = TARGET_ENOSTR,
762 [ENODATA] = TARGET_ENODATA,
763 [ETIME] = TARGET_ETIME,
764 [ENOSR] = TARGET_ENOSR,
765 [ENONET] = TARGET_ENONET,
766 [ENOPKG] = TARGET_ENOPKG,
767 [EREMOTE] = TARGET_EREMOTE,
768 [ENOLINK] = TARGET_ENOLINK,
769 [EADV] = TARGET_EADV,
770 [ESRMNT] = TARGET_ESRMNT,
771 [ECOMM] = TARGET_ECOMM,
772 [EPROTO] = TARGET_EPROTO,
773 [EDOTDOT] = TARGET_EDOTDOT,
774 [EMULTIHOP] = TARGET_EMULTIHOP,
775 [EBADMSG] = TARGET_EBADMSG,
776 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
777 [EOVERFLOW] = TARGET_EOVERFLOW,
778 [ENOTUNIQ] = TARGET_ENOTUNIQ,
779 [EBADFD] = TARGET_EBADFD,
780 [EREMCHG] = TARGET_EREMCHG,
781 [ELIBACC] = TARGET_ELIBACC,
782 [ELIBBAD] = TARGET_ELIBBAD,
783 [ELIBSCN] = TARGET_ELIBSCN,
784 [ELIBMAX] = TARGET_ELIBMAX,
785 [ELIBEXEC] = TARGET_ELIBEXEC,
786 [EILSEQ] = TARGET_EILSEQ,
787 [ENOSYS] = TARGET_ENOSYS,
788 [ELOOP] = TARGET_ELOOP,
789 [ERESTART] = TARGET_ERESTART,
790 [ESTRPIPE] = TARGET_ESTRPIPE,
791 [ENOTEMPTY] = TARGET_ENOTEMPTY,
792 [EUSERS] = TARGET_EUSERS,
793 [ENOTSOCK] = TARGET_ENOTSOCK,
794 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
795 [EMSGSIZE] = TARGET_EMSGSIZE,
796 [EPROTOTYPE] = TARGET_EPROTOTYPE,
797 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
798 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
799 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
800 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
801 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
802 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
803 [EADDRINUSE] = TARGET_EADDRINUSE,
804 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
805 [ENETDOWN] = TARGET_ENETDOWN,
806 [ENETUNREACH] = TARGET_ENETUNREACH,
807 [ENETRESET] = TARGET_ENETRESET,
808 [ECONNABORTED] = TARGET_ECONNABORTED,
809 [ECONNRESET] = TARGET_ECONNRESET,
810 [ENOBUFS] = TARGET_ENOBUFS,
811 [EISCONN] = TARGET_EISCONN,
812 [ENOTCONN] = TARGET_ENOTCONN,
813 [EUCLEAN] = TARGET_EUCLEAN,
814 [ENOTNAM] = TARGET_ENOTNAM,
815 [ENAVAIL] = TARGET_ENAVAIL,
816 [EISNAM] = TARGET_EISNAM,
817 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200818 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000819 [ESHUTDOWN] = TARGET_ESHUTDOWN,
820 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
821 [ETIMEDOUT] = TARGET_ETIMEDOUT,
822 [ECONNREFUSED] = TARGET_ECONNREFUSED,
823 [EHOSTDOWN] = TARGET_EHOSTDOWN,
824 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
825 [EALREADY] = TARGET_EALREADY,
826 [EINPROGRESS] = TARGET_EINPROGRESS,
827 [ESTALE] = TARGET_ESTALE,
828 [ECANCELED] = TARGET_ECANCELED,
829 [ENOMEDIUM] = TARGET_ENOMEDIUM,
830 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000831#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000832 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000833#endif
834#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000835 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000836#endif
837#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000838 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000839#endif
840#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000841 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000842#endif
843#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000844 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000845#endif
846#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000847 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000848#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200849#ifdef ENOMSG
850 [ENOMSG] = TARGET_ENOMSG,
851#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800852#ifdef ERKFILL
853 [ERFKILL] = TARGET_ERFKILL,
854#endif
855#ifdef EHWPOISON
856 [EHWPOISON] = TARGET_EHWPOISON,
857#endif
thsb92c47c2007-11-01 00:07:38 +0000858};
ths637947f2007-06-01 12:09:19 +0000859
860static inline int host_to_target_errno(int err)
861{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100862 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
863 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000864 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100865 }
ths637947f2007-06-01 12:09:19 +0000866 return err;
867}
868
thsb92c47c2007-11-01 00:07:38 +0000869static inline int target_to_host_errno(int err)
870{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100871 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
872 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000873 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100874 }
thsb92c47c2007-11-01 00:07:38 +0000875 return err;
876}
877
blueswir1992f48a2007-10-14 16:27:31 +0000878static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000879{
880 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000881 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000882 else
883 return ret;
884}
885
blueswir1992f48a2007-10-14 16:27:31 +0000886static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000887{
blueswir1992f48a2007-10-14 16:27:31 +0000888 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000889}
890
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100891const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000892{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100893 if (err == TARGET_ERESTARTSYS) {
894 return "To be restarted";
895 }
896 if (err == TARGET_QEMU_ESIGRETURN) {
897 return "Successful exit from sigreturn";
898 }
899
Alexander Graf962b2892011-11-21 12:04:07 +0100900 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
901 return NULL;
902 }
thsb92c47c2007-11-01 00:07:38 +0000903 return strerror(target_to_host_errno(err));
904}
905
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100906#define safe_syscall0(type, name) \
907static type safe_##name(void) \
908{ \
909 return safe_syscall(__NR_##name); \
910}
911
912#define safe_syscall1(type, name, type1, arg1) \
913static type safe_##name(type1 arg1) \
914{ \
915 return safe_syscall(__NR_##name, arg1); \
916}
917
918#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
919static type safe_##name(type1 arg1, type2 arg2) \
920{ \
921 return safe_syscall(__NR_##name, arg1, arg2); \
922}
923
924#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
925static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
926{ \
927 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
928}
929
930#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
931 type4, arg4) \
932static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
933{ \
934 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
935}
936
937#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
938 type4, arg4, type5, arg5) \
939static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
940 type5 arg5) \
941{ \
942 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
943}
944
945#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
946 type4, arg4, type5, arg5, type6, arg6) \
947static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
948 type5 arg5, type6 arg6) \
949{ \
950 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
951}
952
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100953safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
954safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100955safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
956 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100957safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
958 struct rusage *, rusage)
959safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
960 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100961safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100962safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
963 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100964safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
965 struct timespec *, tsp, const sigset_t *, sigmask,
966 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100967safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
968 int, maxevents, int, timeout, const sigset_t *, sigmask,
969 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100970safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
971 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100972safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100973safe_syscall2(int, kill, pid_t, pid, int, sig)
974safe_syscall2(int, tkill, int, tid, int, sig)
975safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100976safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
977safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200978safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
979 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200980safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
981 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100982safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
983 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100984safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
985 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
986safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
987 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
988safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
989safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100990safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100991safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
992 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100993safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
994 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100995safe_syscall2(int, nanosleep, const struct timespec *, req,
996 struct timespec *, rem)
997#ifdef TARGET_NR_clock_nanosleep
998safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
999 const struct timespec *, req, struct timespec *, rem)
1000#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +01001001#ifdef __NR_msgsnd
1002safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
1003 int, flags)
1004safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
1005 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +01001006safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
1007 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +01001008#else
1009/* This host kernel architecture uses a single ipc syscall; fake up
1010 * wrappers for the sub-operations to hide this implementation detail.
1011 * Annoyingly we can't include linux/ipc.h to get the constant definitions
1012 * for the call parameter because some structs in there conflict with the
1013 * sys/ipc.h ones. So we just define them here, and rely on them being
1014 * the same for all host architectures.
1015 */
Peter Maydellffb7ee72016-06-06 19:58:12 +01001016#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +01001017#define Q_MSGSND 11
1018#define Q_MSGRCV 12
1019#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
1020
1021safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
1022 void *, ptr, long, fifth)
1023static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
1024{
1025 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
1026}
1027static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
1028{
1029 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
1030}
Peter Maydellffb7ee72016-06-06 19:58:12 +01001031static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
1032 const struct timespec *timeout)
1033{
1034 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
1035 (long)timeout);
1036}
Peter Maydell89f9fe42016-06-06 19:58:05 +01001037#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +01001038#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1039safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
1040 size_t, len, unsigned, prio, const struct timespec *, timeout)
1041safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
1042 size_t, len, unsigned *, prio, const struct timespec *, timeout)
1043#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +01001044/* We do ioctl like this rather than via safe_syscall3 to preserve the
1045 * "third argument might be integer or pointer or not present" behaviour of
1046 * the libc function.
1047 */
1048#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +01001049/* Similarly for fcntl. Note that callers must always:
1050 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1051 * use the flock64 struct rather than unsuffixed flock
1052 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1053 */
1054#ifdef __NR_fcntl64
1055#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1056#else
1057#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1058#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001059
Paul Burton8289d112014-06-22 11:25:33 +01001060static inline int host_to_target_sock_type(int host_type)
1061{
1062 int target_type;
1063
1064 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1065 case SOCK_DGRAM:
1066 target_type = TARGET_SOCK_DGRAM;
1067 break;
1068 case SOCK_STREAM:
1069 target_type = TARGET_SOCK_STREAM;
1070 break;
1071 default:
1072 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1073 break;
1074 }
1075
1076#if defined(SOCK_CLOEXEC)
1077 if (host_type & SOCK_CLOEXEC) {
1078 target_type |= TARGET_SOCK_CLOEXEC;
1079 }
1080#endif
1081
1082#if defined(SOCK_NONBLOCK)
1083 if (host_type & SOCK_NONBLOCK) {
1084 target_type |= TARGET_SOCK_NONBLOCK;
1085 }
1086#endif
1087
1088 return target_type;
1089}
1090
blueswir1992f48a2007-10-14 16:27:31 +00001091static abi_ulong target_brk;
1092static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001093static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001094
blueswir1992f48a2007-10-14 16:27:31 +00001095void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001096{
blueswir14c1de732007-07-07 20:45:44 +00001097 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001098 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001099}
1100
vincent4d1de872011-06-14 21:56:33 +00001101//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1102#define DEBUGF_BRK(message, args...)
1103
ths0da46a62007-10-20 20:23:07 +00001104/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001105abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001106{
blueswir1992f48a2007-10-14 16:27:31 +00001107 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001108 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001109
Paul Brook3a0c6c42012-02-09 19:04:27 +00001110 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001111
vincent4d1de872011-06-14 21:56:33 +00001112 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001113 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001114 return target_brk;
1115 }
1116 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001117 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1118 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001119 return target_brk;
1120 }
bellard31e31b82003-02-18 22:55:36 +00001121
vincent4d1de872011-06-14 21:56:33 +00001122 /* If the new brk is less than the highest page reserved to the
1123 * target heap allocation, set it and we're almost done... */
1124 if (new_brk <= brk_page) {
1125 /* Heap contents are initialized to zero, as for anonymous
1126 * mapped pages. */
1127 if (new_brk > target_brk) {
1128 memset(g2h(target_brk), 0, new_brk - target_brk);
1129 }
bellard31e31b82003-02-18 22:55:36 +00001130 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001131 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001132 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001133 }
1134
Peter Maydell00faf082011-04-18 16:34:24 +01001135 /* We need to allocate more memory after the brk... Note that
1136 * we don't use MAP_FIXED because that will map over the top of
1137 * any existing mapping (like the one with the host libc or qemu
1138 * itself); instead we treat "mapped but at wrong address" as
1139 * a failure and unmap again.
1140 */
vincent4d1de872011-06-14 21:56:33 +00001141 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001142 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001143 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001144 MAP_ANON|MAP_PRIVATE, 0, 0));
1145
1146 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001147 /* Heap contents are initialized to zero, as for anonymous
1148 * mapped pages. Technically the new pages are already
1149 * initialized to zero since they *are* anonymous mapped
1150 * pages, however we have to take care with the contents that
1151 * come from the remaining part of the previous page: it may
1152 * contains garbage data due to a previous heap usage (grown
1153 * then shrunken). */
1154 memset(g2h(target_brk), 0, brk_page - target_brk);
1155
Peter Maydell00faf082011-04-18 16:34:24 +01001156 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001157 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001158 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1159 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001160 return target_brk;
1161 } else if (mapped_addr != -1) {
1162 /* Mapped but at wrong address, meaning there wasn't actually
1163 * enough space for this brk.
1164 */
1165 target_munmap(mapped_addr, new_alloc_size);
1166 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001167 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001168 }
1169 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001170 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001171 }
balrog7ab240a2008-04-26 12:17:34 +00001172
Richard Henderson7dd46c02010-05-03 10:07:49 -07001173#if defined(TARGET_ALPHA)
1174 /* We (partially) emulate OSF/1 on Alpha, which requires we
1175 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001176 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001177#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001178 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001179 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001180}
1181
ths26edcf42007-12-09 02:25:24 +00001182static inline abi_long copy_from_user_fdset(fd_set *fds,
1183 abi_ulong target_fds_addr,
1184 int n)
bellard31e31b82003-02-18 22:55:36 +00001185{
ths26edcf42007-12-09 02:25:24 +00001186 int i, nw, j, k;
1187 abi_ulong b, *target_fds;
1188
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001189 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001190 if (!(target_fds = lock_user(VERIFY_READ,
1191 target_fds_addr,
1192 sizeof(abi_ulong) * nw,
1193 1)))
1194 return -TARGET_EFAULT;
1195
1196 FD_ZERO(fds);
1197 k = 0;
1198 for (i = 0; i < nw; i++) {
1199 /* grab the abi_ulong */
1200 __get_user(b, &target_fds[i]);
1201 for (j = 0; j < TARGET_ABI_BITS; j++) {
1202 /* check the bit inside the abi_ulong */
1203 if ((b >> j) & 1)
1204 FD_SET(k, fds);
1205 k++;
bellard31e31b82003-02-18 22:55:36 +00001206 }
bellard31e31b82003-02-18 22:55:36 +00001207 }
ths26edcf42007-12-09 02:25:24 +00001208
1209 unlock_user(target_fds, target_fds_addr, 0);
1210
1211 return 0;
bellard31e31b82003-02-18 22:55:36 +00001212}
1213
Mike Frysinger055e0902011-06-03 17:01:49 -04001214static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1215 abi_ulong target_fds_addr,
1216 int n)
1217{
1218 if (target_fds_addr) {
1219 if (copy_from_user_fdset(fds, target_fds_addr, n))
1220 return -TARGET_EFAULT;
1221 *fds_ptr = fds;
1222 } else {
1223 *fds_ptr = NULL;
1224 }
1225 return 0;
1226}
1227
ths26edcf42007-12-09 02:25:24 +00001228static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1229 const fd_set *fds,
1230 int n)
bellard31e31b82003-02-18 22:55:36 +00001231{
bellard31e31b82003-02-18 22:55:36 +00001232 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001233 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001234 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001235
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001236 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001237 if (!(target_fds = lock_user(VERIFY_WRITE,
1238 target_fds_addr,
1239 sizeof(abi_ulong) * nw,
1240 0)))
1241 return -TARGET_EFAULT;
1242
1243 k = 0;
1244 for (i = 0; i < nw; i++) {
1245 v = 0;
1246 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001247 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001248 k++;
bellard31e31b82003-02-18 22:55:36 +00001249 }
ths26edcf42007-12-09 02:25:24 +00001250 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001251 }
ths26edcf42007-12-09 02:25:24 +00001252
1253 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1254
1255 return 0;
bellard31e31b82003-02-18 22:55:36 +00001256}
1257
bellardc596ed12003-07-13 17:32:31 +00001258#if defined(__alpha__)
1259#define HOST_HZ 1024
1260#else
1261#define HOST_HZ 100
1262#endif
1263
blueswir1992f48a2007-10-14 16:27:31 +00001264static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001265{
1266#if HOST_HZ == TARGET_HZ
1267 return ticks;
1268#else
1269 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1270#endif
1271}
1272
bellard579a97f2007-11-11 14:26:47 +00001273static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1274 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001275{
pbrook53a59602006-03-25 19:31:22 +00001276 struct target_rusage *target_rusage;
1277
bellard579a97f2007-11-11 14:26:47 +00001278 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1279 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001280 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1281 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1282 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1283 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1284 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1285 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1286 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1287 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1288 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1289 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1290 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1291 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1292 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1293 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1294 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1295 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1296 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1297 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001298 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001299
1300 return 0;
bellardb4091862003-05-16 15:39:34 +00001301}
1302
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001303static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001304{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001305 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001306 rlim_t result;
1307
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001308 target_rlim_swap = tswapal(target_rlim);
1309 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1310 return RLIM_INFINITY;
1311
1312 result = target_rlim_swap;
1313 if (target_rlim_swap != (rlim_t)result)
1314 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001315
1316 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001317}
1318
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001319static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001320{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001321 abi_ulong target_rlim_swap;
1322 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001323
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001324 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001325 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001326 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001327 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001328 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001329
1330 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001331}
1332
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001333static inline int target_to_host_resource(int code)
1334{
1335 switch (code) {
1336 case TARGET_RLIMIT_AS:
1337 return RLIMIT_AS;
1338 case TARGET_RLIMIT_CORE:
1339 return RLIMIT_CORE;
1340 case TARGET_RLIMIT_CPU:
1341 return RLIMIT_CPU;
1342 case TARGET_RLIMIT_DATA:
1343 return RLIMIT_DATA;
1344 case TARGET_RLIMIT_FSIZE:
1345 return RLIMIT_FSIZE;
1346 case TARGET_RLIMIT_LOCKS:
1347 return RLIMIT_LOCKS;
1348 case TARGET_RLIMIT_MEMLOCK:
1349 return RLIMIT_MEMLOCK;
1350 case TARGET_RLIMIT_MSGQUEUE:
1351 return RLIMIT_MSGQUEUE;
1352 case TARGET_RLIMIT_NICE:
1353 return RLIMIT_NICE;
1354 case TARGET_RLIMIT_NOFILE:
1355 return RLIMIT_NOFILE;
1356 case TARGET_RLIMIT_NPROC:
1357 return RLIMIT_NPROC;
1358 case TARGET_RLIMIT_RSS:
1359 return RLIMIT_RSS;
1360 case TARGET_RLIMIT_RTPRIO:
1361 return RLIMIT_RTPRIO;
1362 case TARGET_RLIMIT_SIGPENDING:
1363 return RLIMIT_SIGPENDING;
1364 case TARGET_RLIMIT_STACK:
1365 return RLIMIT_STACK;
1366 default:
1367 return code;
1368 }
1369}
1370
ths788f5ec2007-12-09 02:37:05 +00001371static inline abi_long copy_from_user_timeval(struct timeval *tv,
1372 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001373{
pbrook53a59602006-03-25 19:31:22 +00001374 struct target_timeval *target_tv;
1375
ths788f5ec2007-12-09 02:37:05 +00001376 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001377 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001378
1379 __get_user(tv->tv_sec, &target_tv->tv_sec);
1380 __get_user(tv->tv_usec, &target_tv->tv_usec);
1381
1382 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001383
1384 return 0;
bellard31e31b82003-02-18 22:55:36 +00001385}
1386
ths788f5ec2007-12-09 02:37:05 +00001387static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1388 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001389{
pbrook53a59602006-03-25 19:31:22 +00001390 struct target_timeval *target_tv;
1391
ths788f5ec2007-12-09 02:37:05 +00001392 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001393 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001394
1395 __put_user(tv->tv_sec, &target_tv->tv_sec);
1396 __put_user(tv->tv_usec, &target_tv->tv_usec);
1397
1398 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001399
1400 return 0;
bellard31e31b82003-02-18 22:55:36 +00001401}
1402
Paul Burtonef4467e2014-06-22 11:25:40 +01001403static inline abi_long copy_from_user_timezone(struct timezone *tz,
1404 abi_ulong target_tz_addr)
1405{
1406 struct target_timezone *target_tz;
1407
1408 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1409 return -TARGET_EFAULT;
1410 }
1411
1412 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1413 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1414
1415 unlock_user_struct(target_tz, target_tz_addr, 0);
1416
1417 return 0;
1418}
1419
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001420#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1421#include <mqueue.h>
1422
aurel3224e10032009-04-15 16:11:43 +00001423static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1424 abi_ulong target_mq_attr_addr)
1425{
1426 struct target_mq_attr *target_mq_attr;
1427
1428 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1429 target_mq_attr_addr, 1))
1430 return -TARGET_EFAULT;
1431
1432 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1433 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1434 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1435 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1436
1437 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1438
1439 return 0;
1440}
1441
1442static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1443 const struct mq_attr *attr)
1444{
1445 struct target_mq_attr *target_mq_attr;
1446
1447 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1448 target_mq_attr_addr, 0))
1449 return -TARGET_EFAULT;
1450
1451 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1452 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1453 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1454 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1455
1456 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1457
1458 return 0;
1459}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001460#endif
bellard31e31b82003-02-18 22:55:36 +00001461
Mike Frysinger055e0902011-06-03 17:01:49 -04001462#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001463/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001464static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001465 abi_ulong rfd_addr, abi_ulong wfd_addr,
1466 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001467{
1468 fd_set rfds, wfds, efds;
1469 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001470 struct timeval tv;
1471 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001472 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001473
Mike Frysinger055e0902011-06-03 17:01:49 -04001474 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1475 if (ret) {
1476 return ret;
pbrook53a59602006-03-25 19:31:22 +00001477 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001478 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1479 if (ret) {
1480 return ret;
pbrook53a59602006-03-25 19:31:22 +00001481 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001482 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1483 if (ret) {
1484 return ret;
pbrook53a59602006-03-25 19:31:22 +00001485 }
ths3b46e622007-09-17 08:09:54 +00001486
ths26edcf42007-12-09 02:25:24 +00001487 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001488 if (copy_from_user_timeval(&tv, target_tv_addr))
1489 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001490 ts.tv_sec = tv.tv_sec;
1491 ts.tv_nsec = tv.tv_usec * 1000;
1492 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001493 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001494 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001495 }
ths26edcf42007-12-09 02:25:24 +00001496
Peter Maydell6df9d382016-05-12 18:47:51 +01001497 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1498 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001499
ths26edcf42007-12-09 02:25:24 +00001500 if (!is_error(ret)) {
1501 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1502 return -TARGET_EFAULT;
1503 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1504 return -TARGET_EFAULT;
1505 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1506 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001507
Peter Maydell6df9d382016-05-12 18:47:51 +01001508 if (target_tv_addr) {
1509 tv.tv_sec = ts.tv_sec;
1510 tv.tv_usec = ts.tv_nsec / 1000;
1511 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1512 return -TARGET_EFAULT;
1513 }
1514 }
bellard31e31b82003-02-18 22:55:36 +00001515 }
bellard579a97f2007-11-11 14:26:47 +00001516
bellard31e31b82003-02-18 22:55:36 +00001517 return ret;
1518}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001519
1520#if defined(TARGET_WANT_OLD_SYS_SELECT)
1521static abi_long do_old_select(abi_ulong arg1)
1522{
1523 struct target_sel_arg_struct *sel;
1524 abi_ulong inp, outp, exp, tvp;
1525 long nsel;
1526
1527 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1528 return -TARGET_EFAULT;
1529 }
1530
1531 nsel = tswapal(sel->n);
1532 inp = tswapal(sel->inp);
1533 outp = tswapal(sel->outp);
1534 exp = tswapal(sel->exp);
1535 tvp = tswapal(sel->tvp);
1536
1537 unlock_user_struct(sel, arg1, 0);
1538
1539 return do_select(nsel, inp, outp, exp, tvp);
1540}
1541#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001542#endif
bellard31e31b82003-02-18 22:55:36 +00001543
Riku Voipio099d6b02009-05-05 12:10:04 +03001544static abi_long do_pipe2(int host_pipe[], int flags)
1545{
1546#ifdef CONFIG_PIPE2
1547 return pipe2(host_pipe, flags);
1548#else
1549 return -ENOSYS;
1550#endif
1551}
1552
Richard Hendersonfb41a662010-05-03 10:07:52 -07001553static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1554 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001555{
1556 int host_pipe[2];
1557 abi_long ret;
1558 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1559
1560 if (is_error(ret))
1561 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001562
1563 /* Several targets have special calling conventions for the original
1564 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1565 if (!is_pipe2) {
1566#if defined(TARGET_ALPHA)
1567 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1568 return host_pipe[0];
1569#elif defined(TARGET_MIPS)
1570 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1571 return host_pipe[0];
1572#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001573 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001574 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001575#elif defined(TARGET_SPARC)
1576 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1577 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001578#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001579 }
1580
Riku Voipio099d6b02009-05-05 12:10:04 +03001581 if (put_user_s32(host_pipe[0], pipedes)
1582 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1583 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001584 return get_errno(ret);
1585}
1586
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001587static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1588 abi_ulong target_addr,
1589 socklen_t len)
1590{
1591 struct target_ip_mreqn *target_smreqn;
1592
1593 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1594 if (!target_smreqn)
1595 return -TARGET_EFAULT;
1596 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1597 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1598 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001599 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001600 unlock_user(target_smreqn, target_addr, 0);
1601
1602 return 0;
1603}
1604
Laurent Vivier7b36f782015-10-28 21:40:44 +01001605static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001606 abi_ulong target_addr,
1607 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001608{
aurel32607175e2009-04-15 16:11:59 +00001609 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1610 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001611 struct target_sockaddr *target_saddr;
1612
Laurent Vivier7b36f782015-10-28 21:40:44 +01001613 if (fd_trans_target_to_host_addr(fd)) {
1614 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1615 }
1616
bellard579a97f2007-11-11 14:26:47 +00001617 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1618 if (!target_saddr)
1619 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001620
1621 sa_family = tswap16(target_saddr->sa_family);
1622
1623 /* Oops. The caller might send a incomplete sun_path; sun_path
1624 * must be terminated by \0 (see the manual page), but
1625 * unfortunately it is quite common to specify sockaddr_un
1626 * length as "strlen(x->sun_path)" while it should be
1627 * "strlen(...) + 1". We'll fix that here if needed.
1628 * Linux kernel has a similar feature.
1629 */
1630
1631 if (sa_family == AF_UNIX) {
1632 if (len < unix_maxlen && len > 0) {
1633 char *cp = (char*)target_saddr;
1634
1635 if ( cp[len-1] && !cp[len] )
1636 len++;
1637 }
1638 if (len > unix_maxlen)
1639 len = unix_maxlen;
1640 }
1641
pbrook53a59602006-03-25 19:31:22 +00001642 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001643 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001644 if (sa_family == AF_NETLINK) {
1645 struct sockaddr_nl *nladdr;
1646
1647 nladdr = (struct sockaddr_nl *)addr;
1648 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1649 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1650 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001651 struct target_sockaddr_ll *lladdr;
1652
1653 lladdr = (struct target_sockaddr_ll *)addr;
1654 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1655 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1656 }
pbrook53a59602006-03-25 19:31:22 +00001657 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001658
1659 return 0;
bellard7854b052003-03-29 17:22:23 +00001660}
1661
bellard579a97f2007-11-11 14:26:47 +00001662static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1663 struct sockaddr *addr,
1664 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001665{
pbrook53a59602006-03-25 19:31:22 +00001666 struct target_sockaddr *target_saddr;
1667
Peter Maydella1e22192016-07-07 15:44:43 +01001668 if (len == 0) {
1669 return 0;
1670 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001671 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001672
bellard579a97f2007-11-11 14:26:47 +00001673 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1674 if (!target_saddr)
1675 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001676 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001677 if (len >= offsetof(struct target_sockaddr, sa_family) +
1678 sizeof(target_saddr->sa_family)) {
1679 target_saddr->sa_family = tswap16(addr->sa_family);
1680 }
1681 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001682 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1683 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1684 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001685 } else if (addr->sa_family == AF_PACKET) {
1686 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1687 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1688 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001689 } else if (addr->sa_family == AF_INET6 &&
1690 len >= sizeof(struct target_sockaddr_in6)) {
1691 struct target_sockaddr_in6 *target_in6 =
1692 (struct target_sockaddr_in6 *)target_saddr;
1693 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001694 }
pbrook53a59602006-03-25 19:31:22 +00001695 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001696
1697 return 0;
bellard7854b052003-03-29 17:22:23 +00001698}
1699
bellard5a4a8982007-11-11 17:39:18 +00001700static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1701 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001702{
1703 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001704 abi_long msg_controllen;
1705 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001706 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001707 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001708
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001709 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001710 if (msg_controllen < sizeof (struct target_cmsghdr))
1711 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001712 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001713 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001714 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001715 if (!target_cmsg)
1716 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001717
1718 while (cmsg && target_cmsg) {
1719 void *data = CMSG_DATA(cmsg);
1720 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1721
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001722 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001723 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001724
1725 space += CMSG_SPACE(len);
1726 if (space > msgh->msg_controllen) {
1727 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001728 /* This is a QEMU bug, since we allocated the payload
1729 * area ourselves (unlike overflow in host-to-target
1730 * conversion, which is just the guest giving us a buffer
1731 * that's too small). It can't happen for the payload types
1732 * we currently support; if it becomes an issue in future
1733 * we would need to improve our allocation strategy to
1734 * something more intelligent than "twice the size of the
1735 * target buffer we're reading from".
1736 */
bellard31febb72005-12-18 20:03:27 +00001737 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001738 break;
1739 }
1740
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001741 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1742 cmsg->cmsg_level = SOL_SOCKET;
1743 } else {
1744 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1745 }
bellard7854b052003-03-29 17:22:23 +00001746 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1747 cmsg->cmsg_len = CMSG_LEN(len);
1748
Alex Suykov30b8b682014-12-23 07:52:58 +02001749 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001750 int *fd = (int *)data;
1751 int *target_fd = (int *)target_data;
1752 int i, numfds = len / sizeof(int);
1753
Peter Maydell876e23c2015-05-26 19:46:32 +01001754 for (i = 0; i < numfds; i++) {
1755 __get_user(fd[i], target_fd + i);
1756 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001757 } else if (cmsg->cmsg_level == SOL_SOCKET
1758 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1759 struct ucred *cred = (struct ucred *)data;
1760 struct target_ucred *target_cred =
1761 (struct target_ucred *)target_data;
1762
Peter Maydell876e23c2015-05-26 19:46:32 +01001763 __get_user(cred->pid, &target_cred->pid);
1764 __get_user(cred->uid, &target_cred->uid);
1765 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001766 } else {
1767 gemu_log("Unsupported ancillary data: %d/%d\n",
1768 cmsg->cmsg_level, cmsg->cmsg_type);
1769 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001770 }
1771
1772 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001773 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1774 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001775 }
bellard5a4a8982007-11-11 17:39:18 +00001776 unlock_user(target_cmsg, target_cmsg_addr, 0);
1777 the_end:
bellard7854b052003-03-29 17:22:23 +00001778 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001779 return 0;
bellard7854b052003-03-29 17:22:23 +00001780}
1781
bellard5a4a8982007-11-11 17:39:18 +00001782static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1783 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001784{
1785 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001786 abi_long msg_controllen;
1787 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001788 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001789 socklen_t space = 0;
1790
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001791 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001792 if (msg_controllen < sizeof (struct target_cmsghdr))
1793 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001794 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001795 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001796 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001797 if (!target_cmsg)
1798 return -TARGET_EFAULT;
1799
bellard7854b052003-03-29 17:22:23 +00001800 while (cmsg && target_cmsg) {
1801 void *data = CMSG_DATA(cmsg);
1802 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1803
Peter Maydellad762b92017-12-15 13:52:56 +00001804 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001805 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001806
Peter Maydellc2aeb252015-05-26 19:46:31 +01001807 /* We never copy a half-header but may copy half-data;
1808 * this is Linux's behaviour in put_cmsg(). Note that
1809 * truncation here is a guest problem (which we report
1810 * to the guest via the CTRUNC bit), unlike truncation
1811 * in target_to_host_cmsg, which is a QEMU bug.
1812 */
Peter Maydell71749702017-12-15 13:52:55 +00001813 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001814 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001815 break;
1816 }
1817
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001818 if (cmsg->cmsg_level == SOL_SOCKET) {
1819 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1820 } else {
1821 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1822 }
bellard7854b052003-03-29 17:22:23 +00001823 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001824
Peter Maydellc2aeb252015-05-26 19:46:31 +01001825 /* Payload types which need a different size of payload on
1826 * the target must adjust tgt_len here.
1827 */
1828 switch (cmsg->cmsg_level) {
1829 case SOL_SOCKET:
1830 switch (cmsg->cmsg_type) {
1831 case SO_TIMESTAMP:
1832 tgt_len = sizeof(struct target_timeval);
1833 break;
1834 default:
1835 break;
1836 }
1837 default:
Peter Maydell71749702017-12-15 13:52:55 +00001838 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001839 break;
1840 }
1841
Peter Maydell71749702017-12-15 13:52:55 +00001842 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001843 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001844 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001845 }
1846
1847 /* We must now copy-and-convert len bytes of payload
1848 * into tgt_len bytes of destination space. Bear in mind
1849 * that in both source and destination we may be dealing
1850 * with a truncated value!
1851 */
Huw Davies52b65492014-04-17 14:02:47 +01001852 switch (cmsg->cmsg_level) {
1853 case SOL_SOCKET:
1854 switch (cmsg->cmsg_type) {
1855 case SCM_RIGHTS:
1856 {
1857 int *fd = (int *)data;
1858 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001859 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001860
Peter Maydell876e23c2015-05-26 19:46:32 +01001861 for (i = 0; i < numfds; i++) {
1862 __put_user(fd[i], target_fd + i);
1863 }
Huw Davies52b65492014-04-17 14:02:47 +01001864 break;
1865 }
1866 case SO_TIMESTAMP:
1867 {
1868 struct timeval *tv = (struct timeval *)data;
1869 struct target_timeval *target_tv =
1870 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001871
Peter Maydellc2aeb252015-05-26 19:46:31 +01001872 if (len != sizeof(struct timeval) ||
1873 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001874 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001875 }
Huw Davies52b65492014-04-17 14:02:47 +01001876
1877 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001878 __put_user(tv->tv_sec, &target_tv->tv_sec);
1879 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001880 break;
1881 }
Huw Davies4bc29752014-04-17 14:02:48 +01001882 case SCM_CREDENTIALS:
1883 {
1884 struct ucred *cred = (struct ucred *)data;
1885 struct target_ucred *target_cred =
1886 (struct target_ucred *)target_data;
1887
1888 __put_user(cred->pid, &target_cred->pid);
1889 __put_user(cred->uid, &target_cred->uid);
1890 __put_user(cred->gid, &target_cred->gid);
1891 break;
1892 }
Huw Davies52b65492014-04-17 14:02:47 +01001893 default:
1894 goto unimplemented;
1895 }
1896 break;
1897
Helge Delleree1ac3a2017-02-18 23:31:30 +01001898 case SOL_IP:
1899 switch (cmsg->cmsg_type) {
1900 case IP_TTL:
1901 {
1902 uint32_t *v = (uint32_t *)data;
1903 uint32_t *t_int = (uint32_t *)target_data;
1904
Peter Maydell71749702017-12-15 13:52:55 +00001905 if (len != sizeof(uint32_t) ||
1906 tgt_len != sizeof(uint32_t)) {
1907 goto unimplemented;
1908 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001909 __put_user(*v, t_int);
1910 break;
1911 }
1912 case IP_RECVERR:
1913 {
1914 struct errhdr_t {
1915 struct sock_extended_err ee;
1916 struct sockaddr_in offender;
1917 };
1918 struct errhdr_t *errh = (struct errhdr_t *)data;
1919 struct errhdr_t *target_errh =
1920 (struct errhdr_t *)target_data;
1921
Peter Maydell71749702017-12-15 13:52:55 +00001922 if (len != sizeof(struct errhdr_t) ||
1923 tgt_len != sizeof(struct errhdr_t)) {
1924 goto unimplemented;
1925 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001926 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1927 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1928 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1929 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1930 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1931 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1932 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1933 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1934 (void *) &errh->offender, sizeof(errh->offender));
1935 break;
1936 }
1937 default:
1938 goto unimplemented;
1939 }
1940 break;
1941
1942 case SOL_IPV6:
1943 switch (cmsg->cmsg_type) {
1944 case IPV6_HOPLIMIT:
1945 {
1946 uint32_t *v = (uint32_t *)data;
1947 uint32_t *t_int = (uint32_t *)target_data;
1948
Peter Maydell71749702017-12-15 13:52:55 +00001949 if (len != sizeof(uint32_t) ||
1950 tgt_len != sizeof(uint32_t)) {
1951 goto unimplemented;
1952 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001953 __put_user(*v, t_int);
1954 break;
1955 }
1956 case IPV6_RECVERR:
1957 {
1958 struct errhdr6_t {
1959 struct sock_extended_err ee;
1960 struct sockaddr_in6 offender;
1961 };
1962 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1963 struct errhdr6_t *target_errh =
1964 (struct errhdr6_t *)target_data;
1965
Peter Maydell71749702017-12-15 13:52:55 +00001966 if (len != sizeof(struct errhdr6_t) ||
1967 tgt_len != sizeof(struct errhdr6_t)) {
1968 goto unimplemented;
1969 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001970 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1971 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1972 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1973 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1974 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1975 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1976 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1977 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1978 (void *) &errh->offender, sizeof(errh->offender));
1979 break;
1980 }
1981 default:
1982 goto unimplemented;
1983 }
1984 break;
1985
Huw Davies52b65492014-04-17 14:02:47 +01001986 default:
1987 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001988 gemu_log("Unsupported ancillary data: %d/%d\n",
1989 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001990 memcpy(target_data, data, MIN(len, tgt_len));
1991 if (tgt_len > len) {
1992 memset(target_data + len, 0, tgt_len - len);
1993 }
bellard7854b052003-03-29 17:22:23 +00001994 }
1995
Peter Maydell71749702017-12-15 13:52:55 +00001996 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
1997 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001998 if (msg_controllen < tgt_space) {
1999 tgt_space = msg_controllen;
2000 }
2001 msg_controllen -= tgt_space;
2002 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00002003 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02002004 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
2005 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00002006 }
bellard5a4a8982007-11-11 17:39:18 +00002007 unlock_user(target_cmsg, target_cmsg_addr, space);
2008 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002009 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00002010 return 0;
bellard7854b052003-03-29 17:22:23 +00002011}
2012
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002013static void tswap_nlmsghdr(struct nlmsghdr *nlh)
2014{
2015 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
2016 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
2017 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
2018 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
2019 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
2020}
2021
2022static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
2023 size_t len,
2024 abi_long (*host_to_target_nlmsg)
2025 (struct nlmsghdr *))
2026{
2027 uint32_t nlmsg_len;
2028 abi_long ret;
2029
2030 while (len > sizeof(struct nlmsghdr)) {
2031
2032 nlmsg_len = nlh->nlmsg_len;
2033 if (nlmsg_len < sizeof(struct nlmsghdr) ||
2034 nlmsg_len > len) {
2035 break;
2036 }
2037
2038 switch (nlh->nlmsg_type) {
2039 case NLMSG_DONE:
2040 tswap_nlmsghdr(nlh);
2041 return 0;
2042 case NLMSG_NOOP:
2043 break;
2044 case NLMSG_ERROR:
2045 {
2046 struct nlmsgerr *e = NLMSG_DATA(nlh);
2047 e->error = tswap32(e->error);
2048 tswap_nlmsghdr(&e->msg);
2049 tswap_nlmsghdr(nlh);
2050 return 0;
2051 }
2052 default:
2053 ret = host_to_target_nlmsg(nlh);
2054 if (ret < 0) {
2055 tswap_nlmsghdr(nlh);
2056 return ret;
2057 }
2058 break;
2059 }
2060 tswap_nlmsghdr(nlh);
2061 len -= NLMSG_ALIGN(nlmsg_len);
2062 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
2063 }
2064 return 0;
2065}
2066
2067static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
2068 size_t len,
2069 abi_long (*target_to_host_nlmsg)
2070 (struct nlmsghdr *))
2071{
2072 int ret;
2073
2074 while (len > sizeof(struct nlmsghdr)) {
2075 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
2076 tswap32(nlh->nlmsg_len) > len) {
2077 break;
2078 }
2079 tswap_nlmsghdr(nlh);
2080 switch (nlh->nlmsg_type) {
2081 case NLMSG_DONE:
2082 return 0;
2083 case NLMSG_NOOP:
2084 break;
2085 case NLMSG_ERROR:
2086 {
2087 struct nlmsgerr *e = NLMSG_DATA(nlh);
2088 e->error = tswap32(e->error);
2089 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02002090 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002091 }
2092 default:
2093 ret = target_to_host_nlmsg(nlh);
2094 if (ret < 0) {
2095 return ret;
2096 }
2097 }
2098 len -= NLMSG_ALIGN(nlh->nlmsg_len);
2099 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
2100 }
2101 return 0;
2102}
2103
Laurent Vivier575b22b2016-06-02 22:14:15 +02002104#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02002105static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
2106 size_t len, void *context,
2107 abi_long (*host_to_target_nlattr)
2108 (struct nlattr *,
2109 void *context))
2110{
2111 unsigned short nla_len;
2112 abi_long ret;
2113
2114 while (len > sizeof(struct nlattr)) {
2115 nla_len = nlattr->nla_len;
2116 if (nla_len < sizeof(struct nlattr) ||
2117 nla_len > len) {
2118 break;
2119 }
2120 ret = host_to_target_nlattr(nlattr, context);
2121 nlattr->nla_len = tswap16(nlattr->nla_len);
2122 nlattr->nla_type = tswap16(nlattr->nla_type);
2123 if (ret < 0) {
2124 return ret;
2125 }
2126 len -= NLA_ALIGN(nla_len);
2127 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
2128 }
2129 return 0;
2130}
2131
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002132static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
2133 size_t len,
2134 abi_long (*host_to_target_rtattr)
2135 (struct rtattr *))
2136{
2137 unsigned short rta_len;
2138 abi_long ret;
2139
2140 while (len > sizeof(struct rtattr)) {
2141 rta_len = rtattr->rta_len;
2142 if (rta_len < sizeof(struct rtattr) ||
2143 rta_len > len) {
2144 break;
2145 }
2146 ret = host_to_target_rtattr(rtattr);
2147 rtattr->rta_len = tswap16(rtattr->rta_len);
2148 rtattr->rta_type = tswap16(rtattr->rta_type);
2149 if (ret < 0) {
2150 return ret;
2151 }
2152 len -= RTA_ALIGN(rta_len);
2153 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2154 }
2155 return 0;
2156}
2157
Laurent Vivierc5dff282016-06-27 18:54:30 +02002158#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2159
2160static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2161 void *context)
2162{
2163 uint16_t *u16;
2164 uint32_t *u32;
2165 uint64_t *u64;
2166
2167 switch (nlattr->nla_type) {
2168 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002169 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002170 break;
2171 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002172 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002173 break;
2174 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002175 case QEMU_IFLA_BR_VLAN_FILTERING:
2176 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2177 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2178 case QEMU_IFLA_BR_MCAST_ROUTER:
2179 case QEMU_IFLA_BR_MCAST_SNOOPING:
2180 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2181 case QEMU_IFLA_BR_MCAST_QUERIER:
2182 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2183 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2184 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002185 break;
2186 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002187 case QEMU_IFLA_BR_PRIORITY:
2188 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2189 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2190 case QEMU_IFLA_BR_ROOT_PORT:
2191 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002192 u16 = NLA_DATA(nlattr);
2193 *u16 = tswap16(*u16);
2194 break;
2195 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002196 case QEMU_IFLA_BR_FORWARD_DELAY:
2197 case QEMU_IFLA_BR_HELLO_TIME:
2198 case QEMU_IFLA_BR_MAX_AGE:
2199 case QEMU_IFLA_BR_AGEING_TIME:
2200 case QEMU_IFLA_BR_STP_STATE:
2201 case QEMU_IFLA_BR_ROOT_PATH_COST:
2202 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2203 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2204 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2205 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002206 u32 = NLA_DATA(nlattr);
2207 *u32 = tswap32(*u32);
2208 break;
2209 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002210 case QEMU_IFLA_BR_HELLO_TIMER:
2211 case QEMU_IFLA_BR_TCN_TIMER:
2212 case QEMU_IFLA_BR_GC_TIMER:
2213 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2214 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2215 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2216 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2217 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2218 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2219 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002220 u64 = NLA_DATA(nlattr);
2221 *u64 = tswap64(*u64);
2222 break;
2223 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002224 case QEMU_IFLA_BR_ROOT_ID:
2225 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002226 break;
2227 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002228 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002229 break;
2230 }
2231 return 0;
2232}
2233
2234static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2235 void *context)
2236{
2237 uint16_t *u16;
2238 uint32_t *u32;
2239 uint64_t *u64;
2240
2241 switch (nlattr->nla_type) {
2242 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002243 case QEMU_IFLA_BRPORT_STATE:
2244 case QEMU_IFLA_BRPORT_MODE:
2245 case QEMU_IFLA_BRPORT_GUARD:
2246 case QEMU_IFLA_BRPORT_PROTECT:
2247 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2248 case QEMU_IFLA_BRPORT_LEARNING:
2249 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2250 case QEMU_IFLA_BRPORT_PROXYARP:
2251 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2252 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2253 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2254 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2255 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002256 break;
2257 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002258 case QEMU_IFLA_BRPORT_PRIORITY:
2259 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2260 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2261 case QEMU_IFLA_BRPORT_ID:
2262 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002263 u16 = NLA_DATA(nlattr);
2264 *u16 = tswap16(*u16);
2265 break;
2266 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002267 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002268 u32 = NLA_DATA(nlattr);
2269 *u32 = tswap32(*u32);
2270 break;
2271 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002272 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2273 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2274 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002275 u64 = NLA_DATA(nlattr);
2276 *u64 = tswap64(*u64);
2277 break;
2278 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002279 case QEMU_IFLA_BRPORT_ROOT_ID:
2280 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002281 break;
2282 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002283 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002284 break;
2285 }
2286 return 0;
2287}
2288
2289struct linkinfo_context {
2290 int len;
2291 char *name;
2292 int slave_len;
2293 char *slave_name;
2294};
2295
2296static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2297 void *context)
2298{
2299 struct linkinfo_context *li_context = context;
2300
2301 switch (nlattr->nla_type) {
2302 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002303 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002304 li_context->name = NLA_DATA(nlattr);
2305 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2306 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002307 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002308 li_context->slave_name = NLA_DATA(nlattr);
2309 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2310 break;
2311 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002312 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002313 /* FIXME: only used by CAN */
2314 break;
2315 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002316 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002317 if (strncmp(li_context->name, "bridge",
2318 li_context->len) == 0) {
2319 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2320 nlattr->nla_len,
2321 NULL,
2322 host_to_target_data_bridge_nlattr);
2323 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002324 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002325 }
2326 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002327 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002328 if (strncmp(li_context->slave_name, "bridge",
2329 li_context->slave_len) == 0) {
2330 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2331 nlattr->nla_len,
2332 NULL,
2333 host_to_target_slave_data_bridge_nlattr);
2334 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002335 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002336 li_context->slave_name);
2337 }
2338 break;
2339 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002340 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002341 break;
2342 }
2343
2344 return 0;
2345}
2346
2347static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2348 void *context)
2349{
2350 uint32_t *u32;
2351 int i;
2352
2353 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002354 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002355 u32 = NLA_DATA(nlattr);
2356 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2357 i++) {
2358 u32[i] = tswap32(u32[i]);
2359 }
2360 break;
2361 default:
2362 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2363 }
2364 return 0;
2365}
2366
2367static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2368 void *context)
2369{
2370 uint32_t *u32;
2371 uint64_t *u64;
2372 struct ifla_cacheinfo *ci;
2373 int i;
2374
2375 switch (nlattr->nla_type) {
2376 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002377 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002378 break;
2379 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002380 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002381 break;
2382 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002383 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002384 u32 = NLA_DATA(nlattr);
2385 *u32 = tswap32(*u32);
2386 break;
2387 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002388 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002389 u32 = NLA_DATA(nlattr);
2390 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2391 i++) {
2392 u32[i] = tswap32(u32[i]);
2393 }
2394 break;
2395 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002396 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002397 ci = NLA_DATA(nlattr);
2398 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2399 ci->tstamp = tswap32(ci->tstamp);
2400 ci->reachable_time = tswap32(ci->reachable_time);
2401 ci->retrans_time = tswap32(ci->retrans_time);
2402 break;
2403 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002404 case QEMU_IFLA_INET6_STATS:
2405 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002406 u64 = NLA_DATA(nlattr);
2407 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2408 i++) {
2409 u64[i] = tswap64(u64[i]);
2410 }
2411 break;
2412 default:
2413 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2414 }
2415 return 0;
2416}
2417
2418static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2419 void *context)
2420{
2421 switch (nlattr->nla_type) {
2422 case AF_INET:
2423 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2424 NULL,
2425 host_to_target_data_inet_nlattr);
2426 case AF_INET6:
2427 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2428 NULL,
2429 host_to_target_data_inet6_nlattr);
2430 default:
2431 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2432 break;
2433 }
2434 return 0;
2435}
2436
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002437static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2438{
2439 uint32_t *u32;
2440 struct rtnl_link_stats *st;
2441 struct rtnl_link_stats64 *st64;
2442 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002443 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002444
2445 switch (rtattr->rta_type) {
2446 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002447 case QEMU_IFLA_ADDRESS:
2448 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002449 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002450 case QEMU_IFLA_IFNAME:
2451 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002452 break;
2453 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002454 case QEMU_IFLA_OPERSTATE:
2455 case QEMU_IFLA_LINKMODE:
2456 case QEMU_IFLA_CARRIER:
2457 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002458 break;
2459 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002460 case QEMU_IFLA_MTU:
2461 case QEMU_IFLA_LINK:
2462 case QEMU_IFLA_WEIGHT:
2463 case QEMU_IFLA_TXQLEN:
2464 case QEMU_IFLA_CARRIER_CHANGES:
2465 case QEMU_IFLA_NUM_RX_QUEUES:
2466 case QEMU_IFLA_NUM_TX_QUEUES:
2467 case QEMU_IFLA_PROMISCUITY:
2468 case QEMU_IFLA_EXT_MASK:
2469 case QEMU_IFLA_LINK_NETNSID:
2470 case QEMU_IFLA_GROUP:
2471 case QEMU_IFLA_MASTER:
2472 case QEMU_IFLA_NUM_VF:
Laurent Viviera1488b82016-10-27 03:00:49 +02002473 case QEMU_IFLA_GSO_MAX_SEGS:
2474 case QEMU_IFLA_GSO_MAX_SIZE:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002475 u32 = RTA_DATA(rtattr);
2476 *u32 = tswap32(*u32);
2477 break;
2478 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002479 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002480 st = RTA_DATA(rtattr);
2481 st->rx_packets = tswap32(st->rx_packets);
2482 st->tx_packets = tswap32(st->tx_packets);
2483 st->rx_bytes = tswap32(st->rx_bytes);
2484 st->tx_bytes = tswap32(st->tx_bytes);
2485 st->rx_errors = tswap32(st->rx_errors);
2486 st->tx_errors = tswap32(st->tx_errors);
2487 st->rx_dropped = tswap32(st->rx_dropped);
2488 st->tx_dropped = tswap32(st->tx_dropped);
2489 st->multicast = tswap32(st->multicast);
2490 st->collisions = tswap32(st->collisions);
2491
2492 /* detailed rx_errors: */
2493 st->rx_length_errors = tswap32(st->rx_length_errors);
2494 st->rx_over_errors = tswap32(st->rx_over_errors);
2495 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2496 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2497 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2498 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2499
2500 /* detailed tx_errors */
2501 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2502 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2503 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2504 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2505 st->tx_window_errors = tswap32(st->tx_window_errors);
2506
2507 /* for cslip etc */
2508 st->rx_compressed = tswap32(st->rx_compressed);
2509 st->tx_compressed = tswap32(st->tx_compressed);
2510 break;
2511 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002512 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002513 st64 = RTA_DATA(rtattr);
2514 st64->rx_packets = tswap64(st64->rx_packets);
2515 st64->tx_packets = tswap64(st64->tx_packets);
2516 st64->rx_bytes = tswap64(st64->rx_bytes);
2517 st64->tx_bytes = tswap64(st64->tx_bytes);
2518 st64->rx_errors = tswap64(st64->rx_errors);
2519 st64->tx_errors = tswap64(st64->tx_errors);
2520 st64->rx_dropped = tswap64(st64->rx_dropped);
2521 st64->tx_dropped = tswap64(st64->tx_dropped);
2522 st64->multicast = tswap64(st64->multicast);
2523 st64->collisions = tswap64(st64->collisions);
2524
2525 /* detailed rx_errors: */
2526 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2527 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2528 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2529 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2530 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2531 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2532
2533 /* detailed tx_errors */
2534 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2535 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2536 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2537 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2538 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2539
2540 /* for cslip etc */
2541 st64->rx_compressed = tswap64(st64->rx_compressed);
2542 st64->tx_compressed = tswap64(st64->tx_compressed);
2543 break;
2544 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002545 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002546 map = RTA_DATA(rtattr);
2547 map->mem_start = tswap64(map->mem_start);
2548 map->mem_end = tswap64(map->mem_end);
2549 map->base_addr = tswap64(map->base_addr);
2550 map->irq = tswap16(map->irq);
2551 break;
2552 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002553 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002554 memset(&li_context, 0, sizeof(li_context));
2555 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2556 &li_context,
2557 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002558 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002559 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2560 NULL,
2561 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002562 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002563 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002564 break;
2565 }
2566 return 0;
2567}
2568
2569static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2570{
2571 uint32_t *u32;
2572 struct ifa_cacheinfo *ci;
2573
2574 switch (rtattr->rta_type) {
2575 /* binary: depends on family type */
2576 case IFA_ADDRESS:
2577 case IFA_LOCAL:
2578 break;
2579 /* string */
2580 case IFA_LABEL:
2581 break;
2582 /* u32 */
2583 case IFA_FLAGS:
2584 case IFA_BROADCAST:
2585 u32 = RTA_DATA(rtattr);
2586 *u32 = tswap32(*u32);
2587 break;
2588 /* struct ifa_cacheinfo */
2589 case IFA_CACHEINFO:
2590 ci = RTA_DATA(rtattr);
2591 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2592 ci->ifa_valid = tswap32(ci->ifa_valid);
2593 ci->cstamp = tswap32(ci->cstamp);
2594 ci->tstamp = tswap32(ci->tstamp);
2595 break;
2596 default:
2597 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2598 break;
2599 }
2600 return 0;
2601}
2602
2603static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2604{
2605 uint32_t *u32;
2606 switch (rtattr->rta_type) {
2607 /* binary: depends on family type */
2608 case RTA_GATEWAY:
2609 case RTA_DST:
2610 case RTA_PREFSRC:
2611 break;
2612 /* u32 */
2613 case RTA_PRIORITY:
2614 case RTA_TABLE:
2615 case RTA_OIF:
2616 u32 = RTA_DATA(rtattr);
2617 *u32 = tswap32(*u32);
2618 break;
2619 default:
2620 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2621 break;
2622 }
2623 return 0;
2624}
2625
2626static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2627 uint32_t rtattr_len)
2628{
2629 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2630 host_to_target_data_link_rtattr);
2631}
2632
2633static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2634 uint32_t rtattr_len)
2635{
2636 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2637 host_to_target_data_addr_rtattr);
2638}
2639
2640static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2641 uint32_t rtattr_len)
2642{
2643 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2644 host_to_target_data_route_rtattr);
2645}
2646
2647static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2648{
2649 uint32_t nlmsg_len;
2650 struct ifinfomsg *ifi;
2651 struct ifaddrmsg *ifa;
2652 struct rtmsg *rtm;
2653
2654 nlmsg_len = nlh->nlmsg_len;
2655 switch (nlh->nlmsg_type) {
2656 case RTM_NEWLINK:
2657 case RTM_DELLINK:
2658 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002659 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2660 ifi = NLMSG_DATA(nlh);
2661 ifi->ifi_type = tswap16(ifi->ifi_type);
2662 ifi->ifi_index = tswap32(ifi->ifi_index);
2663 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2664 ifi->ifi_change = tswap32(ifi->ifi_change);
2665 host_to_target_link_rtattr(IFLA_RTA(ifi),
2666 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2667 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002668 break;
2669 case RTM_NEWADDR:
2670 case RTM_DELADDR:
2671 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002672 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2673 ifa = NLMSG_DATA(nlh);
2674 ifa->ifa_index = tswap32(ifa->ifa_index);
2675 host_to_target_addr_rtattr(IFA_RTA(ifa),
2676 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2677 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002678 break;
2679 case RTM_NEWROUTE:
2680 case RTM_DELROUTE:
2681 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002682 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2683 rtm = NLMSG_DATA(nlh);
2684 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2685 host_to_target_route_rtattr(RTM_RTA(rtm),
2686 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2687 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002688 break;
2689 default:
2690 return -TARGET_EINVAL;
2691 }
2692 return 0;
2693}
2694
2695static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2696 size_t len)
2697{
2698 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2699}
2700
2701static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2702 size_t len,
2703 abi_long (*target_to_host_rtattr)
2704 (struct rtattr *))
2705{
2706 abi_long ret;
2707
2708 while (len >= sizeof(struct rtattr)) {
2709 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2710 tswap16(rtattr->rta_len) > len) {
2711 break;
2712 }
2713 rtattr->rta_len = tswap16(rtattr->rta_len);
2714 rtattr->rta_type = tswap16(rtattr->rta_type);
2715 ret = target_to_host_rtattr(rtattr);
2716 if (ret < 0) {
2717 return ret;
2718 }
2719 len -= RTA_ALIGN(rtattr->rta_len);
2720 rtattr = (struct rtattr *)(((char *)rtattr) +
2721 RTA_ALIGN(rtattr->rta_len));
2722 }
2723 return 0;
2724}
2725
2726static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2727{
2728 switch (rtattr->rta_type) {
2729 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002730 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002731 break;
2732 }
2733 return 0;
2734}
2735
2736static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2737{
2738 switch (rtattr->rta_type) {
2739 /* binary: depends on family type */
2740 case IFA_LOCAL:
2741 case IFA_ADDRESS:
2742 break;
2743 default:
2744 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2745 break;
2746 }
2747 return 0;
2748}
2749
2750static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2751{
2752 uint32_t *u32;
2753 switch (rtattr->rta_type) {
2754 /* binary: depends on family type */
2755 case RTA_DST:
2756 case RTA_SRC:
2757 case RTA_GATEWAY:
2758 break;
2759 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002760 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002761 case RTA_OIF:
2762 u32 = RTA_DATA(rtattr);
2763 *u32 = tswap32(*u32);
2764 break;
2765 default:
2766 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2767 break;
2768 }
2769 return 0;
2770}
2771
2772static void target_to_host_link_rtattr(struct rtattr *rtattr,
2773 uint32_t rtattr_len)
2774{
2775 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2776 target_to_host_data_link_rtattr);
2777}
2778
2779static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2780 uint32_t rtattr_len)
2781{
2782 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2783 target_to_host_data_addr_rtattr);
2784}
2785
2786static void target_to_host_route_rtattr(struct rtattr *rtattr,
2787 uint32_t rtattr_len)
2788{
2789 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2790 target_to_host_data_route_rtattr);
2791}
2792
2793static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2794{
2795 struct ifinfomsg *ifi;
2796 struct ifaddrmsg *ifa;
2797 struct rtmsg *rtm;
2798
2799 switch (nlh->nlmsg_type) {
2800 case RTM_GETLINK:
2801 break;
2802 case RTM_NEWLINK:
2803 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002804 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2805 ifi = NLMSG_DATA(nlh);
2806 ifi->ifi_type = tswap16(ifi->ifi_type);
2807 ifi->ifi_index = tswap32(ifi->ifi_index);
2808 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2809 ifi->ifi_change = tswap32(ifi->ifi_change);
2810 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2811 NLMSG_LENGTH(sizeof(*ifi)));
2812 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002813 break;
2814 case RTM_GETADDR:
2815 case RTM_NEWADDR:
2816 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002817 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2818 ifa = NLMSG_DATA(nlh);
2819 ifa->ifa_index = tswap32(ifa->ifa_index);
2820 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2821 NLMSG_LENGTH(sizeof(*ifa)));
2822 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002823 break;
2824 case RTM_GETROUTE:
2825 break;
2826 case RTM_NEWROUTE:
2827 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002828 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2829 rtm = NLMSG_DATA(nlh);
2830 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2831 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2832 NLMSG_LENGTH(sizeof(*rtm)));
2833 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002834 break;
2835 default:
2836 return -TARGET_EOPNOTSUPP;
2837 }
2838 return 0;
2839}
2840
2841static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2842{
2843 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2844}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002845#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002846
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002847static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2848{
2849 switch (nlh->nlmsg_type) {
2850 default:
2851 gemu_log("Unknown host audit message type %d\n",
2852 nlh->nlmsg_type);
2853 return -TARGET_EINVAL;
2854 }
2855 return 0;
2856}
2857
2858static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2859 size_t len)
2860{
2861 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2862}
2863
2864static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2865{
2866 switch (nlh->nlmsg_type) {
2867 case AUDIT_USER:
2868 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2869 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2870 break;
2871 default:
2872 gemu_log("Unknown target audit message type %d\n",
2873 nlh->nlmsg_type);
2874 return -TARGET_EINVAL;
2875 }
2876
2877 return 0;
2878}
2879
2880static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2881{
2882 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2883}
2884
ths0da46a62007-10-20 20:23:07 +00002885/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002886static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002887 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002888{
blueswir1992f48a2007-10-14 16:27:31 +00002889 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002890 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002891 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002892 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002893
bellard8853f862004-02-22 14:57:26 +00002894 switch(level) {
2895 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002896 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002897 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002898 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002899
bellard2f619692007-11-16 10:46:05 +00002900 if (get_user_u32(val, optval_addr))
2901 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002902 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2903 break;
2904 case SOL_IP:
2905 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002906 case IP_TOS:
2907 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002908 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002909 case IP_ROUTER_ALERT:
2910 case IP_RECVOPTS:
2911 case IP_RETOPTS:
2912 case IP_PKTINFO:
2913 case IP_MTU_DISCOVER:
2914 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002915 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002916 case IP_RECVTOS:
2917#ifdef IP_FREEBIND
2918 case IP_FREEBIND:
2919#endif
2920 case IP_MULTICAST_TTL:
2921 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002922 val = 0;
2923 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002924 if (get_user_u32(val, optval_addr))
2925 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002926 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002927 if (get_user_u8(val, optval_addr))
2928 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002929 }
2930 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2931 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002932 case IP_ADD_MEMBERSHIP:
2933 case IP_DROP_MEMBERSHIP:
2934 if (optlen < sizeof (struct target_ip_mreq) ||
2935 optlen > sizeof (struct target_ip_mreqn))
2936 return -TARGET_EINVAL;
2937
2938 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2939 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2940 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2941 break;
2942
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002943 case IP_BLOCK_SOURCE:
2944 case IP_UNBLOCK_SOURCE:
2945 case IP_ADD_SOURCE_MEMBERSHIP:
2946 case IP_DROP_SOURCE_MEMBERSHIP:
2947 if (optlen != sizeof (struct target_ip_mreq_source))
2948 return -TARGET_EINVAL;
2949
2950 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2951 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2952 unlock_user (ip_mreq_source, optval_addr, 0);
2953 break;
2954
bellard8853f862004-02-22 14:57:26 +00002955 default:
2956 goto unimplemented;
2957 }
2958 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002959 case SOL_IPV6:
2960 switch (optname) {
2961 case IPV6_MTU_DISCOVER:
2962 case IPV6_MTU:
2963 case IPV6_V6ONLY:
2964 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002965 case IPV6_UNICAST_HOPS:
2966 case IPV6_RECVERR:
2967 case IPV6_RECVHOPLIMIT:
2968 case IPV6_2292HOPLIMIT:
2969 case IPV6_CHECKSUM:
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002970 val = 0;
2971 if (optlen < sizeof(uint32_t)) {
2972 return -TARGET_EINVAL;
2973 }
2974 if (get_user_u32(val, optval_addr)) {
2975 return -TARGET_EFAULT;
2976 }
2977 ret = get_errno(setsockopt(sockfd, level, optname,
2978 &val, sizeof(val)));
2979 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002980 case IPV6_PKTINFO:
2981 {
2982 struct in6_pktinfo pki;
2983
2984 if (optlen < sizeof(pki)) {
2985 return -TARGET_EINVAL;
2986 }
2987
2988 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2989 return -TARGET_EFAULT;
2990 }
2991
2992 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2993
2994 ret = get_errno(setsockopt(sockfd, level, optname,
2995 &pki, sizeof(pki)));
2996 break;
2997 }
2998 default:
2999 goto unimplemented;
3000 }
3001 break;
3002 case SOL_ICMPV6:
3003 switch (optname) {
3004 case ICMPV6_FILTER:
3005 {
3006 struct icmp6_filter icmp6f;
3007
3008 if (optlen > sizeof(icmp6f)) {
3009 optlen = sizeof(icmp6f);
3010 }
3011
3012 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
3013 return -TARGET_EFAULT;
3014 }
3015
3016 for (val = 0; val < 8; val++) {
3017 icmp6f.data[val] = tswap32(icmp6f.data[val]);
3018 }
3019
3020 ret = get_errno(setsockopt(sockfd, level, optname,
3021 &icmp6f, optlen));
3022 break;
3023 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02003024 default:
3025 goto unimplemented;
3026 }
3027 break;
Jing Huang920394d2012-07-24 13:59:23 +00003028 case SOL_RAW:
3029 switch (optname) {
3030 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003031 case IPV6_CHECKSUM:
3032 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00003033 if (optlen < sizeof(uint32_t)) {
3034 return -TARGET_EINVAL;
3035 }
3036
3037 if (get_user_u32(val, optval_addr)) {
3038 return -TARGET_EFAULT;
3039 }
3040 ret = get_errno(setsockopt(sockfd, level, optname,
3041 &val, sizeof(val)));
3042 break;
3043
3044 default:
3045 goto unimplemented;
3046 }
3047 break;
bellard3532fa72006-06-24 15:06:03 +00003048 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00003049 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00003050 case TARGET_SO_RCVTIMEO:
3051 {
3052 struct timeval tv;
3053
3054 optname = SO_RCVTIMEO;
3055
3056set_timeout:
3057 if (optlen != sizeof(struct target_timeval)) {
3058 return -TARGET_EINVAL;
3059 }
3060
3061 if (copy_from_user_timeval(&tv, optval_addr)) {
3062 return -TARGET_EFAULT;
3063 }
3064
3065 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3066 &tv, sizeof(tv)));
3067 return ret;
3068 }
3069 case TARGET_SO_SNDTIMEO:
3070 optname = SO_SNDTIMEO;
3071 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02003072 case TARGET_SO_ATTACH_FILTER:
3073 {
3074 struct target_sock_fprog *tfprog;
3075 struct target_sock_filter *tfilter;
3076 struct sock_fprog fprog;
3077 struct sock_filter *filter;
3078 int i;
3079
3080 if (optlen != sizeof(*tfprog)) {
3081 return -TARGET_EINVAL;
3082 }
3083 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
3084 return -TARGET_EFAULT;
3085 }
3086 if (!lock_user_struct(VERIFY_READ, tfilter,
3087 tswapal(tfprog->filter), 0)) {
3088 unlock_user_struct(tfprog, optval_addr, 1);
3089 return -TARGET_EFAULT;
3090 }
3091
3092 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303093 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003094 if (filter == NULL) {
3095 unlock_user_struct(tfilter, tfprog->filter, 1);
3096 unlock_user_struct(tfprog, optval_addr, 1);
3097 return -TARGET_ENOMEM;
3098 }
3099 for (i = 0; i < fprog.len; i++) {
3100 filter[i].code = tswap16(tfilter[i].code);
3101 filter[i].jt = tfilter[i].jt;
3102 filter[i].jf = tfilter[i].jf;
3103 filter[i].k = tswap32(tfilter[i].k);
3104 }
3105 fprog.filter = filter;
3106
3107 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
3108 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303109 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003110
3111 unlock_user_struct(tfilter, tfprog->filter, 1);
3112 unlock_user_struct(tfprog, optval_addr, 1);
3113 return ret;
3114 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003115 case TARGET_SO_BINDTODEVICE:
3116 {
3117 char *dev_ifname, *addr_ifname;
3118
3119 if (optlen > IFNAMSIZ - 1) {
3120 optlen = IFNAMSIZ - 1;
3121 }
3122 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3123 if (!dev_ifname) {
3124 return -TARGET_EFAULT;
3125 }
3126 optname = SO_BINDTODEVICE;
3127 addr_ifname = alloca(IFNAMSIZ);
3128 memcpy(addr_ifname, dev_ifname, optlen);
3129 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08003130 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3131 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003132 unlock_user (dev_ifname, optval_addr, 0);
3133 return ret;
3134 }
bellard8853f862004-02-22 14:57:26 +00003135 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00003136 case TARGET_SO_DEBUG:
3137 optname = SO_DEBUG;
3138 break;
3139 case TARGET_SO_REUSEADDR:
3140 optname = SO_REUSEADDR;
3141 break;
3142 case TARGET_SO_TYPE:
3143 optname = SO_TYPE;
3144 break;
3145 case TARGET_SO_ERROR:
3146 optname = SO_ERROR;
3147 break;
3148 case TARGET_SO_DONTROUTE:
3149 optname = SO_DONTROUTE;
3150 break;
3151 case TARGET_SO_BROADCAST:
3152 optname = SO_BROADCAST;
3153 break;
3154 case TARGET_SO_SNDBUF:
3155 optname = SO_SNDBUF;
3156 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003157 case TARGET_SO_SNDBUFFORCE:
3158 optname = SO_SNDBUFFORCE;
3159 break;
bellard3532fa72006-06-24 15:06:03 +00003160 case TARGET_SO_RCVBUF:
3161 optname = SO_RCVBUF;
3162 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003163 case TARGET_SO_RCVBUFFORCE:
3164 optname = SO_RCVBUFFORCE;
3165 break;
bellard3532fa72006-06-24 15:06:03 +00003166 case TARGET_SO_KEEPALIVE:
3167 optname = SO_KEEPALIVE;
3168 break;
3169 case TARGET_SO_OOBINLINE:
3170 optname = SO_OOBINLINE;
3171 break;
3172 case TARGET_SO_NO_CHECK:
3173 optname = SO_NO_CHECK;
3174 break;
3175 case TARGET_SO_PRIORITY:
3176 optname = SO_PRIORITY;
3177 break;
bellard5e83e8e2005-03-01 22:32:06 +00003178#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00003179 case TARGET_SO_BSDCOMPAT:
3180 optname = SO_BSDCOMPAT;
3181 break;
bellard5e83e8e2005-03-01 22:32:06 +00003182#endif
bellard3532fa72006-06-24 15:06:03 +00003183 case TARGET_SO_PASSCRED:
3184 optname = SO_PASSCRED;
3185 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01003186 case TARGET_SO_PASSSEC:
3187 optname = SO_PASSSEC;
3188 break;
bellard3532fa72006-06-24 15:06:03 +00003189 case TARGET_SO_TIMESTAMP:
3190 optname = SO_TIMESTAMP;
3191 break;
3192 case TARGET_SO_RCVLOWAT:
3193 optname = SO_RCVLOWAT;
3194 break;
bellard8853f862004-02-22 14:57:26 +00003195 default:
3196 goto unimplemented;
3197 }
bellard3532fa72006-06-24 15:06:03 +00003198 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003199 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003200
bellard2f619692007-11-16 10:46:05 +00003201 if (get_user_u32(val, optval_addr))
3202 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003203 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003204 break;
bellard7854b052003-03-29 17:22:23 +00003205 default:
bellard8853f862004-02-22 14:57:26 +00003206 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003207 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003208 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003209 }
bellard8853f862004-02-22 14:57:26 +00003210 return ret;
bellard7854b052003-03-29 17:22:23 +00003211}
3212
ths0da46a62007-10-20 20:23:07 +00003213/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003214static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003215 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003216{
blueswir1992f48a2007-10-14 16:27:31 +00003217 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003218 int len, val;
3219 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003220
3221 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003222 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003223 level = SOL_SOCKET;
3224 switch (optname) {
3225 /* These don't just return a single integer */
3226 case TARGET_SO_LINGER:
3227 case TARGET_SO_RCVTIMEO:
3228 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003229 case TARGET_SO_PEERNAME:
3230 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003231 case TARGET_SO_PEERCRED: {
3232 struct ucred cr;
3233 socklen_t crlen;
3234 struct target_ucred *tcr;
3235
3236 if (get_user_u32(len, optlen)) {
3237 return -TARGET_EFAULT;
3238 }
3239 if (len < 0) {
3240 return -TARGET_EINVAL;
3241 }
3242
3243 crlen = sizeof(cr);
3244 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3245 &cr, &crlen));
3246 if (ret < 0) {
3247 return ret;
3248 }
3249 if (len > crlen) {
3250 len = crlen;
3251 }
3252 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3253 return -TARGET_EFAULT;
3254 }
3255 __put_user(cr.pid, &tcr->pid);
3256 __put_user(cr.uid, &tcr->uid);
3257 __put_user(cr.gid, &tcr->gid);
3258 unlock_user_struct(tcr, optval_addr, 1);
3259 if (put_user_u32(len, optlen)) {
3260 return -TARGET_EFAULT;
3261 }
3262 break;
3263 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003264 /* Options with 'int' argument. */
3265 case TARGET_SO_DEBUG:
3266 optname = SO_DEBUG;
3267 goto int_case;
3268 case TARGET_SO_REUSEADDR:
3269 optname = SO_REUSEADDR;
3270 goto int_case;
3271 case TARGET_SO_TYPE:
3272 optname = SO_TYPE;
3273 goto int_case;
3274 case TARGET_SO_ERROR:
3275 optname = SO_ERROR;
3276 goto int_case;
3277 case TARGET_SO_DONTROUTE:
3278 optname = SO_DONTROUTE;
3279 goto int_case;
3280 case TARGET_SO_BROADCAST:
3281 optname = SO_BROADCAST;
3282 goto int_case;
3283 case TARGET_SO_SNDBUF:
3284 optname = SO_SNDBUF;
3285 goto int_case;
3286 case TARGET_SO_RCVBUF:
3287 optname = SO_RCVBUF;
3288 goto int_case;
3289 case TARGET_SO_KEEPALIVE:
3290 optname = SO_KEEPALIVE;
3291 goto int_case;
3292 case TARGET_SO_OOBINLINE:
3293 optname = SO_OOBINLINE;
3294 goto int_case;
3295 case TARGET_SO_NO_CHECK:
3296 optname = SO_NO_CHECK;
3297 goto int_case;
3298 case TARGET_SO_PRIORITY:
3299 optname = SO_PRIORITY;
3300 goto int_case;
3301#ifdef SO_BSDCOMPAT
3302 case TARGET_SO_BSDCOMPAT:
3303 optname = SO_BSDCOMPAT;
3304 goto int_case;
3305#endif
3306 case TARGET_SO_PASSCRED:
3307 optname = SO_PASSCRED;
3308 goto int_case;
3309 case TARGET_SO_TIMESTAMP:
3310 optname = SO_TIMESTAMP;
3311 goto int_case;
3312 case TARGET_SO_RCVLOWAT:
3313 optname = SO_RCVLOWAT;
3314 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003315 case TARGET_SO_ACCEPTCONN:
3316 optname = SO_ACCEPTCONN;
3317 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003318 default:
bellard2efbe912005-07-23 15:10:20 +00003319 goto int_case;
3320 }
3321 break;
3322 case SOL_TCP:
3323 /* TCP options all take an 'int' value. */
3324 int_case:
bellard2f619692007-11-16 10:46:05 +00003325 if (get_user_u32(len, optlen))
3326 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003327 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003328 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003329 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003330 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3331 if (ret < 0)
3332 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003333 if (optname == SO_TYPE) {
3334 val = host_to_target_sock_type(val);
3335 }
bellard2efbe912005-07-23 15:10:20 +00003336 if (len > lv)
3337 len = lv;
bellard2f619692007-11-16 10:46:05 +00003338 if (len == 4) {
3339 if (put_user_u32(val, optval_addr))
3340 return -TARGET_EFAULT;
3341 } else {
3342 if (put_user_u8(val, optval_addr))
3343 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003344 }
bellard2f619692007-11-16 10:46:05 +00003345 if (put_user_u32(len, optlen))
3346 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003347 break;
3348 case SOL_IP:
3349 switch(optname) {
3350 case IP_TOS:
3351 case IP_TTL:
3352 case IP_HDRINCL:
3353 case IP_ROUTER_ALERT:
3354 case IP_RECVOPTS:
3355 case IP_RETOPTS:
3356 case IP_PKTINFO:
3357 case IP_MTU_DISCOVER:
3358 case IP_RECVERR:
3359 case IP_RECVTOS:
3360#ifdef IP_FREEBIND
3361 case IP_FREEBIND:
3362#endif
3363 case IP_MULTICAST_TTL:
3364 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003365 if (get_user_u32(len, optlen))
3366 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003367 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003368 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003369 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003370 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3371 if (ret < 0)
3372 return ret;
bellard2efbe912005-07-23 15:10:20 +00003373 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003374 len = 1;
bellard2f619692007-11-16 10:46:05 +00003375 if (put_user_u32(len, optlen)
3376 || put_user_u8(val, optval_addr))
3377 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003378 } else {
bellard2efbe912005-07-23 15:10:20 +00003379 if (len > sizeof(int))
3380 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003381 if (put_user_u32(len, optlen)
3382 || put_user_u32(val, optval_addr))
3383 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003384 }
bellard8853f862004-02-22 14:57:26 +00003385 break;
bellard2efbe912005-07-23 15:10:20 +00003386 default:
thsc02f4992007-12-18 02:39:59 +00003387 ret = -TARGET_ENOPROTOOPT;
3388 break;
bellard8853f862004-02-22 14:57:26 +00003389 }
3390 break;
3391 default:
3392 unimplemented:
3393 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3394 level, optname);
thsc02f4992007-12-18 02:39:59 +00003395 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003396 break;
3397 }
3398 return ret;
bellard7854b052003-03-29 17:22:23 +00003399}
3400
Max Filippov9ac22512018-04-04 17:30:41 -07003401/* Convert target low/high pair representing file offset into the host
3402 * low/high pair. This function doesn't handle offsets bigger than 64 bits
3403 * as the kernel doesn't handle them either.
3404 */
3405static void target_to_host_low_high(abi_ulong tlow,
3406 abi_ulong thigh,
3407 unsigned long *hlow,
3408 unsigned long *hhigh)
3409{
3410 uint64_t off = tlow |
3411 ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
3412 TARGET_LONG_BITS / 2;
3413
3414 *hlow = off;
3415 *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
3416}
3417
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003418static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003419 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003420{
3421 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003422 struct iovec *vec;
3423 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003424 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003425 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003426 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003427
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003428 if (count == 0) {
3429 errno = 0;
3430 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003431 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003432 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003433 errno = EINVAL;
3434 return NULL;
3435 }
3436
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303437 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003438 if (vec == NULL) {
3439 errno = ENOMEM;
3440 return NULL;
3441 }
3442
3443 target_vec = lock_user(VERIFY_READ, target_addr,
3444 count * sizeof(struct target_iovec), 1);
3445 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003446 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003447 goto fail2;
3448 }
3449
3450 /* ??? If host page size > target page size, this will result in a
3451 value larger than what we can actually support. */
3452 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3453 total_len = 0;
3454
3455 for (i = 0; i < count; i++) {
3456 abi_ulong base = tswapal(target_vec[i].iov_base);
3457 abi_long len = tswapal(target_vec[i].iov_len);
3458
3459 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003460 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003461 goto fail;
3462 } else if (len == 0) {
3463 /* Zero length pointer is ignored. */
3464 vec[i].iov_base = 0;
3465 } else {
3466 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003467 /* If the first buffer pointer is bad, this is a fault. But
3468 * subsequent bad buffers will result in a partial write; this
3469 * is realized by filling the vector with null pointers and
3470 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003471 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003472 if (i == 0) {
3473 err = EFAULT;
3474 goto fail;
3475 } else {
3476 bad_address = true;
3477 }
3478 }
3479 if (bad_address) {
3480 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003481 }
3482 if (len > max_len - total_len) {
3483 len = max_len - total_len;
3484 }
3485 }
3486 vec[i].iov_len = len;
3487 total_len += len;
3488 }
3489
3490 unlock_user(target_vec, target_addr, 0);
3491 return vec;
3492
3493 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003494 while (--i >= 0) {
3495 if (tswapal(target_vec[i].iov_len) > 0) {
3496 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3497 }
3498 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003499 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003500 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303501 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003502 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003503 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003504}
3505
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003506static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003507 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003508{
3509 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003510 int i;
3511
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003512 target_vec = lock_user(VERIFY_READ, target_addr,
3513 count * sizeof(struct target_iovec), 1);
3514 if (target_vec) {
3515 for (i = 0; i < count; i++) {
3516 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003517 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003518 if (len < 0) {
3519 break;
3520 }
balrogd732dcb2008-10-28 10:21:03 +00003521 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3522 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003523 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003524 }
bellard579a97f2007-11-11 14:26:47 +00003525
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303526 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003527}
3528
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003529static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003530{
3531 int host_type = 0;
3532 int target_type = *type;
3533
3534 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3535 case TARGET_SOCK_DGRAM:
3536 host_type = SOCK_DGRAM;
3537 break;
3538 case TARGET_SOCK_STREAM:
3539 host_type = SOCK_STREAM;
3540 break;
3541 default:
3542 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3543 break;
3544 }
3545 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003546#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003547 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003548#else
3549 return -TARGET_EINVAL;
3550#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003551 }
3552 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003553#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003554 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003555#elif !defined(O_NONBLOCK)
3556 return -TARGET_EINVAL;
3557#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003558 }
3559 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003560 return 0;
3561}
3562
3563/* Try to emulate socket type flags after socket creation. */
3564static int sock_flags_fixup(int fd, int target_type)
3565{
3566#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3567 if (target_type & TARGET_SOCK_NONBLOCK) {
3568 int flags = fcntl(fd, F_GETFL);
3569 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3570 close(fd);
3571 return -TARGET_EINVAL;
3572 }
3573 }
3574#endif
3575 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003576}
3577
Laurent Vivier0cf22722015-10-28 21:40:45 +01003578static abi_long packet_target_to_host_sockaddr(void *host_addr,
3579 abi_ulong target_addr,
3580 socklen_t len)
3581{
3582 struct sockaddr *addr = host_addr;
3583 struct target_sockaddr *target_saddr;
3584
3585 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3586 if (!target_saddr) {
3587 return -TARGET_EFAULT;
3588 }
3589
3590 memcpy(addr, target_saddr, len);
3591 addr->sa_family = tswap16(target_saddr->sa_family);
3592 /* spkt_protocol is big-endian */
3593
3594 unlock_user(target_saddr, target_addr, 0);
3595 return 0;
3596}
3597
3598static TargetFdTrans target_packet_trans = {
3599 .target_to_host_addr = packet_target_to_host_sockaddr,
3600};
3601
Laurent Vivier575b22b2016-06-02 22:14:15 +02003602#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003603static abi_long netlink_route_target_to_host(void *buf, size_t len)
3604{
Laurent Vivieref759f62016-06-21 19:51:13 +02003605 abi_long ret;
3606
3607 ret = target_to_host_nlmsg_route(buf, len);
3608 if (ret < 0) {
3609 return ret;
3610 }
3611
3612 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003613}
3614
3615static abi_long netlink_route_host_to_target(void *buf, size_t len)
3616{
Laurent Vivieref759f62016-06-21 19:51:13 +02003617 abi_long ret;
3618
3619 ret = host_to_target_nlmsg_route(buf, len);
3620 if (ret < 0) {
3621 return ret;
3622 }
3623
3624 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003625}
3626
3627static TargetFdTrans target_netlink_route_trans = {
3628 .target_to_host_data = netlink_route_target_to_host,
3629 .host_to_target_data = netlink_route_host_to_target,
3630};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003631#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003632
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003633static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3634{
Laurent Vivieref759f62016-06-21 19:51:13 +02003635 abi_long ret;
3636
3637 ret = target_to_host_nlmsg_audit(buf, len);
3638 if (ret < 0) {
3639 return ret;
3640 }
3641
3642 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003643}
3644
3645static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3646{
Laurent Vivieref759f62016-06-21 19:51:13 +02003647 abi_long ret;
3648
3649 ret = host_to_target_nlmsg_audit(buf, len);
3650 if (ret < 0) {
3651 return ret;
3652 }
3653
3654 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003655}
3656
3657static TargetFdTrans target_netlink_audit_trans = {
3658 .target_to_host_data = netlink_audit_target_to_host,
3659 .host_to_target_data = netlink_audit_host_to_target,
3660};
3661
ths0da46a62007-10-20 20:23:07 +00003662/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003663static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003664{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003665 int target_type = type;
3666 int ret;
3667
3668 ret = target_to_host_sock_type(&type);
3669 if (ret) {
3670 return ret;
3671 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003672
Laurent Vivier575b22b2016-06-02 22:14:15 +02003673 if (domain == PF_NETLINK && !(
3674#ifdef CONFIG_RTNETLINK
3675 protocol == NETLINK_ROUTE ||
3676#endif
3677 protocol == NETLINK_KOBJECT_UEVENT ||
3678 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003679 return -EPFNOSUPPORT;
3680 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003681
3682 if (domain == AF_PACKET ||
3683 (domain == AF_INET && type == SOCK_PACKET)) {
3684 protocol = tswap16(protocol);
3685 }
3686
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003687 ret = get_errno(socket(domain, type, protocol));
3688 if (ret >= 0) {
3689 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003690 if (type == SOCK_PACKET) {
3691 /* Manage an obsolete case :
3692 * if socket type is SOCK_PACKET, bind by name
3693 */
3694 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003695 } else if (domain == PF_NETLINK) {
3696 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003697#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003698 case NETLINK_ROUTE:
3699 fd_trans_register(ret, &target_netlink_route_trans);
3700 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003701#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003702 case NETLINK_KOBJECT_UEVENT:
3703 /* nothing to do: messages are strings */
3704 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003705 case NETLINK_AUDIT:
3706 fd_trans_register(ret, &target_netlink_audit_trans);
3707 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003708 default:
3709 g_assert_not_reached();
3710 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003711 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003712 }
3713 return ret;
bellard3532fa72006-06-24 15:06:03 +00003714}
3715
ths0da46a62007-10-20 20:23:07 +00003716/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003717static abi_long do_bind(int sockfd, abi_ulong target_addr,
3718 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003719{
aurel328f7aeaf2009-01-30 19:47:57 +00003720 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003721 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003722
Blue Swirl38724252010-09-18 05:53:14 +00003723 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003724 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003725 }
aurel328f7aeaf2009-01-30 19:47:57 +00003726
aurel32607175e2009-04-15 16:11:59 +00003727 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003728
Laurent Vivier7b36f782015-10-28 21:40:44 +01003729 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003730 if (ret)
3731 return ret;
3732
bellard3532fa72006-06-24 15:06:03 +00003733 return get_errno(bind(sockfd, addr, addrlen));
3734}
3735
ths0da46a62007-10-20 20:23:07 +00003736/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003737static abi_long do_connect(int sockfd, abi_ulong target_addr,
3738 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003739{
aurel328f7aeaf2009-01-30 19:47:57 +00003740 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003741 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003742
Blue Swirl38724252010-09-18 05:53:14 +00003743 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003744 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003745 }
aurel328f7aeaf2009-01-30 19:47:57 +00003746
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003747 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003748
Laurent Vivier7b36f782015-10-28 21:40:44 +01003749 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003750 if (ret)
3751 return ret;
3752
Peter Maydell2a3c7612016-06-06 19:58:03 +01003753 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003754}
3755
Alexander Graff19e00d2014-03-02 19:36:42 +00003756/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3757static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3758 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003759{
balrog6de645c2008-10-28 10:26:29 +00003760 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003761 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003762 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003763 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003764 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003765
bellard3532fa72006-06-24 15:06:03 +00003766 if (msgp->msg_name) {
3767 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003768 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003769 ret = target_to_host_sockaddr(fd, msg.msg_name,
3770 tswapal(msgp->msg_name),
3771 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003772 if (ret == -TARGET_EFAULT) {
3773 /* For connected sockets msg_name and msg_namelen must
3774 * be ignored, so returning EFAULT immediately is wrong.
3775 * Instead, pass a bad msg_name to the host kernel, and
3776 * let it decide whether to return EFAULT or not.
3777 */
3778 msg.msg_name = (void *)-1;
3779 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003780 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003781 }
bellard3532fa72006-06-24 15:06:03 +00003782 } else {
3783 msg.msg_name = NULL;
3784 msg.msg_namelen = 0;
3785 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003786 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003787 msg.msg_control = alloca(msg.msg_controllen);
3788 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003789
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003790 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003791 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003792
3793 if (count > IOV_MAX) {
3794 /* sendrcvmsg returns a different errno for this condition than
3795 * readv/writev, so we must catch it here before lock_iovec() does.
3796 */
3797 ret = -TARGET_EMSGSIZE;
3798 goto out2;
3799 }
3800
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003801 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3802 target_vec, count, send);
3803 if (vec == NULL) {
3804 ret = -host_to_target_errno(errno);
3805 goto out2;
3806 }
bellard3532fa72006-06-24 15:06:03 +00003807 msg.msg_iovlen = count;
3808 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003809
bellard3532fa72006-06-24 15:06:03 +00003810 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003811 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003812 void *host_msg;
3813
3814 host_msg = g_malloc(msg.msg_iov->iov_len);
3815 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3816 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003817 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003818 if (ret >= 0) {
3819 msg.msg_iov->iov_base = host_msg;
3820 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3821 }
3822 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003823 } else {
3824 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003825 if (ret == 0) {
3826 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3827 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003828 }
bellard3532fa72006-06-24 15:06:03 +00003829 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003830 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003831 if (!is_error(ret)) {
3832 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003833 if (fd_trans_host_to_target_data(fd)) {
3834 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003835 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003836 } else {
3837 ret = host_to_target_cmsg(msgp, &msg);
3838 }
Jing Huangca619062012-07-24 13:58:02 +00003839 if (!is_error(ret)) {
3840 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003841 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003842 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3843 msg.msg_name, msg.msg_namelen);
3844 if (ret) {
3845 goto out;
3846 }
3847 }
3848
balrog6de645c2008-10-28 10:26:29 +00003849 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003850 }
balrog6de645c2008-10-28 10:26:29 +00003851 }
bellard3532fa72006-06-24 15:06:03 +00003852 }
Jing Huangca619062012-07-24 13:58:02 +00003853
3854out:
bellard3532fa72006-06-24 15:06:03 +00003855 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003856out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003857 return ret;
3858}
3859
3860static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3861 int flags, int send)
3862{
3863 abi_long ret;
3864 struct target_msghdr *msgp;
3865
3866 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3867 msgp,
3868 target_msg,
3869 send ? 1 : 0)) {
3870 return -TARGET_EFAULT;
3871 }
3872 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003873 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003874 return ret;
3875}
3876
Alexander Graff19e00d2014-03-02 19:36:42 +00003877/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3878 * so it might not have this *mmsg-specific flag either.
3879 */
3880#ifndef MSG_WAITFORONE
3881#define MSG_WAITFORONE 0x10000
3882#endif
3883
3884static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3885 unsigned int vlen, unsigned int flags,
3886 int send)
3887{
3888 struct target_mmsghdr *mmsgp;
3889 abi_long ret = 0;
3890 int i;
3891
3892 if (vlen > UIO_MAXIOV) {
3893 vlen = UIO_MAXIOV;
3894 }
3895
3896 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3897 if (!mmsgp) {
3898 return -TARGET_EFAULT;
3899 }
3900
3901 for (i = 0; i < vlen; i++) {
3902 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3903 if (is_error(ret)) {
3904 break;
3905 }
3906 mmsgp[i].msg_len = tswap32(ret);
3907 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3908 if (flags & MSG_WAITFORONE) {
3909 flags |= MSG_DONTWAIT;
3910 }
3911 }
3912
3913 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3914
3915 /* Return number of datagrams sent if we sent any at all;
3916 * otherwise return the error.
3917 */
3918 if (i) {
3919 return i;
3920 }
3921 return ret;
3922}
Alexander Graff19e00d2014-03-02 19:36:42 +00003923
Peter Maydella94b4982013-02-08 04:35:04 +00003924/* do_accept4() Must return target values and target errnos. */
3925static abi_long do_accept4(int fd, abi_ulong target_addr,
3926 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003927{
bellard2f619692007-11-16 10:46:05 +00003928 socklen_t addrlen;
3929 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003930 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003931 int host_flags;
3932
3933 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003934
Peter Maydella94b4982013-02-08 04:35:04 +00003935 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003936 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003937 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003938
3939 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003940 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003941 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003942
Blue Swirl38724252010-09-18 05:53:14 +00003943 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003944 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003945 }
aurel328f7aeaf2009-01-30 19:47:57 +00003946
Arnaud Patard917507b2009-06-19 10:44:45 +03003947 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3948 return -TARGET_EINVAL;
3949
bellard2f619692007-11-16 10:46:05 +00003950 addr = alloca(addrlen);
3951
Peter Maydellff6dc132016-06-06 19:58:13 +01003952 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003953 if (!is_error(ret)) {
3954 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003955 if (put_user_u32(addrlen, target_addrlen_addr))
3956 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003957 }
3958 return ret;
3959}
3960
ths0da46a62007-10-20 20:23:07 +00003961/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003962static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003963 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003964{
bellard2f619692007-11-16 10:46:05 +00003965 socklen_t addrlen;
3966 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003967 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003968
bellard2f619692007-11-16 10:46:05 +00003969 if (get_user_u32(addrlen, target_addrlen_addr))
3970 return -TARGET_EFAULT;
3971
Blue Swirl38724252010-09-18 05:53:14 +00003972 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003973 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003974 }
aurel328f7aeaf2009-01-30 19:47:57 +00003975
Arnaud Patard917507b2009-06-19 10:44:45 +03003976 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3977 return -TARGET_EFAULT;
3978
bellard2f619692007-11-16 10:46:05 +00003979 addr = alloca(addrlen);
3980
pbrook1be9e1d2006-11-19 15:26:04 +00003981 ret = get_errno(getpeername(fd, addr, &addrlen));
3982 if (!is_error(ret)) {
3983 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003984 if (put_user_u32(addrlen, target_addrlen_addr))
3985 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003986 }
3987 return ret;
3988}
3989
ths0da46a62007-10-20 20:23:07 +00003990/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003991static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003992 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003993{
bellard2f619692007-11-16 10:46:05 +00003994 socklen_t addrlen;
3995 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003996 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003997
bellard2f619692007-11-16 10:46:05 +00003998 if (get_user_u32(addrlen, target_addrlen_addr))
3999 return -TARGET_EFAULT;
4000
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_EFAULT;
4007
bellard2f619692007-11-16 10:46:05 +00004008 addr = alloca(addrlen);
4009
pbrook1be9e1d2006-11-19 15:26:04 +00004010 ret = get_errno(getsockname(fd, addr, &addrlen));
4011 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_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004020static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00004021 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00004022{
4023 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00004024 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004025
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02004026 target_to_host_sock_type(&type);
4027
pbrook1be9e1d2006-11-19 15:26:04 +00004028 ret = get_errno(socketpair(domain, type, protocol, tab));
4029 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00004030 if (put_user_s32(tab[0], target_tab_addr)
4031 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
4032 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004033 }
4034 return ret;
4035}
4036
ths0da46a62007-10-20 20:23:07 +00004037/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004038static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
4039 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004040{
4041 void *addr;
4042 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02004043 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00004044 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004045
Blue Swirl38724252010-09-18 05:53:14 +00004046 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004047 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004048 }
aurel328f7aeaf2009-01-30 19:47:57 +00004049
bellard579a97f2007-11-11 14:26:47 +00004050 host_msg = lock_user(VERIFY_READ, msg, len, 1);
4051 if (!host_msg)
4052 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004053 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004054 copy_msg = host_msg;
4055 host_msg = g_malloc(len);
4056 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004057 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
4058 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004059 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004060 }
4061 }
pbrook1be9e1d2006-11-19 15:26:04 +00004062 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02004063 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01004064 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03004065 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004066 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03004067 }
Peter Maydell66687532016-06-06 19:58:04 +01004068 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004069 } else {
Peter Maydell66687532016-06-06 19:58:04 +01004070 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004071 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02004072fail:
4073 if (copy_msg) {
4074 g_free(host_msg);
4075 host_msg = copy_msg;
4076 }
pbrook1be9e1d2006-11-19 15:26:04 +00004077 unlock_user(host_msg, msg, 0);
4078 return ret;
4079}
4080
ths0da46a62007-10-20 20:23:07 +00004081/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004082static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4083 abi_ulong target_addr,
4084 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004085{
4086 socklen_t addrlen;
4087 void *addr;
4088 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004089 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004090
bellard579a97f2007-11-11 14:26:47 +00004091 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4092 if (!host_msg)
4093 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004094 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004095 if (get_user_u32(addrlen, target_addrlen)) {
4096 ret = -TARGET_EFAULT;
4097 goto fail;
4098 }
Blue Swirl38724252010-09-18 05:53:14 +00004099 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004100 ret = -TARGET_EINVAL;
4101 goto fail;
4102 }
pbrook1be9e1d2006-11-19 15:26:04 +00004103 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004104 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4105 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004106 } else {
4107 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004108 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004109 }
4110 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004111 if (fd_trans_host_to_target_data(fd)) {
4112 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4113 }
pbrook1be9e1d2006-11-19 15:26:04 +00004114 if (target_addr) {
4115 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004116 if (put_user_u32(addrlen, target_addrlen)) {
4117 ret = -TARGET_EFAULT;
4118 goto fail;
4119 }
pbrook1be9e1d2006-11-19 15:26:04 +00004120 }
4121 unlock_user(host_msg, msg, len);
4122 } else {
bellard2f619692007-11-16 10:46:05 +00004123fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004124 unlock_user(host_msg, msg, 0);
4125 }
4126 return ret;
4127}
4128
j_mayer32407102007-09-26 23:01:49 +00004129#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004130/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004131static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004132{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004133 static const unsigned nargs[] = { /* number of arguments per operation */
4134 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4135 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4136 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4137 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4138 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4139 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4140 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4141 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4142 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4143 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4144 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4145 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4146 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4147 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4148 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4149 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4150 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4151 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4152 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4153 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004154 };
4155 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004156 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004157
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004158 /* check the range of the first argument num */
4159 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4160 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4161 return -TARGET_EINVAL;
4162 }
4163 /* ensure we have space for args */
4164 if (nargs[num] > ARRAY_SIZE(a)) {
4165 return -TARGET_EINVAL;
4166 }
4167 /* collect the arguments in a[] according to nargs[] */
4168 for (i = 0; i < nargs[num]; ++i) {
4169 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4170 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004171 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004172 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004173 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004174 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004175 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004176 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004177 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004178 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004179 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004180 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004181 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004182 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004183 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004184 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004185 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004186 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004187 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004188 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004189 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004190 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004191 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004192 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004193 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004194 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004195 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004196 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004197 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004198 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004199 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004200 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004201 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004202 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004203 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004204 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004205 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4206 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4207 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4208 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4209 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4210 return do_accept4(a[0], a[1], a[2], a[3]);
4211 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4212 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4213 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4214 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004215 default:
4216 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004217 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004218 }
bellard31e31b82003-02-18 22:55:36 +00004219}
j_mayer32407102007-09-26 23:01:49 +00004220#endif
bellard31e31b82003-02-18 22:55:36 +00004221
bellard8853f862004-02-22 14:57:26 +00004222#define N_SHM_REGIONS 32
4223
4224static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004225 abi_ulong start;
4226 abi_ulong size;
4227 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004228} shm_regions[N_SHM_REGIONS];
4229
Peter Maydell005eb2a2016-07-15 16:50:47 +01004230#ifndef TARGET_SEMID64_DS
4231/* asm-generic version of this struct */
4232struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004233{
4234 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004235 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004236#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004237 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004238#endif
blueswir1992f48a2007-10-14 16:27:31 +00004239 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004240#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004241 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004242#endif
blueswir1992f48a2007-10-14 16:27:31 +00004243 abi_ulong sem_nsems;
4244 abi_ulong __unused3;
4245 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004246};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004247#endif
ths3eb6b042007-06-03 14:26:27 +00004248
bellard579a97f2007-11-11 14:26:47 +00004249static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4250 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004251{
4252 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004253 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004254
bellard579a97f2007-11-11 14:26:47 +00004255 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4256 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004257 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004258 host_ip->__key = tswap32(target_ip->__key);
4259 host_ip->uid = tswap32(target_ip->uid);
4260 host_ip->gid = tswap32(target_ip->gid);
4261 host_ip->cuid = tswap32(target_ip->cuid);
4262 host_ip->cgid = tswap32(target_ip->cgid);
4263#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4264 host_ip->mode = tswap32(target_ip->mode);
4265#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004266 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004267#endif
4268#if defined(TARGET_PPC)
4269 host_ip->__seq = tswap32(target_ip->__seq);
4270#else
4271 host_ip->__seq = tswap16(target_ip->__seq);
4272#endif
ths3eb6b042007-06-03 14:26:27 +00004273 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004274 return 0;
ths3eb6b042007-06-03 14:26:27 +00004275}
4276
bellard579a97f2007-11-11 14:26:47 +00004277static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4278 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004279{
4280 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004281 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004282
bellard579a97f2007-11-11 14:26:47 +00004283 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4284 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004285 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004286 target_ip->__key = tswap32(host_ip->__key);
4287 target_ip->uid = tswap32(host_ip->uid);
4288 target_ip->gid = tswap32(host_ip->gid);
4289 target_ip->cuid = tswap32(host_ip->cuid);
4290 target_ip->cgid = tswap32(host_ip->cgid);
4291#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4292 target_ip->mode = tswap32(host_ip->mode);
4293#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004294 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004295#endif
4296#if defined(TARGET_PPC)
4297 target_ip->__seq = tswap32(host_ip->__seq);
4298#else
4299 target_ip->__seq = tswap16(host_ip->__seq);
4300#endif
ths3eb6b042007-06-03 14:26:27 +00004301 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004302 return 0;
ths3eb6b042007-06-03 14:26:27 +00004303}
4304
bellard579a97f2007-11-11 14:26:47 +00004305static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4306 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004307{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004308 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004309
bellard579a97f2007-11-11 14:26:47 +00004310 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4311 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004312 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4313 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004314 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4315 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4316 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004317 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004318 return 0;
ths3eb6b042007-06-03 14:26:27 +00004319}
4320
bellard579a97f2007-11-11 14:26:47 +00004321static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4322 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004323{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004324 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004325
bellard579a97f2007-11-11 14:26:47 +00004326 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4327 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004328 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004329 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004330 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4331 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4332 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004333 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004334 return 0;
ths3eb6b042007-06-03 14:26:27 +00004335}
4336
aurel32e5289082009-04-18 16:16:12 +00004337struct target_seminfo {
4338 int semmap;
4339 int semmni;
4340 int semmns;
4341 int semmnu;
4342 int semmsl;
4343 int semopm;
4344 int semume;
4345 int semusz;
4346 int semvmx;
4347 int semaem;
4348};
4349
4350static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4351 struct seminfo *host_seminfo)
4352{
4353 struct target_seminfo *target_seminfo;
4354 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4355 return -TARGET_EFAULT;
4356 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4357 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4358 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4359 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4360 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4361 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4362 __put_user(host_seminfo->semume, &target_seminfo->semume);
4363 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4364 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4365 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4366 unlock_user_struct(target_seminfo, target_addr, 1);
4367 return 0;
4368}
4369
thsfa294812007-02-02 22:05:00 +00004370union semun {
4371 int val;
ths3eb6b042007-06-03 14:26:27 +00004372 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004373 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004374 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004375};
4376
ths3eb6b042007-06-03 14:26:27 +00004377union target_semun {
4378 int val;
aurel32e5289082009-04-18 16:16:12 +00004379 abi_ulong buf;
4380 abi_ulong array;
4381 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004382};
4383
aurel32e5289082009-04-18 16:16:12 +00004384static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4385 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004386{
aurel32e5289082009-04-18 16:16:12 +00004387 int nsems;
4388 unsigned short *array;
4389 union semun semun;
4390 struct semid_ds semid_ds;
4391 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004392
aurel32e5289082009-04-18 16:16:12 +00004393 semun.buf = &semid_ds;
4394
4395 ret = semctl(semid, 0, IPC_STAT, semun);
4396 if (ret == -1)
4397 return get_errno(ret);
4398
4399 nsems = semid_ds.sem_nsems;
4400
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304401 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004402 if (!*host_array) {
4403 return -TARGET_ENOMEM;
4404 }
aurel32e5289082009-04-18 16:16:12 +00004405 array = lock_user(VERIFY_READ, target_addr,
4406 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004407 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304408 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004409 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004410 }
aurel32e5289082009-04-18 16:16:12 +00004411
4412 for(i=0; i<nsems; i++) {
4413 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004414 }
aurel32e5289082009-04-18 16:16:12 +00004415 unlock_user(array, target_addr, 0);
4416
bellard579a97f2007-11-11 14:26:47 +00004417 return 0;
ths3eb6b042007-06-03 14:26:27 +00004418}
4419
aurel32e5289082009-04-18 16:16:12 +00004420static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4421 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004422{
aurel32e5289082009-04-18 16:16:12 +00004423 int nsems;
4424 unsigned short *array;
4425 union semun semun;
4426 struct semid_ds semid_ds;
4427 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004428
aurel32e5289082009-04-18 16:16:12 +00004429 semun.buf = &semid_ds;
4430
4431 ret = semctl(semid, 0, IPC_STAT, semun);
4432 if (ret == -1)
4433 return get_errno(ret);
4434
4435 nsems = semid_ds.sem_nsems;
4436
4437 array = lock_user(VERIFY_WRITE, target_addr,
4438 nsems*sizeof(unsigned short), 0);
4439 if (!array)
4440 return -TARGET_EFAULT;
4441
4442 for(i=0; i<nsems; i++) {
4443 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004444 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304445 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004446 unlock_user(array, target_addr, 1);
4447
bellard579a97f2007-11-11 14:26:47 +00004448 return 0;
ths3eb6b042007-06-03 14:26:27 +00004449}
4450
aurel32e5289082009-04-18 16:16:12 +00004451static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004452 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004453{
Stefan Weild1c002b2015-02-08 15:40:58 +01004454 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004455 union semun arg;
4456 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304457 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004458 struct seminfo seminfo;
4459 abi_long ret = -TARGET_EINVAL;
4460 abi_long err;
4461 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004462
4463 switch( cmd ) {
4464 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004465 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004466 /* In 64 bit cross-endian situations, we will erroneously pick up
4467 * the wrong half of the union for the "val" element. To rectify
4468 * this, the entire 8-byte structure is byteswapped, followed by
4469 * a swap of the 4 byte val field. In other cases, the data is
4470 * already in proper host byte order. */
4471 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4472 target_su.buf = tswapal(target_su.buf);
4473 arg.val = tswap32(target_su.val);
4474 } else {
4475 arg.val = target_su.val;
4476 }
aurel32e5289082009-04-18 16:16:12 +00004477 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004478 break;
4479 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004480 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004481 err = target_to_host_semarray(semid, &array, target_su.array);
4482 if (err)
4483 return err;
4484 arg.array = array;
4485 ret = get_errno(semctl(semid, semnum, cmd, arg));
4486 err = host_to_target_semarray(semid, target_su.array, &array);
4487 if (err)
4488 return err;
ths3eb6b042007-06-03 14:26:27 +00004489 break;
4490 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004491 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004492 case SEM_STAT:
4493 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4494 if (err)
4495 return err;
4496 arg.buf = &dsarg;
4497 ret = get_errno(semctl(semid, semnum, cmd, arg));
4498 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4499 if (err)
4500 return err;
ths3eb6b042007-06-03 14:26:27 +00004501 break;
aurel32e5289082009-04-18 16:16:12 +00004502 case IPC_INFO:
4503 case SEM_INFO:
4504 arg.__buf = &seminfo;
4505 ret = get_errno(semctl(semid, semnum, cmd, arg));
4506 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4507 if (err)
4508 return err;
4509 break;
4510 case IPC_RMID:
4511 case GETPID:
4512 case GETNCNT:
4513 case GETZCNT:
4514 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4515 break;
ths3eb6b042007-06-03 14:26:27 +00004516 }
4517
4518 return ret;
4519}
4520
aurel32e5289082009-04-18 16:16:12 +00004521struct target_sembuf {
4522 unsigned short sem_num;
4523 short sem_op;
4524 short sem_flg;
4525};
4526
4527static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4528 abi_ulong target_addr,
4529 unsigned nsops)
4530{
4531 struct target_sembuf *target_sembuf;
4532 int i;
4533
4534 target_sembuf = lock_user(VERIFY_READ, target_addr,
4535 nsops*sizeof(struct target_sembuf), 1);
4536 if (!target_sembuf)
4537 return -TARGET_EFAULT;
4538
4539 for(i=0; i<nsops; i++) {
4540 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4541 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4542 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4543 }
4544
4545 unlock_user(target_sembuf, target_addr, 0);
4546
4547 return 0;
4548}
4549
4550static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4551{
4552 struct sembuf sops[nsops];
4553
4554 if (target_to_host_sembuf(sops, ptr, nsops))
4555 return -TARGET_EFAULT;
4556
Peter Maydellffb7ee72016-06-06 19:58:12 +01004557 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004558}
4559
ths1bc012f2007-06-03 14:27:49 +00004560struct target_msqid_ds
4561{
aurel321c54ff92008-10-13 21:08:44 +00004562 struct target_ipc_perm msg_perm;
4563 abi_ulong msg_stime;
4564#if TARGET_ABI_BITS == 32
4565 abi_ulong __unused1;
4566#endif
4567 abi_ulong msg_rtime;
4568#if TARGET_ABI_BITS == 32
4569 abi_ulong __unused2;
4570#endif
4571 abi_ulong msg_ctime;
4572#if TARGET_ABI_BITS == 32
4573 abi_ulong __unused3;
4574#endif
4575 abi_ulong __msg_cbytes;
4576 abi_ulong msg_qnum;
4577 abi_ulong msg_qbytes;
4578 abi_ulong msg_lspid;
4579 abi_ulong msg_lrpid;
4580 abi_ulong __unused4;
4581 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004582};
4583
bellard579a97f2007-11-11 14:26:47 +00004584static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4585 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004586{
4587 struct target_msqid_ds *target_md;
4588
bellard579a97f2007-11-11 14:26:47 +00004589 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4590 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004591 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4592 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004593 host_md->msg_stime = tswapal(target_md->msg_stime);
4594 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4595 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4596 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4597 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4598 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4599 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4600 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004601 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004602 return 0;
ths1bc012f2007-06-03 14:27:49 +00004603}
4604
bellard579a97f2007-11-11 14:26:47 +00004605static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4606 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004607{
4608 struct target_msqid_ds *target_md;
4609
bellard579a97f2007-11-11 14:26:47 +00004610 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4611 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004612 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4613 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004614 target_md->msg_stime = tswapal(host_md->msg_stime);
4615 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4616 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4617 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4618 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4619 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4620 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4621 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004622 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004623 return 0;
ths1bc012f2007-06-03 14:27:49 +00004624}
4625
aurel321c54ff92008-10-13 21:08:44 +00004626struct target_msginfo {
4627 int msgpool;
4628 int msgmap;
4629 int msgmax;
4630 int msgmnb;
4631 int msgmni;
4632 int msgssz;
4633 int msgtql;
4634 unsigned short int msgseg;
4635};
4636
4637static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4638 struct msginfo *host_msginfo)
4639{
4640 struct target_msginfo *target_msginfo;
4641 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4642 return -TARGET_EFAULT;
4643 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4644 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4645 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4646 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4647 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4648 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4649 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4650 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4651 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004652 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004653}
4654
4655static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004656{
4657 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004658 struct msginfo msginfo;
4659 abi_long ret = -TARGET_EINVAL;
4660
4661 cmd &= 0xff;
4662
4663 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004664 case IPC_STAT:
4665 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004666 case MSG_STAT:
4667 if (target_to_host_msqid_ds(&dsarg,ptr))
4668 return -TARGET_EFAULT;
4669 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4670 if (host_to_target_msqid_ds(ptr,&dsarg))
4671 return -TARGET_EFAULT;
4672 break;
4673 case IPC_RMID:
4674 ret = get_errno(msgctl(msgid, cmd, NULL));
4675 break;
4676 case IPC_INFO:
4677 case MSG_INFO:
4678 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4679 if (host_to_target_msginfo(ptr, &msginfo))
4680 return -TARGET_EFAULT;
4681 break;
ths1bc012f2007-06-03 14:27:49 +00004682 }
aurel321c54ff92008-10-13 21:08:44 +00004683
ths1bc012f2007-06-03 14:27:49 +00004684 return ret;
4685}
4686
4687struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004688 abi_long mtype;
4689 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004690};
4691
blueswir1992f48a2007-10-14 16:27:31 +00004692static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004693 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004694{
4695 struct target_msgbuf *target_mb;
4696 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004697 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004698
Tom Mustaedcc5f92014-08-12 13:53:37 -05004699 if (msgsz < 0) {
4700 return -TARGET_EINVAL;
4701 }
4702
bellard579a97f2007-11-11 14:26:47 +00004703 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4704 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304705 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004706 if (!host_mb) {
4707 unlock_user_struct(target_mb, msgp, 0);
4708 return -TARGET_ENOMEM;
4709 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004710 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004711 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004712 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304713 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004714 unlock_user_struct(target_mb, msgp, 0);
4715
4716 return ret;
4717}
4718
blueswir1992f48a2007-10-14 16:27:31 +00004719static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004720 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004721 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004722{
4723 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004724 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004725 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004726 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004727
Peter Maydell99874f62016-05-20 19:00:56 +01004728 if (msgsz < 0) {
4729 return -TARGET_EINVAL;
4730 }
4731
bellard579a97f2007-11-11 14:26:47 +00004732 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4733 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004734
Peter Maydell415d8472016-05-20 19:00:57 +01004735 host_mb = g_try_malloc(msgsz + sizeof(long));
4736 if (!host_mb) {
4737 ret = -TARGET_ENOMEM;
4738 goto end;
4739 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004740 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004741
bellard579a97f2007-11-11 14:26:47 +00004742 if (ret > 0) {
4743 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4744 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4745 if (!target_mtext) {
4746 ret = -TARGET_EFAULT;
4747 goto end;
4748 }
aurel321c54ff92008-10-13 21:08:44 +00004749 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004750 unlock_user(target_mtext, target_mtext_addr, ret);
4751 }
aurel321c54ff92008-10-13 21:08:44 +00004752
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004753 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004754
bellard579a97f2007-11-11 14:26:47 +00004755end:
4756 if (target_mb)
4757 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004758 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004759 return ret;
4760}
4761
Riku Voipio88a8c982009-04-03 10:42:00 +03004762static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4763 abi_ulong target_addr)
4764{
4765 struct target_shmid_ds *target_sd;
4766
4767 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4768 return -TARGET_EFAULT;
4769 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4770 return -TARGET_EFAULT;
4771 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4772 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4773 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4774 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4775 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4776 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4777 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4778 unlock_user_struct(target_sd, target_addr, 0);
4779 return 0;
4780}
4781
4782static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4783 struct shmid_ds *host_sd)
4784{
4785 struct target_shmid_ds *target_sd;
4786
4787 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4788 return -TARGET_EFAULT;
4789 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4790 return -TARGET_EFAULT;
4791 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4792 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4793 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4794 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4795 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4796 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4797 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4798 unlock_user_struct(target_sd, target_addr, 1);
4799 return 0;
4800}
4801
4802struct target_shminfo {
4803 abi_ulong shmmax;
4804 abi_ulong shmmin;
4805 abi_ulong shmmni;
4806 abi_ulong shmseg;
4807 abi_ulong shmall;
4808};
4809
4810static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4811 struct shminfo *host_shminfo)
4812{
4813 struct target_shminfo *target_shminfo;
4814 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4815 return -TARGET_EFAULT;
4816 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4817 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4818 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4819 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4820 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4821 unlock_user_struct(target_shminfo, target_addr, 1);
4822 return 0;
4823}
4824
4825struct target_shm_info {
4826 int used_ids;
4827 abi_ulong shm_tot;
4828 abi_ulong shm_rss;
4829 abi_ulong shm_swp;
4830 abi_ulong swap_attempts;
4831 abi_ulong swap_successes;
4832};
4833
4834static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4835 struct shm_info *host_shm_info)
4836{
4837 struct target_shm_info *target_shm_info;
4838 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4839 return -TARGET_EFAULT;
4840 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4841 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4842 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4843 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4844 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4845 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4846 unlock_user_struct(target_shm_info, target_addr, 1);
4847 return 0;
4848}
4849
4850static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4851{
4852 struct shmid_ds dsarg;
4853 struct shminfo shminfo;
4854 struct shm_info shm_info;
4855 abi_long ret = -TARGET_EINVAL;
4856
4857 cmd &= 0xff;
4858
4859 switch(cmd) {
4860 case IPC_STAT:
4861 case IPC_SET:
4862 case SHM_STAT:
4863 if (target_to_host_shmid_ds(&dsarg, buf))
4864 return -TARGET_EFAULT;
4865 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4866 if (host_to_target_shmid_ds(buf, &dsarg))
4867 return -TARGET_EFAULT;
4868 break;
4869 case IPC_INFO:
4870 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4871 if (host_to_target_shminfo(buf, &shminfo))
4872 return -TARGET_EFAULT;
4873 break;
4874 case SHM_INFO:
4875 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4876 if (host_to_target_shm_info(buf, &shm_info))
4877 return -TARGET_EFAULT;
4878 break;
4879 case IPC_RMID:
4880 case SHM_LOCK:
4881 case SHM_UNLOCK:
4882 ret = get_errno(shmctl(shmid, cmd, NULL));
4883 break;
4884 }
4885
4886 return ret;
4887}
4888
Peter Maydellee8e7612016-07-11 16:48:11 +01004889#ifndef TARGET_FORCE_SHMLBA
4890/* For most architectures, SHMLBA is the same as the page size;
4891 * some architectures have larger values, in which case they should
4892 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4893 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4894 * and defining its own value for SHMLBA.
4895 *
4896 * The kernel also permits SHMLBA to be set by the architecture to a
4897 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4898 * this means that addresses are rounded to the large size if
4899 * SHM_RND is set but addresses not aligned to that size are not rejected
4900 * as long as they are at least page-aligned. Since the only architecture
4901 * which uses this is ia64 this code doesn't provide for that oddity.
4902 */
4903static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4904{
4905 return TARGET_PAGE_SIZE;
4906}
4907#endif
4908
4909static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4910 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004911{
4912 abi_long raddr;
4913 void *host_raddr;
4914 struct shmid_ds shm_info;
4915 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004916 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004917
4918 /* find out the length of the shared memory segment */
4919 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4920 if (is_error(ret)) {
4921 /* can't get length, bail out */
4922 return ret;
4923 }
4924
Peter Maydellee8e7612016-07-11 16:48:11 +01004925 shmlba = target_shmlba(cpu_env);
4926
4927 if (shmaddr & (shmlba - 1)) {
4928 if (shmflg & SHM_RND) {
4929 shmaddr &= ~(shmlba - 1);
4930 } else {
4931 return -TARGET_EINVAL;
4932 }
4933 }
Max Filippovebf9a362018-03-07 13:50:10 -08004934 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
4935 return -TARGET_EINVAL;
4936 }
Peter Maydellee8e7612016-07-11 16:48:11 +01004937
Riku Voipio88a8c982009-04-03 10:42:00 +03004938 mmap_lock();
4939
4940 if (shmaddr)
4941 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4942 else {
4943 abi_ulong mmap_start;
4944
4945 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4946
4947 if (mmap_start == -1) {
4948 errno = ENOMEM;
4949 host_raddr = (void *)-1;
4950 } else
4951 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4952 }
4953
4954 if (host_raddr == (void *)-1) {
4955 mmap_unlock();
4956 return get_errno((long)host_raddr);
4957 }
4958 raddr=h2g((unsigned long)host_raddr);
4959
4960 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4961 PAGE_VALID | PAGE_READ |
4962 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4963
4964 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004965 if (!shm_regions[i].in_use) {
4966 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004967 shm_regions[i].start = raddr;
4968 shm_regions[i].size = shm_info.shm_segsz;
4969 break;
4970 }
4971 }
4972
4973 mmap_unlock();
4974 return raddr;
4975
4976}
4977
4978static inline abi_long do_shmdt(abi_ulong shmaddr)
4979{
4980 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08004981 abi_long rv;
4982
4983 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03004984
4985 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004986 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4987 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004988 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004989 break;
4990 }
4991 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08004992 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03004993
Max Filippov3c5f6a52018-02-28 14:16:04 -08004994 mmap_unlock();
4995
4996 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03004997}
4998
aurel321c54ff92008-10-13 21:08:44 +00004999#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00005000/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00005001/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01005002static abi_long do_ipc(CPUArchState *cpu_env,
5003 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05005004 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00005005 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00005006{
5007 int version;
blueswir1992f48a2007-10-14 16:27:31 +00005008 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00005009
5010 version = call >> 16;
5011 call &= 0xffff;
5012
5013 switch (call) {
thsfa294812007-02-02 22:05:00 +00005014 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00005015 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00005016 break;
5017
5018 case IPCOP_semget:
5019 ret = get_errno(semget(first, second, third));
5020 break;
5021
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005022 case IPCOP_semctl: {
5023 /* The semun argument to semctl is passed by value, so dereference the
5024 * ptr argument. */
5025 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05005026 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01005027 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00005028 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005029 }
thsd96372e2007-02-02 22:05:44 +00005030
aurel321c54ff92008-10-13 21:08:44 +00005031 case IPCOP_msgget:
5032 ret = get_errno(msgget(first, second));
5033 break;
thsd96372e2007-02-02 22:05:44 +00005034
aurel321c54ff92008-10-13 21:08:44 +00005035 case IPCOP_msgsnd:
5036 ret = do_msgsnd(first, ptr, second, third);
5037 break;
thsd96372e2007-02-02 22:05:44 +00005038
aurel321c54ff92008-10-13 21:08:44 +00005039 case IPCOP_msgctl:
5040 ret = do_msgctl(first, second, ptr);
5041 break;
thsd96372e2007-02-02 22:05:44 +00005042
aurel321c54ff92008-10-13 21:08:44 +00005043 case IPCOP_msgrcv:
5044 switch (version) {
5045 case 0:
5046 {
5047 struct target_ipc_kludge {
5048 abi_long msgp;
5049 abi_long msgtyp;
5050 } *tmp;
thsd96372e2007-02-02 22:05:44 +00005051
aurel321c54ff92008-10-13 21:08:44 +00005052 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
5053 ret = -TARGET_EFAULT;
5054 break;
ths1bc012f2007-06-03 14:27:49 +00005055 }
aurel321c54ff92008-10-13 21:08:44 +00005056
Laurent Vivier79dd77d2012-12-20 11:00:11 +00005057 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00005058
5059 unlock_user_struct(tmp, ptr, 0);
5060 break;
5061 }
5062 default:
5063 ret = do_msgrcv(first, ptr, second, fifth, third);
5064 }
5065 break;
thsd96372e2007-02-02 22:05:44 +00005066
bellard8853f862004-02-22 14:57:26 +00005067 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03005068 switch (version) {
5069 default:
bellard5a4a8982007-11-11 17:39:18 +00005070 {
5071 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01005072 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03005073 if (is_error(raddr))
5074 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00005075 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00005076 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03005077 break;
5078 }
5079 case 1:
5080 ret = -TARGET_EINVAL;
5081 break;
bellard5a4a8982007-11-11 17:39:18 +00005082 }
bellard8853f862004-02-22 14:57:26 +00005083 break;
5084 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03005085 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00005086 break;
5087
5088 case IPCOP_shmget:
5089 /* IPC_* flag values are the same on all linux platforms */
5090 ret = get_errno(shmget(first, second, third));
5091 break;
5092
5093 /* IPC_* and SHM_* command values are the same on all linux platforms */
5094 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005095 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005096 break;
5097 default:
j_mayer32407102007-09-26 23:01:49 +00005098 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005099 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005100 break;
5101 }
5102 return ret;
5103}
j_mayer32407102007-09-26 23:01:49 +00005104#endif
bellard8853f862004-02-22 14:57:26 +00005105
bellard31e31b82003-02-18 22:55:36 +00005106/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005107
Blue Swirl001faf32009-05-13 17:53:17 +00005108#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005109#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5110enum {
5111#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005112STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005113};
5114#undef STRUCT
5115#undef STRUCT_SPECIAL
5116
Blue Swirl001faf32009-05-13 17:53:17 +00005117#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005118#define STRUCT_SPECIAL(name)
5119#include "syscall_types.h"
5120#undef STRUCT
5121#undef STRUCT_SPECIAL
5122
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005123typedef struct IOCTLEntry IOCTLEntry;
5124
5125typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005126 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005127
5128struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005129 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005130 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005131 const char *name;
5132 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005133 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005134 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005135};
bellard31e31b82003-02-18 22:55:36 +00005136
5137#define IOC_R 0x0001
5138#define IOC_W 0x0002
5139#define IOC_RW (IOC_R | IOC_W)
5140
5141#define MAX_STRUCT_SIZE 4096
5142
Peter Maydelldace20d2011-01-10 13:11:24 +00005143#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005144/* So fiemap access checks don't overflow on 32 bit systems.
5145 * This is very slightly smaller than the limit imposed by
5146 * the underlying kernel.
5147 */
5148#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5149 / sizeof(struct fiemap_extent))
5150
5151static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005152 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005153{
5154 /* The parameter for this ioctl is a struct fiemap followed
5155 * by an array of struct fiemap_extent whose size is set
5156 * in fiemap->fm_extent_count. The array is filled in by the
5157 * ioctl.
5158 */
5159 int target_size_in, target_size_out;
5160 struct fiemap *fm;
5161 const argtype *arg_type = ie->arg_type;
5162 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5163 void *argptr, *p;
5164 abi_long ret;
5165 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5166 uint32_t outbufsz;
5167 int free_fm = 0;
5168
5169 assert(arg_type[0] == TYPE_PTR);
5170 assert(ie->access == IOC_RW);
5171 arg_type++;
5172 target_size_in = thunk_type_size(arg_type, 0);
5173 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5174 if (!argptr) {
5175 return -TARGET_EFAULT;
5176 }
5177 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5178 unlock_user(argptr, arg, 0);
5179 fm = (struct fiemap *)buf_temp;
5180 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5181 return -TARGET_EINVAL;
5182 }
5183
5184 outbufsz = sizeof (*fm) +
5185 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5186
5187 if (outbufsz > MAX_STRUCT_SIZE) {
5188 /* We can't fit all the extents into the fixed size buffer.
5189 * Allocate one that is large enough and use it instead.
5190 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305191 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005192 if (!fm) {
5193 return -TARGET_ENOMEM;
5194 }
5195 memcpy(fm, buf_temp, sizeof(struct fiemap));
5196 free_fm = 1;
5197 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005198 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005199 if (!is_error(ret)) {
5200 target_size_out = target_size_in;
5201 /* An extent_count of 0 means we were only counting the extents
5202 * so there are no structs to copy
5203 */
5204 if (fm->fm_extent_count != 0) {
5205 target_size_out += fm->fm_mapped_extents * extent_size;
5206 }
5207 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5208 if (!argptr) {
5209 ret = -TARGET_EFAULT;
5210 } else {
5211 /* Convert the struct fiemap */
5212 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5213 if (fm->fm_extent_count != 0) {
5214 p = argptr + target_size_in;
5215 /* ...and then all the struct fiemap_extents */
5216 for (i = 0; i < fm->fm_mapped_extents; i++) {
5217 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5218 THUNK_TARGET);
5219 p += extent_size;
5220 }
5221 }
5222 unlock_user(argptr, arg, target_size_out);
5223 }
5224 }
5225 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305226 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005227 }
5228 return ret;
5229}
Peter Maydelldace20d2011-01-10 13:11:24 +00005230#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005231
Laurent Vivier059c2f22011-03-30 00:12:12 +02005232static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005233 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005234{
5235 const argtype *arg_type = ie->arg_type;
5236 int target_size;
5237 void *argptr;
5238 int ret;
5239 struct ifconf *host_ifconf;
5240 uint32_t outbufsz;
5241 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5242 int target_ifreq_size;
5243 int nb_ifreq;
5244 int free_buf = 0;
5245 int i;
5246 int target_ifc_len;
5247 abi_long target_ifc_buf;
5248 int host_ifc_len;
5249 char *host_ifc_buf;
5250
5251 assert(arg_type[0] == TYPE_PTR);
5252 assert(ie->access == IOC_RW);
5253
5254 arg_type++;
5255 target_size = thunk_type_size(arg_type, 0);
5256
5257 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5258 if (!argptr)
5259 return -TARGET_EFAULT;
5260 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5261 unlock_user(argptr, arg, 0);
5262
5263 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5264 target_ifc_len = host_ifconf->ifc_len;
5265 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5266
5267 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5268 nb_ifreq = target_ifc_len / target_ifreq_size;
5269 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5270
5271 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5272 if (outbufsz > MAX_STRUCT_SIZE) {
5273 /* We can't fit all the extents into the fixed size buffer.
5274 * Allocate one that is large enough and use it instead.
5275 */
5276 host_ifconf = malloc(outbufsz);
5277 if (!host_ifconf) {
5278 return -TARGET_ENOMEM;
5279 }
5280 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5281 free_buf = 1;
5282 }
5283 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5284
5285 host_ifconf->ifc_len = host_ifc_len;
5286 host_ifconf->ifc_buf = host_ifc_buf;
5287
Peter Maydell49ca6f32016-06-06 19:58:14 +01005288 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005289 if (!is_error(ret)) {
5290 /* convert host ifc_len to target ifc_len */
5291
5292 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5293 target_ifc_len = nb_ifreq * target_ifreq_size;
5294 host_ifconf->ifc_len = target_ifc_len;
5295
5296 /* restore target ifc_buf */
5297
5298 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5299
5300 /* copy struct ifconf to target user */
5301
5302 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5303 if (!argptr)
5304 return -TARGET_EFAULT;
5305 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5306 unlock_user(argptr, arg, target_size);
5307
5308 /* copy ifreq[] to target user */
5309
5310 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5311 for (i = 0; i < nb_ifreq ; i++) {
5312 thunk_convert(argptr + i * target_ifreq_size,
5313 host_ifc_buf + i * sizeof(struct ifreq),
5314 ifreq_arg_type, THUNK_TARGET);
5315 }
5316 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5317 }
5318
5319 if (free_buf) {
5320 free(host_ifconf);
5321 }
5322
5323 return ret;
5324}
5325
Alexander Graf56e904e2012-01-31 18:42:06 +01005326static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005327 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005328{
5329 void *argptr;
5330 struct dm_ioctl *host_dm;
5331 abi_long guest_data;
5332 uint32_t guest_data_size;
5333 int target_size;
5334 const argtype *arg_type = ie->arg_type;
5335 abi_long ret;
5336 void *big_buf = NULL;
5337 char *host_data;
5338
5339 arg_type++;
5340 target_size = thunk_type_size(arg_type, 0);
5341 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5342 if (!argptr) {
5343 ret = -TARGET_EFAULT;
5344 goto out;
5345 }
5346 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5347 unlock_user(argptr, arg, 0);
5348
5349 /* buf_temp is too small, so fetch things into a bigger buffer */
5350 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5351 memcpy(big_buf, buf_temp, target_size);
5352 buf_temp = big_buf;
5353 host_dm = big_buf;
5354
5355 guest_data = arg + host_dm->data_start;
5356 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005357 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005358 goto out;
5359 }
5360 guest_data_size = host_dm->data_size - host_dm->data_start;
5361 host_data = (char*)host_dm + host_dm->data_start;
5362
5363 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005364 if (!argptr) {
5365 ret = -TARGET_EFAULT;
5366 goto out;
5367 }
5368
Alexander Graf56e904e2012-01-31 18:42:06 +01005369 switch (ie->host_cmd) {
5370 case DM_REMOVE_ALL:
5371 case DM_LIST_DEVICES:
5372 case DM_DEV_CREATE:
5373 case DM_DEV_REMOVE:
5374 case DM_DEV_SUSPEND:
5375 case DM_DEV_STATUS:
5376 case DM_DEV_WAIT:
5377 case DM_TABLE_STATUS:
5378 case DM_TABLE_CLEAR:
5379 case DM_TABLE_DEPS:
5380 case DM_LIST_VERSIONS:
5381 /* no input data */
5382 break;
5383 case DM_DEV_RENAME:
5384 case DM_DEV_SET_GEOMETRY:
5385 /* data contains only strings */
5386 memcpy(host_data, argptr, guest_data_size);
5387 break;
5388 case DM_TARGET_MSG:
5389 memcpy(host_data, argptr, guest_data_size);
5390 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5391 break;
5392 case DM_TABLE_LOAD:
5393 {
5394 void *gspec = argptr;
5395 void *cur_data = host_data;
5396 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5397 int spec_size = thunk_type_size(arg_type, 0);
5398 int i;
5399
5400 for (i = 0; i < host_dm->target_count; i++) {
5401 struct dm_target_spec *spec = cur_data;
5402 uint32_t next;
5403 int slen;
5404
5405 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5406 slen = strlen((char*)gspec + spec_size) + 1;
5407 next = spec->next;
5408 spec->next = sizeof(*spec) + slen;
5409 strcpy((char*)&spec[1], gspec + spec_size);
5410 gspec += next;
5411 cur_data += spec->next;
5412 }
5413 break;
5414 }
5415 default:
5416 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005417 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005418 goto out;
5419 }
5420 unlock_user(argptr, guest_data, 0);
5421
Peter Maydell49ca6f32016-06-06 19:58:14 +01005422 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005423 if (!is_error(ret)) {
5424 guest_data = arg + host_dm->data_start;
5425 guest_data_size = host_dm->data_size - host_dm->data_start;
5426 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5427 switch (ie->host_cmd) {
5428 case DM_REMOVE_ALL:
5429 case DM_DEV_CREATE:
5430 case DM_DEV_REMOVE:
5431 case DM_DEV_RENAME:
5432 case DM_DEV_SUSPEND:
5433 case DM_DEV_STATUS:
5434 case DM_TABLE_LOAD:
5435 case DM_TABLE_CLEAR:
5436 case DM_TARGET_MSG:
5437 case DM_DEV_SET_GEOMETRY:
5438 /* no return data */
5439 break;
5440 case DM_LIST_DEVICES:
5441 {
5442 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5443 uint32_t remaining_data = guest_data_size;
5444 void *cur_data = argptr;
5445 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5446 int nl_size = 12; /* can't use thunk_size due to alignment */
5447
5448 while (1) {
5449 uint32_t next = nl->next;
5450 if (next) {
5451 nl->next = nl_size + (strlen(nl->name) + 1);
5452 }
5453 if (remaining_data < nl->next) {
5454 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5455 break;
5456 }
5457 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5458 strcpy(cur_data + nl_size, nl->name);
5459 cur_data += nl->next;
5460 remaining_data -= nl->next;
5461 if (!next) {
5462 break;
5463 }
5464 nl = (void*)nl + next;
5465 }
5466 break;
5467 }
5468 case DM_DEV_WAIT:
5469 case DM_TABLE_STATUS:
5470 {
5471 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5472 void *cur_data = argptr;
5473 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5474 int spec_size = thunk_type_size(arg_type, 0);
5475 int i;
5476
5477 for (i = 0; i < host_dm->target_count; i++) {
5478 uint32_t next = spec->next;
5479 int slen = strlen((char*)&spec[1]) + 1;
5480 spec->next = (cur_data - argptr) + spec_size + slen;
5481 if (guest_data_size < spec->next) {
5482 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5483 break;
5484 }
5485 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5486 strcpy(cur_data + spec_size, (char*)&spec[1]);
5487 cur_data = argptr + spec->next;
5488 spec = (void*)host_dm + host_dm->data_start + next;
5489 }
5490 break;
5491 }
5492 case DM_TABLE_DEPS:
5493 {
5494 void *hdata = (void*)host_dm + host_dm->data_start;
5495 int count = *(uint32_t*)hdata;
5496 uint64_t *hdev = hdata + 8;
5497 uint64_t *gdev = argptr + 8;
5498 int i;
5499
5500 *(uint32_t*)argptr = tswap32(count);
5501 for (i = 0; i < count; i++) {
5502 *gdev = tswap64(*hdev);
5503 gdev++;
5504 hdev++;
5505 }
5506 break;
5507 }
5508 case DM_LIST_VERSIONS:
5509 {
5510 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5511 uint32_t remaining_data = guest_data_size;
5512 void *cur_data = argptr;
5513 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5514 int vers_size = thunk_type_size(arg_type, 0);
5515
5516 while (1) {
5517 uint32_t next = vers->next;
5518 if (next) {
5519 vers->next = vers_size + (strlen(vers->name) + 1);
5520 }
5521 if (remaining_data < vers->next) {
5522 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5523 break;
5524 }
5525 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5526 strcpy(cur_data + vers_size, vers->name);
5527 cur_data += vers->next;
5528 remaining_data -= vers->next;
5529 if (!next) {
5530 break;
5531 }
5532 vers = (void*)vers + next;
5533 }
5534 break;
5535 }
5536 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005537 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005538 ret = -TARGET_EINVAL;
5539 goto out;
5540 }
5541 unlock_user(argptr, guest_data, guest_data_size);
5542
5543 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5544 if (!argptr) {
5545 ret = -TARGET_EFAULT;
5546 goto out;
5547 }
5548 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5549 unlock_user(argptr, arg, target_size);
5550 }
5551out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005552 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005553 return ret;
5554}
5555
Alexander Grafa59b5e32014-08-22 13:15:50 +02005556static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005557 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005558{
5559 void *argptr;
5560 int target_size;
5561 const argtype *arg_type = ie->arg_type;
5562 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5563 abi_long ret;
5564
5565 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5566 struct blkpg_partition host_part;
5567
5568 /* Read and convert blkpg */
5569 arg_type++;
5570 target_size = thunk_type_size(arg_type, 0);
5571 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5572 if (!argptr) {
5573 ret = -TARGET_EFAULT;
5574 goto out;
5575 }
5576 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5577 unlock_user(argptr, arg, 0);
5578
5579 switch (host_blkpg->op) {
5580 case BLKPG_ADD_PARTITION:
5581 case BLKPG_DEL_PARTITION:
5582 /* payload is struct blkpg_partition */
5583 break;
5584 default:
5585 /* Unknown opcode */
5586 ret = -TARGET_EINVAL;
5587 goto out;
5588 }
5589
5590 /* Read and convert blkpg->data */
5591 arg = (abi_long)(uintptr_t)host_blkpg->data;
5592 target_size = thunk_type_size(part_arg_type, 0);
5593 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5594 if (!argptr) {
5595 ret = -TARGET_EFAULT;
5596 goto out;
5597 }
5598 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5599 unlock_user(argptr, arg, 0);
5600
5601 /* Swizzle the data pointer to our local copy and call! */
5602 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005603 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005604
5605out:
5606 return ret;
5607}
5608
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005609static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005610 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005611{
5612 const argtype *arg_type = ie->arg_type;
5613 const StructEntry *se;
5614 const argtype *field_types;
5615 const int *dst_offsets, *src_offsets;
5616 int target_size;
5617 void *argptr;
5618 abi_ulong *target_rt_dev_ptr;
5619 unsigned long *host_rt_dev_ptr;
5620 abi_long ret;
5621 int i;
5622
5623 assert(ie->access == IOC_W);
5624 assert(*arg_type == TYPE_PTR);
5625 arg_type++;
5626 assert(*arg_type == TYPE_STRUCT);
5627 target_size = thunk_type_size(arg_type, 0);
5628 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5629 if (!argptr) {
5630 return -TARGET_EFAULT;
5631 }
5632 arg_type++;
5633 assert(*arg_type == (int)STRUCT_rtentry);
5634 se = struct_entries + *arg_type++;
5635 assert(se->convert[0] == NULL);
5636 /* convert struct here to be able to catch rt_dev string */
5637 field_types = se->field_types;
5638 dst_offsets = se->field_offsets[THUNK_HOST];
5639 src_offsets = se->field_offsets[THUNK_TARGET];
5640 for (i = 0; i < se->nb_fields; i++) {
5641 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5642 assert(*field_types == TYPE_PTRVOID);
5643 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5644 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5645 if (*target_rt_dev_ptr != 0) {
5646 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5647 tswapal(*target_rt_dev_ptr));
5648 if (!*host_rt_dev_ptr) {
5649 unlock_user(argptr, arg, 0);
5650 return -TARGET_EFAULT;
5651 }
5652 } else {
5653 *host_rt_dev_ptr = 0;
5654 }
5655 field_types++;
5656 continue;
5657 }
5658 field_types = thunk_convert(buf_temp + dst_offsets[i],
5659 argptr + src_offsets[i],
5660 field_types, THUNK_HOST);
5661 }
5662 unlock_user(argptr, arg, 0);
5663
Peter Maydell49ca6f32016-06-06 19:58:14 +01005664 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005665 if (*host_rt_dev_ptr != 0) {
5666 unlock_user((void *)*host_rt_dev_ptr,
5667 *target_rt_dev_ptr, 0);
5668 }
5669 return ret;
5670}
5671
Paul Burtonca56f5b2014-06-22 11:25:47 +01005672static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005673 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005674{
5675 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005676 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005677}
5678
Andreas Schwab2b74f622018-01-29 11:47:06 +01005679#ifdef TIOCGPTPEER
5680static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5681 int fd, int cmd, abi_long arg)
5682{
5683 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5684 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5685}
5686#endif
5687
blueswir19f106a72008-10-05 10:52:52 +00005688static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005689#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005690 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5691#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5692 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005693#define IOCTL_IGNORE(cmd) \
5694 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005695#include "ioctls.h"
5696 { 0, 0, },
5697};
5698
pbrook53a59602006-03-25 19:31:22 +00005699/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005700/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005701static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005702{
5703 const IOCTLEntry *ie;
5704 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005705 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005706 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005707 int target_size;
5708 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005709
5710 ie = ioctl_entries;
5711 for(;;) {
5712 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005713 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005714 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005715 }
5716 if (ie->target_cmd == cmd)
5717 break;
5718 ie++;
5719 }
5720 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005721#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005722 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005723#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005724 if (ie->do_ioctl) {
5725 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005726 } else if (!ie->host_cmd) {
5727 /* Some architectures define BSD ioctls in their headers
5728 that are not implemented in Linux. */
5729 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005730 }
5731
bellard31e31b82003-02-18 22:55:36 +00005732 switch(arg_type[0]) {
5733 case TYPE_NULL:
5734 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005735 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005736 break;
5737 case TYPE_PTRVOID:
5738 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005739 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005740 break;
5741 case TYPE_PTR:
5742 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005743 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005744 switch(ie->access) {
5745 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005746 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005747 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005748 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5749 if (!argptr)
5750 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005751 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5752 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005753 }
5754 break;
5755 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005756 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5757 if (!argptr)
5758 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005759 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5760 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005761 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005762 break;
5763 default:
5764 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005765 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5766 if (!argptr)
5767 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005768 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5769 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005770 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005771 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005772 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5773 if (!argptr)
5774 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005775 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5776 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005777 }
5778 break;
5779 }
5780 break;
5781 default:
j_mayer32407102007-09-26 23:01:49 +00005782 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5783 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005784 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005785 break;
5786 }
5787 return ret;
5788}
5789
blueswir1b39bc502008-10-05 10:51:10 +00005790static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005791 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5792 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5793 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5794 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5795 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5796 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5797 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5798 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5799 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5800 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5801 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5802 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5803 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5804 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5805 { 0, 0, 0, 0 }
5806};
5807
blueswir1b39bc502008-10-05 10:51:10 +00005808static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005809 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5810 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5811 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5812 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5813 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5814 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5815 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5816 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5817 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5818 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5819 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5820 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5821 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5822 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5823 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5824 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5825 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5826 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5827 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5828 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5829 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5830 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5831 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5832 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5833 { 0, 0, 0, 0 }
5834};
5835
blueswir1b39bc502008-10-05 10:51:10 +00005836static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005837 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5838 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5839 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5840 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5841 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5842 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5843 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5844 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5845 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5846 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5847 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5848 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5849 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5850 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5851 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5852 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5853 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5854 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5855 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5856 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5857 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5858 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5859 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5860 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5861 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5862 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5863 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5864 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5865 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5866 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5867 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5868 { 0, 0, 0, 0 }
5869};
5870
blueswir1b39bc502008-10-05 10:51:10 +00005871static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005872 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5873 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5874 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5875 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5876 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5877 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5878 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5879 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5880 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5881 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5882 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5883 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5884 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5885 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5886 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5887 { 0, 0, 0, 0 }
5888};
5889
5890static void target_to_host_termios (void *dst, const void *src)
5891{
5892 struct host_termios *host = dst;
5893 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005894
ths5fafdf22007-09-16 21:08:06 +00005895 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005896 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005897 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005898 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005899 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005900 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005901 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005902 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5903 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005904
Arnaud Patard44607122009-04-21 17:39:08 +03005905 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005906 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5907 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005908 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005909 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005910 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005911 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005912 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005913 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005914 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005915 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5916 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005917 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5918 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5919 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5920 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5921 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005922 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005923}
ths3b46e622007-09-17 08:09:54 +00005924
bellard31e31b82003-02-18 22:55:36 +00005925static void host_to_target_termios (void *dst, const void *src)
5926{
5927 struct target_termios *target = dst;
5928 const struct host_termios *host = src;
5929
ths5fafdf22007-09-16 21:08:06 +00005930 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005931 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005932 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005933 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005934 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005935 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005936 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005937 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5938 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005939
Arnaud Patard44607122009-04-21 17:39:08 +03005940 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005941 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5942 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5943 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5944 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5945 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5946 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5947 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5948 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5949 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5950 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5951 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5952 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5953 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5954 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5955 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5956 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5957 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5958}
5959
blueswir18e853dc2008-10-05 10:49:32 +00005960static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005961 .convert = { host_to_target_termios, target_to_host_termios },
5962 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5963 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5964};
5965
bellard5286db72003-06-05 00:57:30 +00005966static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005967 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5968 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5969 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5970 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5971 MAP_ANONYMOUS, MAP_ANONYMOUS },
5972 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5973 MAP_GROWSDOWN, MAP_GROWSDOWN },
5974 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5975 MAP_DENYWRITE, MAP_DENYWRITE },
5976 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5977 MAP_EXECUTABLE, MAP_EXECUTABLE },
5978 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
5979 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
5980 MAP_NORESERVE, MAP_NORESERVE },
5981 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
5982 /* MAP_STACK had been ignored by the kernel for quite some time.
5983 Recognize it for the target insofar as we do not want to pass
5984 it through to the host. */
5985 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
5986 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00005987};
5988
bellard2ab83ea2003-06-15 19:56:46 +00005989#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005990
5991/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005992static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005993
bellard03acab62007-11-11 14:57:14 +00005994static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005995{
5996 int size;
pbrook53a59602006-03-25 19:31:22 +00005997 void *p;
bellard6dbad632003-03-16 18:05:05 +00005998
5999 if (!ldt_table)
6000 return 0;
6001 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
6002 if (size > bytecount)
6003 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00006004 p = lock_user(VERIFY_WRITE, ptr, size, 0);
6005 if (!p)
bellard03acab62007-11-11 14:57:14 +00006006 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00006007 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00006008 memcpy(p, ldt_table, size);
6009 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00006010 return size;
6011}
6012
6013/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00006014static abi_long write_ldt(CPUX86State *env,
6015 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00006016{
6017 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00006018 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00006019 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00006020 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00006021 uint32_t *lp, entry_1, entry_2;
6022
6023 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00006024 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00006025 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00006026 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00006027 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006028 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00006029 ldt_info.limit = tswap32(target_ldt_info->limit);
6030 ldt_info.flags = tswap32(target_ldt_info->flags);
6031 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00006032
bellard6dbad632003-03-16 18:05:05 +00006033 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00006034 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006035 seg_32bit = ldt_info.flags & 1;
6036 contents = (ldt_info.flags >> 1) & 3;
6037 read_exec_only = (ldt_info.flags >> 3) & 1;
6038 limit_in_pages = (ldt_info.flags >> 4) & 1;
6039 seg_not_present = (ldt_info.flags >> 5) & 1;
6040 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00006041#ifdef TARGET_ABI32
6042 lm = 0;
6043#else
6044 lm = (ldt_info.flags >> 7) & 1;
6045#endif
bellard6dbad632003-03-16 18:05:05 +00006046 if (contents == 3) {
6047 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00006048 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006049 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00006050 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006051 }
6052 /* allocate the LDT */
6053 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006054 env->ldt.base = target_mmap(0,
6055 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6056 PROT_READ|PROT_WRITE,
6057 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6058 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006059 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00006060 memset(g2h(env->ldt.base), 0,
6061 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006062 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006063 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006064 }
6065
6066 /* NOTE: same code as Linux kernel */
6067 /* Allow LDTs to be cleared by the user. */
6068 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6069 if (oldmode ||
6070 (contents == 0 &&
6071 read_exec_only == 1 &&
6072 seg_32bit == 0 &&
6073 limit_in_pages == 0 &&
6074 seg_not_present == 1 &&
6075 useable == 0 )) {
6076 entry_1 = 0;
6077 entry_2 = 0;
6078 goto install;
6079 }
6080 }
ths3b46e622007-09-17 08:09:54 +00006081
bellard6dbad632003-03-16 18:05:05 +00006082 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6083 (ldt_info.limit & 0x0ffff);
6084 entry_2 = (ldt_info.base_addr & 0xff000000) |
6085 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6086 (ldt_info.limit & 0xf0000) |
6087 ((read_exec_only ^ 1) << 9) |
6088 (contents << 10) |
6089 ((seg_not_present ^ 1) << 15) |
6090 (seg_32bit << 22) |
6091 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006092 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006093 0x7000;
6094 if (!oldmode)
6095 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006096
bellard6dbad632003-03-16 18:05:05 +00006097 /* Install the new entry ... */
6098install:
6099 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6100 lp[0] = tswap32(entry_1);
6101 lp[1] = tswap32(entry_2);
6102 return 0;
6103}
6104
6105/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006106static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6107 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006108{
bellard03acab62007-11-11 14:57:14 +00006109 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006110
bellard6dbad632003-03-16 18:05:05 +00006111 switch (func) {
6112 case 0:
6113 ret = read_ldt(ptr, bytecount);
6114 break;
6115 case 1:
6116 ret = write_ldt(env, ptr, bytecount, 1);
6117 break;
6118 case 0x11:
6119 ret = write_ldt(env, ptr, bytecount, 0);
6120 break;
bellard03acab62007-11-11 14:57:14 +00006121 default:
6122 ret = -TARGET_ENOSYS;
6123 break;
bellard6dbad632003-03-16 18:05:05 +00006124 }
6125 return ret;
6126}
bellard1b6b0292003-03-22 17:31:38 +00006127
blueswir14583f582008-08-24 10:35:55 +00006128#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006129abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006130{
6131 uint64_t *gdt_table = g2h(env->gdt.base);
6132 struct target_modify_ldt_ldt_s ldt_info;
6133 struct target_modify_ldt_ldt_s *target_ldt_info;
6134 int seg_32bit, contents, read_exec_only, limit_in_pages;
6135 int seg_not_present, useable, lm;
6136 uint32_t *lp, entry_1, entry_2;
6137 int i;
6138
6139 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6140 if (!target_ldt_info)
6141 return -TARGET_EFAULT;
6142 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006143 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006144 ldt_info.limit = tswap32(target_ldt_info->limit);
6145 ldt_info.flags = tswap32(target_ldt_info->flags);
6146 if (ldt_info.entry_number == -1) {
6147 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6148 if (gdt_table[i] == 0) {
6149 ldt_info.entry_number = i;
6150 target_ldt_info->entry_number = tswap32(i);
6151 break;
6152 }
6153 }
6154 }
6155 unlock_user_struct(target_ldt_info, ptr, 1);
6156
6157 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6158 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6159 return -TARGET_EINVAL;
6160 seg_32bit = ldt_info.flags & 1;
6161 contents = (ldt_info.flags >> 1) & 3;
6162 read_exec_only = (ldt_info.flags >> 3) & 1;
6163 limit_in_pages = (ldt_info.flags >> 4) & 1;
6164 seg_not_present = (ldt_info.flags >> 5) & 1;
6165 useable = (ldt_info.flags >> 6) & 1;
6166#ifdef TARGET_ABI32
6167 lm = 0;
6168#else
6169 lm = (ldt_info.flags >> 7) & 1;
6170#endif
6171
6172 if (contents == 3) {
6173 if (seg_not_present == 0)
6174 return -TARGET_EINVAL;
6175 }
6176
6177 /* NOTE: same code as Linux kernel */
6178 /* Allow LDTs to be cleared by the user. */
6179 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6180 if ((contents == 0 &&
6181 read_exec_only == 1 &&
6182 seg_32bit == 0 &&
6183 limit_in_pages == 0 &&
6184 seg_not_present == 1 &&
6185 useable == 0 )) {
6186 entry_1 = 0;
6187 entry_2 = 0;
6188 goto install;
6189 }
6190 }
6191
6192 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6193 (ldt_info.limit & 0x0ffff);
6194 entry_2 = (ldt_info.base_addr & 0xff000000) |
6195 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6196 (ldt_info.limit & 0xf0000) |
6197 ((read_exec_only ^ 1) << 9) |
6198 (contents << 10) |
6199 ((seg_not_present ^ 1) << 15) |
6200 (seg_32bit << 22) |
6201 (limit_in_pages << 23) |
6202 (useable << 20) |
6203 (lm << 21) |
6204 0x7000;
6205
6206 /* Install the new entry ... */
6207install:
6208 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6209 lp[0] = tswap32(entry_1);
6210 lp[1] = tswap32(entry_2);
6211 return 0;
6212}
6213
blueswir18fcd3692008-08-17 20:26:25 +00006214static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006215{
6216 struct target_modify_ldt_ldt_s *target_ldt_info;
6217 uint64_t *gdt_table = g2h(env->gdt.base);
6218 uint32_t base_addr, limit, flags;
6219 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6220 int seg_not_present, useable, lm;
6221 uint32_t *lp, entry_1, entry_2;
6222
6223 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6224 if (!target_ldt_info)
6225 return -TARGET_EFAULT;
6226 idx = tswap32(target_ldt_info->entry_number);
6227 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6228 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6229 unlock_user_struct(target_ldt_info, ptr, 1);
6230 return -TARGET_EINVAL;
6231 }
6232 lp = (uint32_t *)(gdt_table + idx);
6233 entry_1 = tswap32(lp[0]);
6234 entry_2 = tswap32(lp[1]);
6235
6236 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6237 contents = (entry_2 >> 10) & 3;
6238 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6239 seg_32bit = (entry_2 >> 22) & 1;
6240 limit_in_pages = (entry_2 >> 23) & 1;
6241 useable = (entry_2 >> 20) & 1;
6242#ifdef TARGET_ABI32
6243 lm = 0;
6244#else
6245 lm = (entry_2 >> 21) & 1;
6246#endif
6247 flags = (seg_32bit << 0) | (contents << 1) |
6248 (read_exec_only << 3) | (limit_in_pages << 4) |
6249 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6250 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6251 base_addr = (entry_1 >> 16) |
6252 (entry_2 & 0xff000000) |
6253 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006254 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006255 target_ldt_info->limit = tswap32(limit);
6256 target_ldt_info->flags = tswap32(flags);
6257 unlock_user_struct(target_ldt_info, ptr, 1);
6258 return 0;
6259}
blueswir14583f582008-08-24 10:35:55 +00006260#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006261
bellardd2fd1af2007-11-14 18:08:56 +00006262#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006263abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006264{
Juan Quintela1add8692011-06-16 17:37:09 +01006265 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006266 abi_ulong val;
6267 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006268
bellardd2fd1af2007-11-14 18:08:56 +00006269 switch(code) {
6270 case TARGET_ARCH_SET_GS:
6271 case TARGET_ARCH_SET_FS:
6272 if (code == TARGET_ARCH_SET_GS)
6273 idx = R_GS;
6274 else
6275 idx = R_FS;
6276 cpu_x86_load_seg(env, idx, 0);
6277 env->segs[idx].base = addr;
6278 break;
6279 case TARGET_ARCH_GET_GS:
6280 case TARGET_ARCH_GET_FS:
6281 if (code == TARGET_ARCH_GET_GS)
6282 idx = R_GS;
6283 else
6284 idx = R_FS;
6285 val = env->segs[idx].base;
6286 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006287 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006288 break;
6289 default:
6290 ret = -TARGET_EINVAL;
6291 break;
6292 }
Juan Quintela1add8692011-06-16 17:37:09 +01006293 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006294}
6295#endif
6296
bellard2ab83ea2003-06-15 19:56:46 +00006297#endif /* defined(TARGET_I386) */
6298
Riku Voipio05098a92011-03-04 15:27:29 +02006299#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006300
pbrookd865bab2008-06-07 22:12:17 +00006301
6302static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6303typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006304 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006305 pthread_mutex_t mutex;
6306 pthread_cond_t cond;
6307 pthread_t thread;
6308 uint32_t tid;
6309 abi_ulong child_tidptr;
6310 abi_ulong parent_tidptr;
6311 sigset_t sigmask;
6312} new_thread_info;
6313
6314static void *clone_func(void *arg)
6315{
6316 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006317 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006318 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006319 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006320
Emilio G. Cota70903762015-08-23 20:23:41 -04006321 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006322 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006323 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006324 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006325 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006326 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006327 info->tid = gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006328 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006329 if (info->child_tidptr)
6330 put_user_u32(info->tid, info->child_tidptr);
6331 if (info->parent_tidptr)
6332 put_user_u32(info->tid, info->parent_tidptr);
6333 /* Enable signals. */
6334 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6335 /* Signal to the parent that we're ready. */
6336 pthread_mutex_lock(&info->mutex);
6337 pthread_cond_broadcast(&info->cond);
6338 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006339 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006340 pthread_mutex_lock(&clone_lock);
6341 pthread_mutex_unlock(&clone_lock);
6342 cpu_loop(env);
6343 /* never exits */
6344 return NULL;
6345}
bellard1b6b0292003-03-22 17:31:38 +00006346
ths0da46a62007-10-20 20:23:07 +00006347/* do_fork() Must return host values and target errnos (unlike most
6348 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006349static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006350 abi_ulong parent_tidptr, target_ulong newtls,
6351 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006352{
Andreas Färber0429a972013-08-26 18:14:44 +02006353 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006354 int ret;
bellard5cd43932003-03-29 16:54:36 +00006355 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006356 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006357 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006358 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006359
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006360 flags &= ~CLONE_IGNORED_FLAGS;
6361
balrog436d1242008-09-21 02:39:45 +00006362 /* Emulate vfork() with fork() */
6363 if (flags & CLONE_VFORK)
6364 flags &= ~(CLONE_VFORK | CLONE_VM);
6365
bellard1b6b0292003-03-22 17:31:38 +00006366 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006367 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006368 new_thread_info info;
6369 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006370
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006371 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6372 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6373 return -TARGET_EINVAL;
6374 }
6375
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006376 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006377 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006378
6379 /* Grab a mutex so that thread setup appears atomic. */
6380 pthread_mutex_lock(&clone_lock);
6381
bellard1b6b0292003-03-22 17:31:38 +00006382 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006383 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006384 /* Init regs that differ from the parent. */
6385 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006386 new_cpu = ENV_GET_CPU(new_env);
6387 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006388 ts->bprm = parent_ts->bprm;
6389 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006390 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006391
Peter Maydell7cfbd382016-08-02 18:41:26 +01006392 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006393 ts->child_tidptr = child_tidptr;
6394 }
6395
Peter Maydell7cfbd382016-08-02 18:41:26 +01006396 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006397 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006398 }
pbrookd865bab2008-06-07 22:12:17 +00006399
pbrookd865bab2008-06-07 22:12:17 +00006400 memset(&info, 0, sizeof(info));
6401 pthread_mutex_init(&info.mutex, NULL);
6402 pthread_mutex_lock(&info.mutex);
6403 pthread_cond_init(&info.cond, NULL);
6404 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006405 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006406 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006407 }
6408 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006409 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006410 }
pbrookd865bab2008-06-07 22:12:17 +00006411
6412 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006413 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6414 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006415 /* It is not safe to deliver signals until the child has finished
6416 initializing, so temporarily block all signals. */
6417 sigfillset(&sigmask);
6418 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6419
Alex Bennéeb67cb682016-10-05 11:13:04 -07006420 /* If this is our first additional thread, we need to ensure we
6421 * generate code for parallel execution and flush old translations.
6422 */
6423 if (!parallel_cpus) {
6424 parallel_cpus = true;
6425 tb_flush(cpu);
6426 }
6427
pbrookd865bab2008-06-07 22:12:17 +00006428 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006429 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006430
6431 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6432 pthread_attr_destroy(&attr);
6433 if (ret == 0) {
6434 /* Wait for the child to initialize. */
6435 pthread_cond_wait(&info.cond, &info.mutex);
6436 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006437 } else {
6438 ret = -1;
6439 }
6440 pthread_mutex_unlock(&info.mutex);
6441 pthread_cond_destroy(&info.cond);
6442 pthread_mutex_destroy(&info.mutex);
6443 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006444 } else {
6445 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006446 if (flags & CLONE_INVALID_FORK_FLAGS) {
6447 return -TARGET_EINVAL;
6448 }
6449
6450 /* We can't support custom termination signals */
6451 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006452 return -TARGET_EINVAL;
6453 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006454
6455 if (block_signals()) {
6456 return -TARGET_ERESTARTSYS;
6457 }
6458
pbrookd865bab2008-06-07 22:12:17 +00006459 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006460 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006461 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006462 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00006463 cpu_clone_regs(env, newsp);
6464 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006465 /* There is a race condition here. The parent process could
6466 theoretically read the TID in the child process before the child
6467 tid is set. This would require using either ptrace
6468 (not implemented) or having *_tidptr to point at a shared memory
6469 mapping. We can't repeat the spinlock hack used above because
6470 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006471 if (flags & CLONE_CHILD_SETTID)
6472 put_user_u32(gettid(), child_tidptr);
6473 if (flags & CLONE_PARENT_SETTID)
6474 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006475 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006476 if (flags & CLONE_SETTLS)
6477 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006478 if (flags & CLONE_CHILD_CLEARTID)
6479 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006480 } else {
6481 fork_end(0);
6482 }
bellard1b6b0292003-03-22 17:31:38 +00006483 }
6484 return ret;
6485}
6486
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006487/* warning : doesn't handle linux specific flags... */
6488static int target_to_host_fcntl_cmd(int cmd)
6489{
6490 switch(cmd) {
6491 case TARGET_F_DUPFD:
6492 case TARGET_F_GETFD:
6493 case TARGET_F_SETFD:
6494 case TARGET_F_GETFL:
6495 case TARGET_F_SETFL:
6496 return cmd;
6497 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006498 return F_GETLK64;
6499 case TARGET_F_SETLK:
6500 return F_SETLK64;
6501 case TARGET_F_SETLKW:
6502 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006503 case TARGET_F_GETOWN:
6504 return F_GETOWN;
6505 case TARGET_F_SETOWN:
6506 return F_SETOWN;
6507 case TARGET_F_GETSIG:
6508 return F_GETSIG;
6509 case TARGET_F_SETSIG:
6510 return F_SETSIG;
6511#if TARGET_ABI_BITS == 32
6512 case TARGET_F_GETLK64:
6513 return F_GETLK64;
6514 case TARGET_F_SETLK64:
6515 return F_SETLK64;
6516 case TARGET_F_SETLKW64:
6517 return F_SETLKW64;
6518#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006519 case TARGET_F_SETLEASE:
6520 return F_SETLEASE;
6521 case TARGET_F_GETLEASE:
6522 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006523#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006524 case TARGET_F_DUPFD_CLOEXEC:
6525 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006526#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006527 case TARGET_F_NOTIFY:
6528 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006529#ifdef F_GETOWN_EX
6530 case TARGET_F_GETOWN_EX:
6531 return F_GETOWN_EX;
6532#endif
6533#ifdef F_SETOWN_EX
6534 case TARGET_F_SETOWN_EX:
6535 return F_SETOWN_EX;
6536#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006537#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006538 case TARGET_F_SETPIPE_SZ:
6539 return F_SETPIPE_SZ;
6540 case TARGET_F_GETPIPE_SZ:
6541 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006542#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006543 default:
6544 return -TARGET_EINVAL;
6545 }
6546 return -TARGET_EINVAL;
6547}
6548
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006549#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6550static const bitmask_transtbl flock_tbl[] = {
6551 TRANSTBL_CONVERT(F_RDLCK),
6552 TRANSTBL_CONVERT(F_WRLCK),
6553 TRANSTBL_CONVERT(F_UNLCK),
6554 TRANSTBL_CONVERT(F_EXLCK),
6555 TRANSTBL_CONVERT(F_SHLCK),
6556 { 0, 0, 0, 0 }
6557};
6558
Peter Maydell213d3e92016-06-13 11:22:05 +01006559static inline abi_long copy_from_user_flock(struct flock64 *fl,
6560 abi_ulong target_flock_addr)
6561{
6562 struct target_flock *target_fl;
6563 short l_type;
6564
6565 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6566 return -TARGET_EFAULT;
6567 }
6568
6569 __get_user(l_type, &target_fl->l_type);
6570 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6571 __get_user(fl->l_whence, &target_fl->l_whence);
6572 __get_user(fl->l_start, &target_fl->l_start);
6573 __get_user(fl->l_len, &target_fl->l_len);
6574 __get_user(fl->l_pid, &target_fl->l_pid);
6575 unlock_user_struct(target_fl, target_flock_addr, 0);
6576 return 0;
6577}
6578
6579static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6580 const struct flock64 *fl)
6581{
6582 struct target_flock *target_fl;
6583 short l_type;
6584
6585 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6586 return -TARGET_EFAULT;
6587 }
6588
6589 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6590 __put_user(l_type, &target_fl->l_type);
6591 __put_user(fl->l_whence, &target_fl->l_whence);
6592 __put_user(fl->l_start, &target_fl->l_start);
6593 __put_user(fl->l_len, &target_fl->l_len);
6594 __put_user(fl->l_pid, &target_fl->l_pid);
6595 unlock_user_struct(target_fl, target_flock_addr, 1);
6596 return 0;
6597}
6598
6599typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6600typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6601
6602#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6603static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6604 abi_ulong target_flock_addr)
6605{
6606 struct target_eabi_flock64 *target_fl;
6607 short l_type;
6608
6609 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6610 return -TARGET_EFAULT;
6611 }
6612
6613 __get_user(l_type, &target_fl->l_type);
6614 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6615 __get_user(fl->l_whence, &target_fl->l_whence);
6616 __get_user(fl->l_start, &target_fl->l_start);
6617 __get_user(fl->l_len, &target_fl->l_len);
6618 __get_user(fl->l_pid, &target_fl->l_pid);
6619 unlock_user_struct(target_fl, target_flock_addr, 0);
6620 return 0;
6621}
6622
6623static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6624 const struct flock64 *fl)
6625{
6626 struct target_eabi_flock64 *target_fl;
6627 short l_type;
6628
6629 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6630 return -TARGET_EFAULT;
6631 }
6632
6633 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6634 __put_user(l_type, &target_fl->l_type);
6635 __put_user(fl->l_whence, &target_fl->l_whence);
6636 __put_user(fl->l_start, &target_fl->l_start);
6637 __put_user(fl->l_len, &target_fl->l_len);
6638 __put_user(fl->l_pid, &target_fl->l_pid);
6639 unlock_user_struct(target_fl, target_flock_addr, 1);
6640 return 0;
6641}
6642#endif
6643
6644static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6645 abi_ulong target_flock_addr)
6646{
6647 struct target_flock64 *target_fl;
6648 short l_type;
6649
6650 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6651 return -TARGET_EFAULT;
6652 }
6653
6654 __get_user(l_type, &target_fl->l_type);
6655 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6656 __get_user(fl->l_whence, &target_fl->l_whence);
6657 __get_user(fl->l_start, &target_fl->l_start);
6658 __get_user(fl->l_len, &target_fl->l_len);
6659 __get_user(fl->l_pid, &target_fl->l_pid);
6660 unlock_user_struct(target_fl, target_flock_addr, 0);
6661 return 0;
6662}
6663
6664static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6665 const struct flock64 *fl)
6666{
6667 struct target_flock64 *target_fl;
6668 short l_type;
6669
6670 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6671 return -TARGET_EFAULT;
6672 }
6673
6674 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6675 __put_user(l_type, &target_fl->l_type);
6676 __put_user(fl->l_whence, &target_fl->l_whence);
6677 __put_user(fl->l_start, &target_fl->l_start);
6678 __put_user(fl->l_len, &target_fl->l_len);
6679 __put_user(fl->l_pid, &target_fl->l_pid);
6680 unlock_user_struct(target_fl, target_flock_addr, 1);
6681 return 0;
6682}
6683
blueswir1992f48a2007-10-14 16:27:31 +00006684static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006685{
ths43f238d2007-01-05 20:55:49 +00006686 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006687#ifdef F_GETOWN_EX
6688 struct f_owner_ex fox;
6689 struct target_f_owner_ex *target_fox;
6690#endif
blueswir1992f48a2007-10-14 16:27:31 +00006691 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006692 int host_cmd = target_to_host_fcntl_cmd(cmd);
6693
6694 if (host_cmd == -TARGET_EINVAL)
6695 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006696
bellard7775e9e2003-05-14 22:46:48 +00006697 switch(cmd) {
6698 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006699 ret = copy_from_user_flock(&fl64, arg);
6700 if (ret) {
6701 return ret;
6702 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006703 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006704 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006705 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006706 }
6707 break;
ths3b46e622007-09-17 08:09:54 +00006708
bellard7775e9e2003-05-14 22:46:48 +00006709 case TARGET_F_SETLK:
6710 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006711 ret = copy_from_user_flock(&fl64, arg);
6712 if (ret) {
6713 return ret;
6714 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006715 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006716 break;
ths3b46e622007-09-17 08:09:54 +00006717
bellard7775e9e2003-05-14 22:46:48 +00006718 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006719 ret = copy_from_user_flock64(&fl64, arg);
6720 if (ret) {
6721 return ret;
6722 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006723 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006724 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006725 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006726 }
bellard9ee1fa22007-11-11 15:11:19 +00006727 break;
bellard7775e9e2003-05-14 22:46:48 +00006728 case TARGET_F_SETLK64:
6729 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006730 ret = copy_from_user_flock64(&fl64, arg);
6731 if (ret) {
6732 return ret;
6733 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006734 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006735 break;
6736
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006737 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006738 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006739 if (ret >= 0) {
6740 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6741 }
bellardffa65c32004-01-04 23:57:22 +00006742 break;
6743
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006744 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006745 ret = get_errno(safe_fcntl(fd, host_cmd,
6746 target_to_host_bitmask(arg,
6747 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006748 break;
6749
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006750#ifdef F_GETOWN_EX
6751 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006752 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006753 if (ret >= 0) {
6754 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6755 return -TARGET_EFAULT;
6756 target_fox->type = tswap32(fox.type);
6757 target_fox->pid = tswap32(fox.pid);
6758 unlock_user_struct(target_fox, arg, 1);
6759 }
6760 break;
6761#endif
6762
6763#ifdef F_SETOWN_EX
6764 case TARGET_F_SETOWN_EX:
6765 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6766 return -TARGET_EFAULT;
6767 fox.type = tswap32(target_fox->type);
6768 fox.pid = tswap32(target_fox->pid);
6769 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006770 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006771 break;
6772#endif
6773
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006774 case TARGET_F_SETOWN:
6775 case TARGET_F_GETOWN:
6776 case TARGET_F_SETSIG:
6777 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006778 case TARGET_F_SETLEASE:
6779 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006780 case TARGET_F_SETPIPE_SZ:
6781 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006782 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006783 break;
6784
bellard7775e9e2003-05-14 22:46:48 +00006785 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006786 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006787 break;
6788 }
6789 return ret;
6790}
6791
bellard67867302003-11-23 17:05:30 +00006792#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006793
bellard67867302003-11-23 17:05:30 +00006794static inline int high2lowuid(int uid)
6795{
6796 if (uid > 65535)
6797 return 65534;
6798 else
6799 return uid;
6800}
6801
6802static inline int high2lowgid(int gid)
6803{
6804 if (gid > 65535)
6805 return 65534;
6806 else
6807 return gid;
6808}
6809
6810static inline int low2highuid(int uid)
6811{
6812 if ((int16_t)uid == -1)
6813 return -1;
6814 else
6815 return uid;
6816}
6817
6818static inline int low2highgid(int gid)
6819{
6820 if ((int16_t)gid == -1)
6821 return -1;
6822 else
6823 return gid;
6824}
Riku Voipio0c866a72011-04-18 15:23:06 +03006825static inline int tswapid(int id)
6826{
6827 return tswap16(id);
6828}
Peter Maydell76ca3102014-03-02 19:36:41 +00006829
6830#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6831
Riku Voipio0c866a72011-04-18 15:23:06 +03006832#else /* !USE_UID16 */
6833static inline int high2lowuid(int uid)
6834{
6835 return uid;
6836}
6837static inline int high2lowgid(int gid)
6838{
6839 return gid;
6840}
6841static inline int low2highuid(int uid)
6842{
6843 return uid;
6844}
6845static inline int low2highgid(int gid)
6846{
6847 return gid;
6848}
6849static inline int tswapid(int id)
6850{
6851 return tswap32(id);
6852}
Peter Maydell76ca3102014-03-02 19:36:41 +00006853
6854#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6855
bellard67867302003-11-23 17:05:30 +00006856#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006857
Peter Maydellfd6f7792016-03-01 16:33:02 +00006858/* We must do direct syscalls for setting UID/GID, because we want to
6859 * implement the Linux system call semantics of "change only for this thread",
6860 * not the libc/POSIX semantics of "change for all threads in process".
6861 * (See http://ewontfix.com/17/ for more details.)
6862 * We use the 32-bit version of the syscalls if present; if it is not
6863 * then either the host architecture supports 32-bit UIDs natively with
6864 * the standard syscall, or the 16-bit UID is the best we can do.
6865 */
6866#ifdef __NR_setuid32
6867#define __NR_sys_setuid __NR_setuid32
6868#else
6869#define __NR_sys_setuid __NR_setuid
6870#endif
6871#ifdef __NR_setgid32
6872#define __NR_sys_setgid __NR_setgid32
6873#else
6874#define __NR_sys_setgid __NR_setgid
6875#endif
6876#ifdef __NR_setresuid32
6877#define __NR_sys_setresuid __NR_setresuid32
6878#else
6879#define __NR_sys_setresuid __NR_setresuid
6880#endif
6881#ifdef __NR_setresgid32
6882#define __NR_sys_setresgid __NR_setresgid32
6883#else
6884#define __NR_sys_setresgid __NR_setresgid
6885#endif
6886
6887_syscall1(int, sys_setuid, uid_t, uid)
6888_syscall1(int, sys_setgid, gid_t, gid)
6889_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6890_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6891
bellard31e31b82003-02-18 22:55:36 +00006892void syscall_init(void)
6893{
bellard2ab83ea2003-06-15 19:56:46 +00006894 IOCTLEntry *ie;
6895 const argtype *arg_type;
6896 int size;
thsb92c47c2007-11-01 00:07:38 +00006897 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006898
Alexander Graf8be656b2015-05-06 23:47:32 +02006899 thunk_init(STRUCT_MAX);
6900
Blue Swirl001faf32009-05-13 17:53:17 +00006901#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006902#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006903#include "syscall_types.h"
6904#undef STRUCT
6905#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006906
Peter Maydelldd6e9572012-07-23 08:07:22 +00006907 /* Build target_to_host_errno_table[] table from
6908 * host_to_target_errno_table[]. */
6909 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6910 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6911 }
6912
bellard2ab83ea2003-06-15 19:56:46 +00006913 /* we patch the ioctl size if necessary. We rely on the fact that
6914 no ioctl has all the bits at '1' in the size field */
6915 ie = ioctl_entries;
6916 while (ie->target_cmd != 0) {
6917 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6918 TARGET_IOC_SIZEMASK) {
6919 arg_type = ie->arg_type;
6920 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006921 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006922 ie->target_cmd);
6923 exit(1);
6924 }
6925 arg_type++;
6926 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006927 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006928 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6929 (size << TARGET_IOC_SIZESHIFT);
6930 }
thsb92c47c2007-11-01 00:07:38 +00006931
bellard2ab83ea2003-06-15 19:56:46 +00006932 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006933#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6934 (defined(__x86_64__) && defined(TARGET_X86_64))
6935 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6936 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6937 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006938 }
6939#endif
6940 ie++;
6941 }
bellard31e31b82003-02-18 22:55:36 +00006942}
bellardc573ff62004-01-04 15:51:36 +00006943
blueswir1992f48a2007-10-14 16:27:31 +00006944#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006945static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6946{
thsaf325d32008-06-10 15:29:15 +00006947#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006948 return ((uint64_t)word0 << 32) | word1;
6949#else
6950 return ((uint64_t)word1 << 32) | word0;
6951#endif
6952}
blueswir1992f48a2007-10-14 16:27:31 +00006953#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006954static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6955{
6956 return word0;
6957}
blueswir1992f48a2007-10-14 16:27:31 +00006958#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006959
6960#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006961static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6962 abi_long arg2,
6963 abi_long arg3,
6964 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006965{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006966 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006967 arg2 = arg3;
6968 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006969 }
pbrookce4defa2006-02-09 16:49:55 +00006970 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6971}
6972#endif
6973
6974#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006975static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6976 abi_long arg2,
6977 abi_long arg3,
6978 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006979{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006980 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006981 arg2 = arg3;
6982 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006983 }
pbrookce4defa2006-02-09 16:49:55 +00006984 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6985}
6986#endif
6987
bellard579a97f2007-11-11 14:26:47 +00006988static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6989 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006990{
6991 struct target_timespec *target_ts;
6992
bellard579a97f2007-11-11 14:26:47 +00006993 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6994 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006995 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6996 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006997 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006998 return 0;
pbrook53a59602006-03-25 19:31:22 +00006999}
7000
bellard579a97f2007-11-11 14:26:47 +00007001static inline abi_long host_to_target_timespec(abi_ulong target_addr,
7002 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00007003{
7004 struct target_timespec *target_ts;
7005
bellard579a97f2007-11-11 14:26:47 +00007006 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
7007 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01007008 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
7009 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00007010 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00007011 return 0;
pbrook53a59602006-03-25 19:31:22 +00007012}
7013
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11007014static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
7015 abi_ulong target_addr)
7016{
7017 struct target_itimerspec *target_itspec;
7018
7019 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
7020 return -TARGET_EFAULT;
7021 }
7022
7023 host_itspec->it_interval.tv_sec =
7024 tswapal(target_itspec->it_interval.tv_sec);
7025 host_itspec->it_interval.tv_nsec =
7026 tswapal(target_itspec->it_interval.tv_nsec);
7027 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
7028 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
7029
7030 unlock_user_struct(target_itspec, target_addr, 1);
7031 return 0;
7032}
7033
7034static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
7035 struct itimerspec *host_its)
7036{
7037 struct target_itimerspec *target_itspec;
7038
7039 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
7040 return -TARGET_EFAULT;
7041 }
7042
7043 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
7044 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
7045
7046 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
7047 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
7048
7049 unlock_user_struct(target_itspec, target_addr, 0);
7050 return 0;
7051}
7052
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007053static inline abi_long target_to_host_timex(struct timex *host_tx,
7054 abi_long target_addr)
7055{
7056 struct target_timex *target_tx;
7057
7058 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7059 return -TARGET_EFAULT;
7060 }
7061
7062 __get_user(host_tx->modes, &target_tx->modes);
7063 __get_user(host_tx->offset, &target_tx->offset);
7064 __get_user(host_tx->freq, &target_tx->freq);
7065 __get_user(host_tx->maxerror, &target_tx->maxerror);
7066 __get_user(host_tx->esterror, &target_tx->esterror);
7067 __get_user(host_tx->status, &target_tx->status);
7068 __get_user(host_tx->constant, &target_tx->constant);
7069 __get_user(host_tx->precision, &target_tx->precision);
7070 __get_user(host_tx->tolerance, &target_tx->tolerance);
7071 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7072 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7073 __get_user(host_tx->tick, &target_tx->tick);
7074 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7075 __get_user(host_tx->jitter, &target_tx->jitter);
7076 __get_user(host_tx->shift, &target_tx->shift);
7077 __get_user(host_tx->stabil, &target_tx->stabil);
7078 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7079 __get_user(host_tx->calcnt, &target_tx->calcnt);
7080 __get_user(host_tx->errcnt, &target_tx->errcnt);
7081 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7082 __get_user(host_tx->tai, &target_tx->tai);
7083
7084 unlock_user_struct(target_tx, target_addr, 0);
7085 return 0;
7086}
7087
7088static inline abi_long host_to_target_timex(abi_long target_addr,
7089 struct timex *host_tx)
7090{
7091 struct target_timex *target_tx;
7092
7093 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7094 return -TARGET_EFAULT;
7095 }
7096
7097 __put_user(host_tx->modes, &target_tx->modes);
7098 __put_user(host_tx->offset, &target_tx->offset);
7099 __put_user(host_tx->freq, &target_tx->freq);
7100 __put_user(host_tx->maxerror, &target_tx->maxerror);
7101 __put_user(host_tx->esterror, &target_tx->esterror);
7102 __put_user(host_tx->status, &target_tx->status);
7103 __put_user(host_tx->constant, &target_tx->constant);
7104 __put_user(host_tx->precision, &target_tx->precision);
7105 __put_user(host_tx->tolerance, &target_tx->tolerance);
7106 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7107 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7108 __put_user(host_tx->tick, &target_tx->tick);
7109 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7110 __put_user(host_tx->jitter, &target_tx->jitter);
7111 __put_user(host_tx->shift, &target_tx->shift);
7112 __put_user(host_tx->stabil, &target_tx->stabil);
7113 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7114 __put_user(host_tx->calcnt, &target_tx->calcnt);
7115 __put_user(host_tx->errcnt, &target_tx->errcnt);
7116 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7117 __put_user(host_tx->tai, &target_tx->tai);
7118
7119 unlock_user_struct(target_tx, target_addr, 1);
7120 return 0;
7121}
7122
7123
Peter Maydellc0659762014-08-09 15:42:32 +01007124static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7125 abi_ulong target_addr)
7126{
7127 struct target_sigevent *target_sevp;
7128
7129 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7130 return -TARGET_EFAULT;
7131 }
7132
7133 /* This union is awkward on 64 bit systems because it has a 32 bit
7134 * integer and a pointer in it; we follow the conversion approach
7135 * used for handling sigval types in signal.c so the guest should get
7136 * the correct value back even if we did a 64 bit byteswap and it's
7137 * using the 32 bit integer.
7138 */
7139 host_sevp->sigev_value.sival_ptr =
7140 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7141 host_sevp->sigev_signo =
7142 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7143 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7144 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7145
7146 unlock_user_struct(target_sevp, target_addr, 1);
7147 return 0;
7148}
7149
Tom Musta6f6a4032014-08-12 13:53:42 -05007150#if defined(TARGET_NR_mlockall)
7151static inline int target_to_host_mlockall_arg(int arg)
7152{
7153 int result = 0;
7154
7155 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7156 result |= MCL_CURRENT;
7157 }
7158 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7159 result |= MCL_FUTURE;
7160 }
7161 return result;
7162}
7163#endif
7164
balrog6a24a772008-09-20 02:23:36 +00007165static inline abi_long host_to_target_stat64(void *cpu_env,
7166 abi_ulong target_addr,
7167 struct stat *host_st)
7168{
Alexander Graf09701192013-09-03 20:12:15 +01007169#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007170 if (((CPUARMState *)cpu_env)->eabi) {
7171 struct target_eabi_stat64 *target_st;
7172
7173 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7174 return -TARGET_EFAULT;
7175 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7176 __put_user(host_st->st_dev, &target_st->st_dev);
7177 __put_user(host_st->st_ino, &target_st->st_ino);
7178#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7179 __put_user(host_st->st_ino, &target_st->__st_ino);
7180#endif
7181 __put_user(host_st->st_mode, &target_st->st_mode);
7182 __put_user(host_st->st_nlink, &target_st->st_nlink);
7183 __put_user(host_st->st_uid, &target_st->st_uid);
7184 __put_user(host_st->st_gid, &target_st->st_gid);
7185 __put_user(host_st->st_rdev, &target_st->st_rdev);
7186 __put_user(host_st->st_size, &target_st->st_size);
7187 __put_user(host_st->st_blksize, &target_st->st_blksize);
7188 __put_user(host_st->st_blocks, &target_st->st_blocks);
7189 __put_user(host_st->st_atime, &target_st->target_st_atime);
7190 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7191 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7192 unlock_user_struct(target_st, target_addr, 1);
7193 } else
7194#endif
7195 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007196#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007197 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007198#else
7199 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007200#endif
balrog6a24a772008-09-20 02:23:36 +00007201
7202 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7203 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007204 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007205 __put_user(host_st->st_dev, &target_st->st_dev);
7206 __put_user(host_st->st_ino, &target_st->st_ino);
7207#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7208 __put_user(host_st->st_ino, &target_st->__st_ino);
7209#endif
7210 __put_user(host_st->st_mode, &target_st->st_mode);
7211 __put_user(host_st->st_nlink, &target_st->st_nlink);
7212 __put_user(host_st->st_uid, &target_st->st_uid);
7213 __put_user(host_st->st_gid, &target_st->st_gid);
7214 __put_user(host_st->st_rdev, &target_st->st_rdev);
7215 /* XXX: better use of kernel struct */
7216 __put_user(host_st->st_size, &target_st->st_size);
7217 __put_user(host_st->st_blksize, &target_st->st_blksize);
7218 __put_user(host_st->st_blocks, &target_st->st_blocks);
7219 __put_user(host_st->st_atime, &target_st->target_st_atime);
7220 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7221 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7222 unlock_user_struct(target_st, target_addr, 1);
7223 }
7224
7225 return 0;
7226}
balrog6a24a772008-09-20 02:23:36 +00007227
pbrookbd0c5662008-05-29 14:34:11 +00007228/* ??? Using host futex calls even when target atomic operations
7229 are not really atomic probably breaks things. However implementing
7230 futexes locally would make futexes shared between multiple processes
7231 tricky. However they're probably useless because guest atomic
7232 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007233static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7234 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007235{
7236 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007237 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007238
7239 /* ??? We assume FUTEX_* constants are the same on both host
7240 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007241#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007242 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007243#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007244 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007245#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007246 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007247 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007248 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007249 if (timeout) {
7250 pts = &ts;
7251 target_to_host_timespec(pts, timeout);
7252 } else {
7253 pts = NULL;
7254 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007255 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007256 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007257 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007258 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007259 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007260 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007261 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007262 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007263 case FUTEX_WAKE_OP:
7264 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7265 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7266 But the prototype takes a `struct timespec *'; insert casts
7267 to satisfy the compiler. We do not need to tswap TIMEOUT
7268 since it's not compared to guest memory. */
7269 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007270 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7271 g2h(uaddr2),
7272 (base_op == FUTEX_CMP_REQUEUE
7273 ? tswap32(val3)
7274 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007275 default:
7276 return -TARGET_ENOSYS;
7277 }
7278}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007279#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7280static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7281 abi_long handle, abi_long mount_id,
7282 abi_long flags)
7283{
7284 struct file_handle *target_fh;
7285 struct file_handle *fh;
7286 int mid = 0;
7287 abi_long ret;
7288 char *name;
7289 unsigned int size, total_size;
7290
7291 if (get_user_s32(size, handle)) {
7292 return -TARGET_EFAULT;
7293 }
7294
7295 name = lock_user_string(pathname);
7296 if (!name) {
7297 return -TARGET_EFAULT;
7298 }
7299
7300 total_size = sizeof(struct file_handle) + size;
7301 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7302 if (!target_fh) {
7303 unlock_user(name, pathname, 0);
7304 return -TARGET_EFAULT;
7305 }
7306
7307 fh = g_malloc0(total_size);
7308 fh->handle_bytes = size;
7309
7310 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7311 unlock_user(name, pathname, 0);
7312
7313 /* man name_to_handle_at(2):
7314 * Other than the use of the handle_bytes field, the caller should treat
7315 * the file_handle structure as an opaque data type
7316 */
7317
7318 memcpy(target_fh, fh, total_size);
7319 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7320 target_fh->handle_type = tswap32(fh->handle_type);
7321 g_free(fh);
7322 unlock_user(target_fh, handle, total_size);
7323
7324 if (put_user_s32(mid, mount_id)) {
7325 return -TARGET_EFAULT;
7326 }
7327
7328 return ret;
7329
7330}
7331#endif
7332
7333#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7334static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7335 abi_long flags)
7336{
7337 struct file_handle *target_fh;
7338 struct file_handle *fh;
7339 unsigned int size, total_size;
7340 abi_long ret;
7341
7342 if (get_user_s32(size, handle)) {
7343 return -TARGET_EFAULT;
7344 }
7345
7346 total_size = sizeof(struct file_handle) + size;
7347 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7348 if (!target_fh) {
7349 return -TARGET_EFAULT;
7350 }
7351
Thomas Huthe9d49d52015-10-09 17:56:38 +02007352 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007353 fh->handle_bytes = size;
7354 fh->handle_type = tswap32(target_fh->handle_type);
7355
7356 ret = get_errno(open_by_handle_at(mount_fd, fh,
7357 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7358
7359 g_free(fh);
7360
7361 unlock_user(target_fh, handle, total_size);
7362
7363 return ret;
7364}
7365#endif
pbrookbd0c5662008-05-29 14:34:11 +00007366
Laurent Viviere36800c2015-10-02 14:48:09 +02007367#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7368
7369/* signalfd siginfo conversion */
7370
7371static void
7372host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7373 const struct signalfd_siginfo *info)
7374{
7375 int sig = host_to_target_signal(info->ssi_signo);
7376
7377 /* linux/signalfd.h defines a ssi_addr_lsb
7378 * not defined in sys/signalfd.h but used by some kernels
7379 */
7380
7381#ifdef BUS_MCEERR_AO
7382 if (tinfo->ssi_signo == SIGBUS &&
7383 (tinfo->ssi_code == BUS_MCEERR_AR ||
7384 tinfo->ssi_code == BUS_MCEERR_AO)) {
7385 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7386 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7387 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7388 }
7389#endif
7390
7391 tinfo->ssi_signo = tswap32(sig);
7392 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7393 tinfo->ssi_code = tswap32(info->ssi_code);
7394 tinfo->ssi_pid = tswap32(info->ssi_pid);
7395 tinfo->ssi_uid = tswap32(info->ssi_uid);
7396 tinfo->ssi_fd = tswap32(info->ssi_fd);
7397 tinfo->ssi_tid = tswap32(info->ssi_tid);
7398 tinfo->ssi_band = tswap32(info->ssi_band);
7399 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7400 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7401 tinfo->ssi_status = tswap32(info->ssi_status);
7402 tinfo->ssi_int = tswap32(info->ssi_int);
7403 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7404 tinfo->ssi_utime = tswap64(info->ssi_utime);
7405 tinfo->ssi_stime = tswap64(info->ssi_stime);
7406 tinfo->ssi_addr = tswap64(info->ssi_addr);
7407}
7408
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007409static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007410{
7411 int i;
7412
7413 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7414 host_to_target_signalfd_siginfo(buf + i, buf + i);
7415 }
7416
7417 return len;
7418}
7419
7420static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007421 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007422};
7423
7424static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7425{
7426 int host_flags;
7427 target_sigset_t *target_mask;
7428 sigset_t host_mask;
7429 abi_long ret;
7430
7431 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7432 return -TARGET_EINVAL;
7433 }
7434 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7435 return -TARGET_EFAULT;
7436 }
7437
7438 target_to_host_sigset(&host_mask, target_mask);
7439
7440 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7441
7442 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7443 if (ret >= 0) {
7444 fd_trans_register(ret, &target_signalfd_trans);
7445 }
7446
7447 unlock_user_struct(target_mask, mask, 0);
7448
7449 return ret;
7450}
7451#endif
7452
pbrook1d9d8b52009-04-16 15:17:02 +00007453/* Map host to target signal numbers for the wait family of syscalls.
7454 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007455int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007456{
7457 if (WIFSIGNALED(status)) {
7458 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7459 }
7460 if (WIFSTOPPED(status)) {
7461 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7462 | (status & 0xff);
7463 }
7464 return status;
7465}
7466
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007467static int open_self_cmdline(void *cpu_env, int fd)
7468{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007469 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7470 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7471 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007472
Andreas Schwab58de8b92017-03-20 12:31:55 +01007473 for (i = 0; i < bprm->argc; i++) {
7474 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007475
Andreas Schwab58de8b92017-03-20 12:31:55 +01007476 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007477 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007478 }
7479 }
7480
Andreas Schwab58de8b92017-03-20 12:31:55 +01007481 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007482}
7483
Alexander Graf36c08d42011-11-02 20:23:24 +01007484static int open_self_maps(void *cpu_env, int fd)
7485{
Andreas Färber0429a972013-08-26 18:14:44 +02007486 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7487 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007488 FILE *fp;
7489 char *line = NULL;
7490 size_t len = 0;
7491 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007492
Alexander Graf1a49ef22012-05-01 16:30:28 +01007493 fp = fopen("/proc/self/maps", "r");
7494 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007495 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007496 }
7497
7498 while ((read = getline(&line, &len, fp)) != -1) {
7499 int fields, dev_maj, dev_min, inode;
7500 uint64_t min, max, offset;
7501 char flag_r, flag_w, flag_x, flag_p;
7502 char path[512] = "";
7503 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7504 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7505 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7506
7507 if ((fields < 10) || (fields > 11)) {
7508 continue;
7509 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007510 if (h2g_valid(min)) {
7511 int flags = page_get_flags(h2g(min));
Max Filippovebf9a362018-03-07 13:50:10 -08007512 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007513 if (page_check_range(h2g(min), max - min, flags) == -1) {
7514 continue;
7515 }
7516 if (h2g(min) == ts->info->stack_limit) {
7517 pstrcpy(path, sizeof(path), " [stack]");
7518 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007519 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007520 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007521 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007522 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007523 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007524 }
7525 }
7526
7527 free(line);
7528 fclose(fp);
7529
Alexander Graf36c08d42011-11-02 20:23:24 +01007530 return 0;
7531}
7532
Alexander Graf480b8e72011-11-02 20:23:25 +01007533static int open_self_stat(void *cpu_env, int fd)
7534{
Andreas Färber0429a972013-08-26 18:14:44 +02007535 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7536 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007537 abi_ulong start_stack = ts->info->start_stack;
7538 int i;
7539
7540 for (i = 0; i < 44; i++) {
7541 char buf[128];
7542 int len;
7543 uint64_t val = 0;
7544
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007545 if (i == 0) {
7546 /* pid */
7547 val = getpid();
7548 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7549 } else if (i == 1) {
7550 /* app name */
7551 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7552 } else if (i == 27) {
7553 /* stack bottom */
7554 val = start_stack;
7555 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7556 } else {
7557 /* for the rest, there is MasterCard */
7558 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007559 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007560
Alexander Graf480b8e72011-11-02 20:23:25 +01007561 len = strlen(buf);
7562 if (write(fd, buf, len) != len) {
7563 return -1;
7564 }
7565 }
7566
7567 return 0;
7568}
7569
Alexander Graf257450e2011-11-02 20:23:26 +01007570static int open_self_auxv(void *cpu_env, int fd)
7571{
Andreas Färber0429a972013-08-26 18:14:44 +02007572 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7573 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007574 abi_ulong auxv = ts->info->saved_auxv;
7575 abi_ulong len = ts->info->auxv_len;
7576 char *ptr;
7577
7578 /*
7579 * Auxiliary vector is stored in target process stack.
7580 * read in whole auxv vector and copy it to file
7581 */
7582 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7583 if (ptr != NULL) {
7584 while (len > 0) {
7585 ssize_t r;
7586 r = write(fd, ptr, len);
7587 if (r <= 0) {
7588 break;
7589 }
7590 len -= r;
7591 ptr += r;
7592 }
7593 lseek(fd, 0, SEEK_SET);
7594 unlock_user(ptr, auxv, len);
7595 }
7596
7597 return 0;
7598}
7599
Andreas Schwab463d8e72013-07-02 14:04:12 +01007600static int is_proc_myself(const char *filename, const char *entry)
7601{
7602 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7603 filename += strlen("/proc/");
7604 if (!strncmp(filename, "self/", strlen("self/"))) {
7605 filename += strlen("self/");
7606 } else if (*filename >= '1' && *filename <= '9') {
7607 char myself[80];
7608 snprintf(myself, sizeof(myself), "%d/", getpid());
7609 if (!strncmp(filename, myself, strlen(myself))) {
7610 filename += strlen(myself);
7611 } else {
7612 return 0;
7613 }
7614 } else {
7615 return 0;
7616 }
7617 if (!strcmp(filename, entry)) {
7618 return 1;
7619 }
7620 }
7621 return 0;
7622}
7623
Laurent Vivierde6b9932013-08-30 01:46:40 +02007624#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7625static int is_proc(const char *filename, const char *entry)
7626{
7627 return strcmp(filename, entry) == 0;
7628}
7629
7630static int open_net_route(void *cpu_env, int fd)
7631{
7632 FILE *fp;
7633 char *line = NULL;
7634 size_t len = 0;
7635 ssize_t read;
7636
7637 fp = fopen("/proc/net/route", "r");
7638 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007639 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007640 }
7641
7642 /* read header */
7643
7644 read = getline(&line, &len, fp);
7645 dprintf(fd, "%s", line);
7646
7647 /* read routes */
7648
7649 while ((read = getline(&line, &len, fp)) != -1) {
7650 char iface[16];
7651 uint32_t dest, gw, mask;
7652 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7653 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7654 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7655 &mask, &mtu, &window, &irtt);
7656 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7657 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7658 metric, tswap32(mask), mtu, window, irtt);
7659 }
7660
7661 free(line);
7662 fclose(fp);
7663
7664 return 0;
7665}
7666#endif
7667
Riku Voipio0b2effd2014-08-06 10:36:37 +03007668static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007669{
7670 struct fake_open {
7671 const char *filename;
7672 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007673 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007674 };
7675 const struct fake_open *fake_open;
7676 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007677 { "maps", open_self_maps, is_proc_myself },
7678 { "stat", open_self_stat, is_proc_myself },
7679 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007680 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007681#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7682 { "/proc/net/route", open_net_route, is_proc },
7683#endif
7684 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007685 };
7686
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007687 if (is_proc_myself(pathname, "exe")) {
7688 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007689 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007690 }
7691
Alexander Graf3be14d02011-11-02 20:23:23 +01007692 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007693 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007694 break;
7695 }
7696 }
7697
7698 if (fake_open->filename) {
7699 const char *tmpdir;
7700 char filename[PATH_MAX];
7701 int fd, r;
7702
7703 /* create temporary file to map stat to */
7704 tmpdir = getenv("TMPDIR");
7705 if (!tmpdir)
7706 tmpdir = "/tmp";
7707 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7708 fd = mkstemp(filename);
7709 if (fd < 0) {
7710 return fd;
7711 }
7712 unlink(filename);
7713
7714 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007715 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007716 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007717 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007718 return r;
7719 }
7720 lseek(fd, 0, SEEK_SET);
7721
7722 return fd;
7723 }
7724
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007725 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007726}
7727
Alexander Grafaecc8862014-11-10 21:33:03 +01007728#define TIMER_MAGIC 0x0caf0000
7729#define TIMER_MAGIC_MASK 0xffff0000
7730
7731/* Convert QEMU provided timer ID back to internal 16bit index format */
7732static target_timer_t get_timer_id(abi_long arg)
7733{
7734 target_timer_t timerid = arg;
7735
7736 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7737 return -TARGET_EINVAL;
7738 }
7739
7740 timerid &= 0xffff;
7741
7742 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7743 return -TARGET_EINVAL;
7744 }
7745
7746 return timerid;
7747}
7748
Laurent Vivier562a20b2017-03-01 10:37:48 +01007749static abi_long swap_data_eventfd(void *buf, size_t len)
7750{
7751 uint64_t *counter = buf;
7752 int i;
7753
7754 if (len < sizeof(uint64_t)) {
7755 return -EINVAL;
7756 }
7757
7758 for (i = 0; i < len; i += sizeof(uint64_t)) {
7759 *counter = tswap64(*counter);
7760 counter++;
7761 }
7762
7763 return len;
7764}
7765
7766static TargetFdTrans target_eventfd_trans = {
7767 .host_to_target_data = swap_data_eventfd,
7768 .target_to_host_data = swap_data_eventfd,
7769};
7770
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007771#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7772 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7773 defined(__NR_inotify_init1))
7774static abi_long host_to_target_data_inotify(void *buf, size_t len)
7775{
7776 struct inotify_event *ev;
7777 int i;
7778 uint32_t name_len;
7779
7780 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7781 ev = (struct inotify_event *)((char *)buf + i);
7782 name_len = ev->len;
7783
7784 ev->wd = tswap32(ev->wd);
7785 ev->mask = tswap32(ev->mask);
7786 ev->cookie = tswap32(ev->cookie);
7787 ev->len = tswap32(name_len);
7788 }
7789
7790 return len;
7791}
7792
7793static TargetFdTrans target_inotify_trans = {
7794 .host_to_target_data = host_to_target_data_inotify,
7795};
7796#endif
7797
Samuel Thibault2e0a8712018-01-09 21:16:43 +01007798static int target_to_host_cpu_mask(unsigned long *host_mask,
7799 size_t host_size,
7800 abi_ulong target_addr,
7801 size_t target_size)
7802{
7803 unsigned target_bits = sizeof(abi_ulong) * 8;
7804 unsigned host_bits = sizeof(*host_mask) * 8;
7805 abi_ulong *target_mask;
7806 unsigned i, j;
7807
7808 assert(host_size >= target_size);
7809
7810 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7811 if (!target_mask) {
7812 return -TARGET_EFAULT;
7813 }
7814 memset(host_mask, 0, host_size);
7815
7816 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7817 unsigned bit = i * target_bits;
7818 abi_ulong val;
7819
7820 __get_user(val, &target_mask[i]);
7821 for (j = 0; j < target_bits; j++, bit++) {
7822 if (val & (1UL << j)) {
7823 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7824 }
7825 }
7826 }
7827
7828 unlock_user(target_mask, target_addr, 0);
7829 return 0;
7830}
7831
7832static int host_to_target_cpu_mask(const unsigned long *host_mask,
7833 size_t host_size,
7834 abi_ulong target_addr,
7835 size_t target_size)
7836{
7837 unsigned target_bits = sizeof(abi_ulong) * 8;
7838 unsigned host_bits = sizeof(*host_mask) * 8;
7839 abi_ulong *target_mask;
7840 unsigned i, j;
7841
7842 assert(host_size >= target_size);
7843
7844 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7845 if (!target_mask) {
7846 return -TARGET_EFAULT;
7847 }
7848
7849 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7850 unsigned bit = i * target_bits;
7851 abi_ulong val = 0;
7852
7853 for (j = 0; j < target_bits; j++, bit++) {
7854 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7855 val |= 1UL << j;
7856 }
7857 }
7858 __put_user(val, &target_mask[i]);
7859 }
7860
7861 unlock_user(target_mask, target_addr, target_size);
7862 return 0;
7863}
7864
ths0da46a62007-10-20 20:23:07 +00007865/* do_syscall() should always have a single exit point at the end so
7866 that actions, such as logging of syscall results, can be performed.
7867 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007868abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7869 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007870 abi_long arg5, abi_long arg6, abi_long arg7,
7871 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007872{
Andreas Färber182735e2013-05-29 22:29:20 +02007873 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007874 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007875 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007876 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007877 void *p;
ths3b46e622007-09-17 08:09:54 +00007878
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007879#if defined(DEBUG_ERESTARTSYS)
7880 /* Debug-only code for exercising the syscall-restart code paths
7881 * in the per-architecture cpu main loops: restart every syscall
7882 * the guest makes once before letting it through.
7883 */
7884 {
7885 static int flag;
7886
7887 flag = !flag;
7888 if (flag) {
7889 return -TARGET_ERESTARTSYS;
7890 }
7891 }
7892#endif
7893
bellard72f03902003-02-18 23:33:18 +00007894#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007895 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007896#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007897 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007898 if(do_strace)
7899 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7900
bellard31e31b82003-02-18 22:55:36 +00007901 switch(num) {
7902 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007903 /* In old applications this may be used to implement _exit(2).
7904 However in threaded applictions it is used for thread termination,
7905 and _exit_group is used for application termination.
7906 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007907
7908 if (block_signals()) {
7909 ret = -TARGET_ERESTARTSYS;
7910 break;
7911 }
7912
Alex Bennéedd1f6342016-09-30 22:31:01 +01007913 cpu_list_lock();
7914
Andreas Färberbdc44642013-06-24 23:50:24 +02007915 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007916 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007917
Andreas Färber9b056fc2013-06-24 23:53:10 +02007918 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007919 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007920
Andreas Färber9b056fc2013-06-24 23:53:10 +02007921 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007922
Andreas Färber0429a972013-08-26 18:14:44 +02007923 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007924 if (ts->child_tidptr) {
7925 put_user_u32(0, ts->child_tidptr);
7926 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7927 NULL, NULL, 0);
7928 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007929 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007930 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007931 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007932 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007933 pthread_exit(NULL);
7934 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007935
7936 cpu_list_unlock();
Juan Quintela9788c9c2009-07-27 16:13:02 +02007937#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007938 _mcleanup();
7939#endif
bellarde9009672005-04-26 20:42:36 +00007940 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007941 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007942 ret = 0; /* avoid warning */
7943 break;
7944 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007945 if (arg3 == 0)
7946 ret = 0;
7947 else {
7948 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7949 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007950 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007951 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007952 fd_trans_host_to_target_data(arg1)) {
7953 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007954 }
aurel3238d840e2009-01-30 19:48:17 +00007955 unlock_user(p, arg2, ret);
7956 }
bellard31e31b82003-02-18 22:55:36 +00007957 break;
7958 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007959 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7960 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01007961 if (fd_trans_target_to_host_data(arg1)) {
7962 void *copy = g_malloc(arg3);
7963 memcpy(copy, p, arg3);
7964 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
7965 if (ret >= 0) {
7966 ret = get_errno(safe_write(arg1, copy, ret));
7967 }
7968 g_free(copy);
7969 } else {
7970 ret = get_errno(safe_write(arg1, p, arg3));
7971 }
pbrook53a59602006-03-25 19:31:22 +00007972 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007973 break;
Chen Gang704eff62015-08-21 05:37:33 +08007974#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007975 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007976 if (!(p = lock_user_string(arg1)))
7977 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007978 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7979 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7980 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007981 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007982 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007983 break;
Chen Gang704eff62015-08-21 05:37:33 +08007984#endif
ths82424832007-09-24 09:21:55 +00007985 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007986 if (!(p = lock_user_string(arg2)))
7987 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007988 ret = get_errno(do_openat(cpu_env, arg1, p,
7989 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7990 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007991 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007992 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007993 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007994#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7995 case TARGET_NR_name_to_handle_at:
7996 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7997 break;
7998#endif
7999#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
8000 case TARGET_NR_open_by_handle_at:
8001 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008002 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02008003 break;
8004#endif
bellard31e31b82003-02-18 22:55:36 +00008005 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02008006 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00008007 ret = get_errno(close(arg1));
8008 break;
8009 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00008010 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00008011 break;
Chen Gang704eff62015-08-21 05:37:33 +08008012#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00008013 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01008014 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008015 break;
Chen Gang704eff62015-08-21 05:37:33 +08008016#endif
thse5febef2007-04-01 18:31:35 +00008017#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00008018 case TARGET_NR_waitpid:
8019 {
pbrook53a59602006-03-25 19:31:22 +00008020 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008021 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01008022 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00008023 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00008024 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008025 }
8026 break;
thse5febef2007-04-01 18:31:35 +00008027#endif
pbrookf0cbb612008-05-30 18:20:05 +00008028#ifdef TARGET_NR_waitid
8029 case TARGET_NR_waitid:
8030 {
8031 siginfo_t info;
8032 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008033 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00008034 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008035 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00008036 goto efault;
8037 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05008038 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00008039 }
8040 }
8041 break;
8042#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008043#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008044 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00008045 if (!(p = lock_user_string(arg1)))
8046 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008047 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008048 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008049 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008050 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008051#endif
Chen Gang704eff62015-08-21 05:37:33 +08008052#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00008053 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00008054 {
8055 void * p2;
8056 p = lock_user_string(arg1);
8057 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008058 if (!p || !p2)
8059 ret = -TARGET_EFAULT;
8060 else
8061 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008062 unlock_user(p2, arg2, 0);
8063 unlock_user(p, arg1, 0);
8064 }
bellard31e31b82003-02-18 22:55:36 +00008065 break;
Chen Gang704eff62015-08-21 05:37:33 +08008066#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008067#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008068 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008069 {
8070 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008071 if (!arg2 || !arg4)
8072 goto efault;
ths64f0ce42007-09-24 09:25:06 +00008073 p = lock_user_string(arg2);
8074 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008075 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008076 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008077 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008078 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008079 unlock_user(p, arg2, 0);
8080 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008081 }
8082 break;
8083#endif
Chen Gang704eff62015-08-21 05:37:33 +08008084#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008085 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008086 if (!(p = lock_user_string(arg1)))
8087 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008088 ret = get_errno(unlink(p));
8089 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008090 break;
Chen Gang704eff62015-08-21 05:37:33 +08008091#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008092#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008093 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008094 if (!(p = lock_user_string(arg2)))
8095 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008096 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008097 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00008098 break;
balrogb7d35e62007-12-12 00:40:24 +00008099#endif
bellard31e31b82003-02-18 22:55:36 +00008100 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008101 {
8102 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008103 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008104 abi_ulong gp;
8105 abi_ulong guest_argp;
8106 abi_ulong guest_envp;
8107 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008108 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008109 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008110
bellardf7341ff2003-03-30 21:00:25 +00008111 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008112 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008113 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008114 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008115 goto efault;
ths03aa1972007-12-02 06:28:08 +00008116 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008117 break;
bellard7854b052003-03-29 17:22:23 +00008118 argc++;
bellard2f619692007-11-16 10:46:05 +00008119 }
bellardf7341ff2003-03-30 21:00:25 +00008120 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008121 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008122 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008123 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008124 goto efault;
ths03aa1972007-12-02 06:28:08 +00008125 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008126 break;
bellard7854b052003-03-29 17:22:23 +00008127 envc++;
bellard2f619692007-11-16 10:46:05 +00008128 }
bellard7854b052003-03-29 17:22:23 +00008129
Prasad J Panditb936cb52017-03-07 12:51:47 +05308130 argp = g_new0(char *, argc + 1);
8131 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008132
pbrookda94d262008-05-30 18:24:00 +00008133 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008134 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008135 if (get_user_ual(addr, gp))
8136 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008137 if (!addr)
8138 break;
bellard2f619692007-11-16 10:46:05 +00008139 if (!(*q = lock_user_string(addr)))
8140 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008141 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008142 }
bellardf7341ff2003-03-30 21:00:25 +00008143 *q = NULL;
8144
pbrookda94d262008-05-30 18:24:00 +00008145 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008146 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008147 if (get_user_ual(addr, gp))
8148 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008149 if (!addr)
8150 break;
bellard2f619692007-11-16 10:46:05 +00008151 if (!(*q = lock_user_string(addr)))
8152 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008153 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008154 }
bellardf7341ff2003-03-30 21:00:25 +00008155 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008156
bellard2f619692007-11-16 10:46:05 +00008157 if (!(p = lock_user_string(arg1)))
8158 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008159 /* Although execve() is not an interruptible syscall it is
8160 * a special case where we must use the safe_syscall wrapper:
8161 * if we allow a signal to happen before we make the host
8162 * syscall then we will 'lose' it, because at the point of
8163 * execve the process leaves QEMU's control. So we use the
8164 * safe syscall wrapper to ensure that we either take the
8165 * signal as a guest signal, or else it does not happen
8166 * before the execve completes and makes it the other
8167 * program's problem.
8168 */
8169 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008170 unlock_user(p, arg1, 0);
8171
bellard2f619692007-11-16 10:46:05 +00008172 goto execve_end;
8173
8174 execve_efault:
8175 ret = -TARGET_EFAULT;
8176
8177 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008178 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008179 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008180 if (get_user_ual(addr, gp)
8181 || !addr)
8182 break;
pbrook53a59602006-03-25 19:31:22 +00008183 unlock_user(*q, addr, 0);
8184 }
8185 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008186 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008187 if (get_user_ual(addr, gp)
8188 || !addr)
8189 break;
pbrook53a59602006-03-25 19:31:22 +00008190 unlock_user(*q, addr, 0);
8191 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308192
8193 g_free(argp);
8194 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008195 }
bellard31e31b82003-02-18 22:55:36 +00008196 break;
8197 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008198 if (!(p = lock_user_string(arg1)))
8199 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008200 ret = get_errno(chdir(p));
8201 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008202 break;
bellarda315a142005-01-30 22:59:18 +00008203#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008204 case TARGET_NR_time:
8205 {
pbrook53a59602006-03-25 19:31:22 +00008206 time_t host_time;
8207 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008208 if (!is_error(ret)
8209 && arg1
8210 && put_user_sal(host_time, arg1))
8211 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008212 }
8213 break;
bellarda315a142005-01-30 22:59:18 +00008214#endif
Chen Gang704eff62015-08-21 05:37:33 +08008215#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008216 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008217 if (!(p = lock_user_string(arg1)))
8218 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008219 ret = get_errno(mknod(p, arg2, arg3));
8220 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008221 break;
Chen Gang704eff62015-08-21 05:37:33 +08008222#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008223#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008224 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008225 if (!(p = lock_user_string(arg2)))
8226 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008227 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008228 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008229 break;
8230#endif
Chen Gang704eff62015-08-21 05:37:33 +08008231#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008232 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008233 if (!(p = lock_user_string(arg1)))
8234 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008235 ret = get_errno(chmod(p, arg2));
8236 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008237 break;
Chen Gang704eff62015-08-21 05:37:33 +08008238#endif
bellardebc05482003-09-30 21:08:41 +00008239#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008240 case TARGET_NR_break:
8241 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008242#endif
8243#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008244 case TARGET_NR_oldstat:
8245 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008246#endif
bellard31e31b82003-02-18 22:55:36 +00008247 case TARGET_NR_lseek:
8248 ret = get_errno(lseek(arg1, arg2, arg3));
8249 break;
Richard Henderson92317332010-05-03 10:07:53 -07008250#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8251 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008252 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008253 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008254 ret = get_errno(getpid());
8255 break;
Richard Henderson92317332010-05-03 10:07:53 -07008256#endif
8257#ifdef TARGET_NR_getpid
8258 case TARGET_NR_getpid:
8259 ret = get_errno(getpid());
8260 break;
8261#endif
bellard31e31b82003-02-18 22:55:36 +00008262 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008263 {
8264 /* need to look at the data field */
8265 void *p2, *p3;
8266
8267 if (arg1) {
8268 p = lock_user_string(arg1);
8269 if (!p) {
8270 goto efault;
8271 }
8272 } else {
8273 p = NULL;
8274 }
8275
8276 p2 = lock_user_string(arg2);
8277 if (!p2) {
8278 if (arg1) {
8279 unlock_user(p, arg1, 0);
8280 }
8281 goto efault;
8282 }
8283
8284 if (arg3) {
8285 p3 = lock_user_string(arg3);
8286 if (!p3) {
8287 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008288 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008289 }
8290 unlock_user(p2, arg2, 0);
8291 goto efault;
8292 }
8293 } else {
8294 p3 = NULL;
8295 }
8296
8297 /* FIXME - arg5 should be locked, but it isn't clear how to
8298 * do that since it's not guaranteed to be a NULL-terminated
8299 * string.
8300 */
8301 if (!arg5) {
8302 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8303 } else {
8304 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8305 }
8306 ret = get_errno(ret);
8307
8308 if (arg1) {
8309 unlock_user(p, arg1, 0);
8310 }
8311 unlock_user(p2, arg2, 0);
8312 if (arg3) {
8313 unlock_user(p3, arg3, 0);
8314 }
8315 }
8316 break;
thse5febef2007-04-01 18:31:35 +00008317#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008318 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008319 if (!(p = lock_user_string(arg1)))
8320 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008321 ret = get_errno(umount(p));
8322 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008323 break;
thse5febef2007-04-01 18:31:35 +00008324#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008325#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008326 case TARGET_NR_stime:
8327 {
pbrook53a59602006-03-25 19:31:22 +00008328 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008329 if (get_user_sal(host_time, arg1))
8330 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008331 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008332 }
8333 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008334#endif
bellard31e31b82003-02-18 22:55:36 +00008335 case TARGET_NR_ptrace:
8336 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008337#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008338 case TARGET_NR_alarm:
8339 ret = alarm(arg1);
8340 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008341#endif
bellardebc05482003-09-30 21:08:41 +00008342#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008343 case TARGET_NR_oldfstat:
8344 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008345#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008346#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008347 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008348 if (!block_signals()) {
8349 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8350 }
8351 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008352 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008353#endif
thse5febef2007-04-01 18:31:35 +00008354#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008355 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008356 {
pbrook53a59602006-03-25 19:31:22 +00008357 struct utimbuf tbuf, *host_tbuf;
8358 struct target_utimbuf *target_tbuf;
8359 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008360 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8361 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008362 tbuf.actime = tswapal(target_tbuf->actime);
8363 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008364 unlock_user_struct(target_tbuf, arg2, 0);
8365 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008366 } else {
pbrook53a59602006-03-25 19:31:22 +00008367 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008368 }
bellard579a97f2007-11-11 14:26:47 +00008369 if (!(p = lock_user_string(arg1)))
8370 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008371 ret = get_errno(utime(p, host_tbuf));
8372 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008373 }
8374 break;
thse5febef2007-04-01 18:31:35 +00008375#endif
Chen Gang704eff62015-08-21 05:37:33 +08008376#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008377 case TARGET_NR_utimes:
8378 {
bellard978a66f2004-12-06 22:58:05 +00008379 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008380 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008381 if (copy_from_user_timeval(&tv[0], arg2)
8382 || copy_from_user_timeval(&tv[1],
8383 arg2 + sizeof(struct target_timeval)))
8384 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008385 tvp = tv;
8386 } else {
8387 tvp = NULL;
8388 }
bellard579a97f2007-11-11 14:26:47 +00008389 if (!(p = lock_user_string(arg1)))
8390 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008391 ret = get_errno(utimes(p, tvp));
8392 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008393 }
8394 break;
Chen Gang704eff62015-08-21 05:37:33 +08008395#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008396#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008397 case TARGET_NR_futimesat:
8398 {
8399 struct timeval *tvp, tv[2];
8400 if (arg3) {
8401 if (copy_from_user_timeval(&tv[0], arg3)
8402 || copy_from_user_timeval(&tv[1],
8403 arg3 + sizeof(struct target_timeval)))
8404 goto efault;
8405 tvp = tv;
8406 } else {
8407 tvp = NULL;
8408 }
8409 if (!(p = lock_user_string(arg2)))
8410 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008411 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008412 unlock_user(p, arg2, 0);
8413 }
8414 break;
8415#endif
bellardebc05482003-09-30 21:08:41 +00008416#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008417 case TARGET_NR_stty:
8418 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008419#endif
8420#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008421 case TARGET_NR_gtty:
8422 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008423#endif
Chen Gang704eff62015-08-21 05:37:33 +08008424#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008425 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008426 if (!(p = lock_user_string(arg1)))
8427 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008428 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008429 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008430 break;
Chen Gang704eff62015-08-21 05:37:33 +08008431#endif
ths92a34c12007-09-24 09:27:49 +00008432#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8433 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008434 if (!(p = lock_user_string(arg2)))
8435 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008436 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008437 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008438 break;
8439#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008440#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008441 case TARGET_NR_nice:
8442 ret = get_errno(nice(arg1));
8443 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008444#endif
bellardebc05482003-09-30 21:08:41 +00008445#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008446 case TARGET_NR_ftime:
8447 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008448#endif
bellard31e31b82003-02-18 22:55:36 +00008449 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008450 sync();
8451 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008452 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008453#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8454 case TARGET_NR_syncfs:
8455 ret = get_errno(syncfs(arg1));
8456 break;
8457#endif
bellard31e31b82003-02-18 22:55:36 +00008458 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008459 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008460 break;
Chen Gang704eff62015-08-21 05:37:33 +08008461#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008462 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008463 {
8464 void *p2;
8465 p = lock_user_string(arg1);
8466 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008467 if (!p || !p2)
8468 ret = -TARGET_EFAULT;
8469 else
8470 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008471 unlock_user(p2, arg2, 0);
8472 unlock_user(p, arg1, 0);
8473 }
bellard31e31b82003-02-18 22:55:36 +00008474 break;
Chen Gang704eff62015-08-21 05:37:33 +08008475#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008476#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008477 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008478 {
bellard579a97f2007-11-11 14:26:47 +00008479 void *p2;
ths722183f2007-09-24 09:24:37 +00008480 p = lock_user_string(arg2);
8481 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008482 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008483 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008484 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008485 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008486 unlock_user(p2, arg4, 0);
8487 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008488 }
8489 break;
8490#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01008491#if defined(TARGET_NR_renameat2)
8492 case TARGET_NR_renameat2:
8493 {
8494 void *p2;
8495 p = lock_user_string(arg2);
8496 p2 = lock_user_string(arg4);
8497 if (!p || !p2) {
8498 ret = -TARGET_EFAULT;
8499 } else {
8500 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
8501 }
8502 unlock_user(p2, arg4, 0);
8503 unlock_user(p, arg2, 0);
8504 }
8505 break;
8506#endif
Chen Gang704eff62015-08-21 05:37:33 +08008507#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008508 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008509 if (!(p = lock_user_string(arg1)))
8510 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008511 ret = get_errno(mkdir(p, arg2));
8512 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008513 break;
Chen Gang704eff62015-08-21 05:37:33 +08008514#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008515#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008516 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008517 if (!(p = lock_user_string(arg2)))
8518 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008519 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008520 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008521 break;
8522#endif
Chen Gang704eff62015-08-21 05:37:33 +08008523#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008524 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008525 if (!(p = lock_user_string(arg1)))
8526 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008527 ret = get_errno(rmdir(p));
8528 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008529 break;
Chen Gang704eff62015-08-21 05:37:33 +08008530#endif
bellard31e31b82003-02-18 22:55:36 +00008531 case TARGET_NR_dup:
8532 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008533 if (ret >= 0) {
8534 fd_trans_dup(arg1, ret);
8535 }
bellard31e31b82003-02-18 22:55:36 +00008536 break;
Chen Gang704eff62015-08-21 05:37:33 +08008537#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008538 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008539 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008540 break;
Chen Gang704eff62015-08-21 05:37:33 +08008541#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008542#ifdef TARGET_NR_pipe2
8543 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008544 ret = do_pipe(cpu_env, arg1,
8545 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008546 break;
8547#endif
bellard31e31b82003-02-18 22:55:36 +00008548 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008549 {
pbrook53a59602006-03-25 19:31:22 +00008550 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008551 struct tms tms;
8552 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008553 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008554 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8555 if (!tmsp)
8556 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008557 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8558 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8559 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8560 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008561 }
bellardc596ed12003-07-13 17:32:31 +00008562 if (!is_error(ret))
8563 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008564 }
8565 break;
bellardebc05482003-09-30 21:08:41 +00008566#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008567 case TARGET_NR_prof:
8568 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008569#endif
thse5febef2007-04-01 18:31:35 +00008570#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008571 case TARGET_NR_signal:
8572 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008573#endif
bellard31e31b82003-02-18 22:55:36 +00008574 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008575 if (arg1 == 0) {
8576 ret = get_errno(acct(NULL));
8577 } else {
8578 if (!(p = lock_user_string(arg1)))
8579 goto efault;
8580 ret = get_errno(acct(path(p)));
8581 unlock_user(p, arg1, 0);
8582 }
pbrook24836682006-04-16 14:14:53 +00008583 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008584#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008585 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008586 if (!(p = lock_user_string(arg1)))
8587 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008588 ret = get_errno(umount2(p, arg2));
8589 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008590 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008591#endif
bellardebc05482003-09-30 21:08:41 +00008592#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008593 case TARGET_NR_lock:
8594 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008595#endif
bellard31e31b82003-02-18 22:55:36 +00008596 case TARGET_NR_ioctl:
8597 ret = do_ioctl(arg1, arg2, arg3);
8598 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008599#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00008600 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008601 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008602 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008603#endif
bellardebc05482003-09-30 21:08:41 +00008604#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008605 case TARGET_NR_mpx:
8606 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008607#endif
bellard31e31b82003-02-18 22:55:36 +00008608 case TARGET_NR_setpgid:
8609 ret = get_errno(setpgid(arg1, arg2));
8610 break;
bellardebc05482003-09-30 21:08:41 +00008611#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008612 case TARGET_NR_ulimit:
8613 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008614#endif
8615#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008616 case TARGET_NR_oldolduname:
8617 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008618#endif
bellard31e31b82003-02-18 22:55:36 +00008619 case TARGET_NR_umask:
8620 ret = get_errno(umask(arg1));
8621 break;
8622 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008623 if (!(p = lock_user_string(arg1)))
8624 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008625 ret = get_errno(chroot(p));
8626 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008627 break;
Chen Gang704eff62015-08-21 05:37:33 +08008628#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008629 case TARGET_NR_ustat:
8630 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008631#endif
8632#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008633 case TARGET_NR_dup2:
8634 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008635 if (ret >= 0) {
8636 fd_trans_dup(arg1, arg2);
8637 }
bellard31e31b82003-02-18 22:55:36 +00008638 break;
Chen Gang704eff62015-08-21 05:37:33 +08008639#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008640#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8641 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008642 {
8643 int host_flags;
8644
8645 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8646 return -EINVAL;
8647 }
8648 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8649 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008650 if (ret >= 0) {
8651 fd_trans_dup(arg1, arg2);
8652 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008653 break;
Peter Maydell10fa9932017-12-15 15:18:00 +00008654 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008655#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008656#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008657 case TARGET_NR_getppid:
8658 ret = get_errno(getppid());
8659 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008660#endif
Chen Gang704eff62015-08-21 05:37:33 +08008661#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008662 case TARGET_NR_getpgrp:
8663 ret = get_errno(getpgrp());
8664 break;
Chen Gang704eff62015-08-21 05:37:33 +08008665#endif
bellard31e31b82003-02-18 22:55:36 +00008666 case TARGET_NR_setsid:
8667 ret = get_errno(setsid());
8668 break;
thse5febef2007-04-01 18:31:35 +00008669#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008670 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008671 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008672#if defined(TARGET_ALPHA)
8673 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008674 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008675 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008676 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8677 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008678 act._sa_handler = old_act->_sa_handler;
8679 target_siginitset(&act.sa_mask, old_act->sa_mask);
8680 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008681 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008682 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008683 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008684 }
8685 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008686 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008687 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8688 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008689 old_act->_sa_handler = oact._sa_handler;
8690 old_act->sa_mask = oact.sa_mask.sig[0];
8691 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008692 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008693 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008694#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008695 struct target_sigaction act, oact, *pact, *old_act;
8696
8697 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008698 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8699 goto efault;
bellard106ec872006-06-27 21:08:10 +00008700 act._sa_handler = old_act->_sa_handler;
8701 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8702 act.sa_flags = old_act->sa_flags;
8703 unlock_user_struct(old_act, arg2, 0);
8704 pact = &act;
8705 } else {
8706 pact = NULL;
8707 }
8708
8709 ret = get_errno(do_sigaction(arg1, pact, &oact));
8710
8711 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008712 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8713 goto efault;
bellard106ec872006-06-27 21:08:10 +00008714 old_act->_sa_handler = oact._sa_handler;
8715 old_act->sa_flags = oact.sa_flags;
8716 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8717 old_act->sa_mask.sig[1] = 0;
8718 old_act->sa_mask.sig[2] = 0;
8719 old_act->sa_mask.sig[3] = 0;
8720 unlock_user_struct(old_act, arg3, 1);
8721 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008722#else
8723 struct target_old_sigaction *old_act;
8724 struct target_sigaction act, oact, *pact;
8725 if (arg2) {
8726 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8727 goto efault;
8728 act._sa_handler = old_act->_sa_handler;
8729 target_siginitset(&act.sa_mask, old_act->sa_mask);
8730 act.sa_flags = old_act->sa_flags;
8731 act.sa_restorer = old_act->sa_restorer;
Laurent Vivier5de154e2018-04-02 12:24:52 +02008732#ifdef TARGET_ARCH_HAS_KA_RESTORER
8733 act.ka_restorer = 0;
8734#endif
Richard Henderson6049f4f2009-12-27 18:30:03 -08008735 unlock_user_struct(old_act, arg2, 0);
8736 pact = &act;
8737 } else {
8738 pact = NULL;
8739 }
8740 ret = get_errno(do_sigaction(arg1, pact, &oact));
8741 if (!is_error(ret) && arg3) {
8742 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8743 goto efault;
8744 old_act->_sa_handler = oact._sa_handler;
8745 old_act->sa_mask = oact.sa_mask.sig[0];
8746 old_act->sa_flags = oact.sa_flags;
8747 old_act->sa_restorer = oact.sa_restorer;
8748 unlock_user_struct(old_act, arg3, 1);
8749 }
ths388bb212007-05-13 13:58:00 +00008750#endif
bellard31e31b82003-02-18 22:55:36 +00008751 }
8752 break;
thse5febef2007-04-01 18:31:35 +00008753#endif
bellard66fb9762003-03-23 01:06:05 +00008754 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008755 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008756#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008757 /* For Alpha and SPARC this is a 5 argument syscall, with
8758 * a 'restorer' parameter which must be copied into the
8759 * sa_restorer field of the sigaction struct.
8760 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8761 * and arg5 is the sigsetsize.
8762 * Alpha also has a separate rt_sigaction struct that it uses
8763 * here; SPARC uses the usual sigaction struct.
8764 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008765 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008766 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008767
8768 if (arg4 != sizeof(target_sigset_t)) {
8769 ret = -TARGET_EINVAL;
8770 break;
8771 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008772 if (arg2) {
8773 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8774 goto efault;
8775 act._sa_handler = rt_act->_sa_handler;
8776 act.sa_mask = rt_act->sa_mask;
8777 act.sa_flags = rt_act->sa_flags;
8778 act.sa_restorer = arg5;
8779 unlock_user_struct(rt_act, arg2, 0);
8780 pact = &act;
8781 }
8782 ret = get_errno(do_sigaction(arg1, pact, &oact));
8783 if (!is_error(ret) && arg3) {
8784 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8785 goto efault;
8786 rt_act->_sa_handler = oact._sa_handler;
8787 rt_act->sa_mask = oact.sa_mask;
8788 rt_act->sa_flags = oact.sa_flags;
8789 unlock_user_struct(rt_act, arg3, 1);
8790 }
8791#else
Peter Maydell78bfef72017-11-06 18:33:26 +00008792#ifdef TARGET_SPARC
8793 target_ulong restorer = arg4;
8794 target_ulong sigsetsize = arg5;
8795#else
8796 target_ulong sigsetsize = arg4;
8797#endif
pbrook53a59602006-03-25 19:31:22 +00008798 struct target_sigaction *act;
8799 struct target_sigaction *oact;
8800
Peter Maydell78bfef72017-11-06 18:33:26 +00008801 if (sigsetsize != sizeof(target_sigset_t)) {
Peter Maydellc8157012016-06-30 14:23:24 +01008802 ret = -TARGET_EINVAL;
8803 break;
8804 }
bellard579a97f2007-11-11 14:26:47 +00008805 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00008806 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
bellard579a97f2007-11-11 14:26:47 +00008807 goto efault;
Peter Maydell78bfef72017-11-06 18:33:26 +00008808 }
Laurent Vivier5de154e2018-04-02 12:24:52 +02008809#ifdef TARGET_ARCH_HAS_KA_RESTORER
8810 act->ka_restorer = restorer;
Peter Maydell78bfef72017-11-06 18:33:26 +00008811#endif
8812 } else {
pbrook53a59602006-03-25 19:31:22 +00008813 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00008814 }
bellard579a97f2007-11-11 14:26:47 +00008815 if (arg3) {
8816 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8817 ret = -TARGET_EFAULT;
8818 goto rt_sigaction_fail;
8819 }
8820 } else
pbrook53a59602006-03-25 19:31:22 +00008821 oact = NULL;
8822 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008823 rt_sigaction_fail:
8824 if (act)
pbrook53a59602006-03-25 19:31:22 +00008825 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008826 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008827 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008828#endif
pbrook53a59602006-03-25 19:31:22 +00008829 }
bellard66fb9762003-03-23 01:06:05 +00008830 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008831#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008832 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008833 {
8834 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008835 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008836 ret = do_sigprocmask(0, NULL, &cur_set);
8837 if (!ret) {
8838 host_to_target_old_sigset(&target_set, &cur_set);
8839 ret = target_set;
8840 }
bellard66fb9762003-03-23 01:06:05 +00008841 }
8842 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008843#endif
8844#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008845 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008846 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02008847 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00008848 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00008849 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008850 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8851 if (!ret) {
8852 host_to_target_old_sigset(&target_set, &oset);
8853 ret = target_set;
8854 }
bellard66fb9762003-03-23 01:06:05 +00008855 }
8856 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008857#endif
thse5febef2007-04-01 18:31:35 +00008858#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008859 case TARGET_NR_sigprocmask:
8860 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008861#if defined(TARGET_ALPHA)
8862 sigset_t set, oldset;
8863 abi_ulong mask;
8864 int how;
8865
8866 switch (arg1) {
8867 case TARGET_SIG_BLOCK:
8868 how = SIG_BLOCK;
8869 break;
8870 case TARGET_SIG_UNBLOCK:
8871 how = SIG_UNBLOCK;
8872 break;
8873 case TARGET_SIG_SETMASK:
8874 how = SIG_SETMASK;
8875 break;
8876 default:
8877 ret = -TARGET_EINVAL;
8878 goto fail;
8879 }
8880 mask = arg2;
8881 target_to_host_old_sigset(&set, &mask);
8882
Peter Maydell3d3efba2016-05-27 15:51:49 +01008883 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008884 if (!is_error(ret)) {
8885 host_to_target_old_sigset(&mask, &oldset);
8886 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008887 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008888 }
8889#else
bellard66fb9762003-03-23 01:06:05 +00008890 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008891 int how;
ths3b46e622007-09-17 08:09:54 +00008892
pbrook53a59602006-03-25 19:31:22 +00008893 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008894 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008895 case TARGET_SIG_BLOCK:
8896 how = SIG_BLOCK;
8897 break;
8898 case TARGET_SIG_UNBLOCK:
8899 how = SIG_UNBLOCK;
8900 break;
8901 case TARGET_SIG_SETMASK:
8902 how = SIG_SETMASK;
8903 break;
8904 default:
ths0da46a62007-10-20 20:23:07 +00008905 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008906 goto fail;
8907 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008908 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008909 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008910 target_to_host_old_sigset(&set, p);
8911 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008912 set_ptr = &set;
8913 } else {
8914 how = 0;
8915 set_ptr = NULL;
8916 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008917 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008918 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008919 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008920 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008921 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008922 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008923 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008924#endif
bellard66fb9762003-03-23 01:06:05 +00008925 }
8926 break;
thse5febef2007-04-01 18:31:35 +00008927#endif
bellard66fb9762003-03-23 01:06:05 +00008928 case TARGET_NR_rt_sigprocmask:
8929 {
8930 int how = arg1;
8931 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008932
Peter Maydellc8157012016-06-30 14:23:24 +01008933 if (arg4 != sizeof(target_sigset_t)) {
8934 ret = -TARGET_EINVAL;
8935 break;
8936 }
8937
pbrook53a59602006-03-25 19:31:22 +00008938 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008939 switch(how) {
8940 case TARGET_SIG_BLOCK:
8941 how = SIG_BLOCK;
8942 break;
8943 case TARGET_SIG_UNBLOCK:
8944 how = SIG_UNBLOCK;
8945 break;
8946 case TARGET_SIG_SETMASK:
8947 how = SIG_SETMASK;
8948 break;
8949 default:
ths0da46a62007-10-20 20:23:07 +00008950 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008951 goto fail;
8952 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008953 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008954 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008955 target_to_host_sigset(&set, p);
8956 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008957 set_ptr = &set;
8958 } else {
8959 how = 0;
8960 set_ptr = NULL;
8961 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008962 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008963 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008964 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008965 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008966 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008967 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008968 }
8969 }
8970 break;
thse5febef2007-04-01 18:31:35 +00008971#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008972 case TARGET_NR_sigpending:
8973 {
8974 sigset_t set;
8975 ret = get_errno(sigpending(&set));
8976 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008977 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008978 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008979 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008980 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008981 }
8982 }
8983 break;
thse5febef2007-04-01 18:31:35 +00008984#endif
bellard66fb9762003-03-23 01:06:05 +00008985 case TARGET_NR_rt_sigpending:
8986 {
8987 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008988
8989 /* Yes, this check is >, not != like most. We follow the kernel's
8990 * logic and it does it like this because it implements
8991 * NR_sigpending through the same code path, and in that case
8992 * the old_sigset_t is smaller in size.
8993 */
8994 if (arg2 > sizeof(target_sigset_t)) {
8995 ret = -TARGET_EINVAL;
8996 break;
8997 }
8998
bellard66fb9762003-03-23 01:06:05 +00008999 ret = get_errno(sigpending(&set));
9000 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05009001 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00009002 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009003 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05009004 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00009005 }
9006 }
9007 break;
thse5febef2007-04-01 18:31:35 +00009008#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00009009 case TARGET_NR_sigsuspend:
9010 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009011 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07009012#if defined(TARGET_ALPHA)
9013 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009014 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009015#else
Anthony Liguoric227f092009-10-01 16:12:16 -05009016 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009017 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009018 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009019 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07009020#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01009021 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9022 SIGSET_T_SIZE));
9023 if (ret != -TARGET_ERESTARTSYS) {
9024 ts->in_sigsuspend = 1;
9025 }
bellard66fb9762003-03-23 01:06:05 +00009026 }
9027 break;
thse5febef2007-04-01 18:31:35 +00009028#endif
bellard66fb9762003-03-23 01:06:05 +00009029 case TARGET_NR_rt_sigsuspend:
9030 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01009031 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01009032
9033 if (arg2 != sizeof(target_sigset_t)) {
9034 ret = -TARGET_EINVAL;
9035 break;
9036 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009037 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009038 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009039 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009040 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009041 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9042 SIGSET_T_SIZE));
9043 if (ret != -TARGET_ERESTARTSYS) {
9044 ts->in_sigsuspend = 1;
9045 }
bellard66fb9762003-03-23 01:06:05 +00009046 }
9047 break;
9048 case TARGET_NR_rt_sigtimedwait:
9049 {
bellard66fb9762003-03-23 01:06:05 +00009050 sigset_t set;
9051 struct timespec uts, *puts;
9052 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00009053
Peter Maydellc8157012016-06-30 14:23:24 +01009054 if (arg4 != sizeof(target_sigset_t)) {
9055 ret = -TARGET_EINVAL;
9056 break;
9057 }
9058
Anthony Liguoric227f092009-10-01 16:12:16 -05009059 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009060 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009061 target_to_host_sigset(&set, p);
9062 unlock_user(p, arg1, 0);
9063 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00009064 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00009065 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00009066 } else {
9067 puts = NULL;
9068 }
Peter Maydellb3f82332016-06-06 19:58:08 +01009069 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9070 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01009071 if (!is_error(ret)) {
9072 if (arg2) {
9073 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
9074 0);
9075 if (!p) {
9076 goto efault;
9077 }
9078 host_to_target_siginfo(p, &uinfo);
9079 unlock_user(p, arg2, sizeof(target_siginfo_t));
9080 }
9081 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00009082 }
9083 }
9084 break;
9085 case TARGET_NR_rt_sigqueueinfo:
9086 {
9087 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009088
9089 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9090 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00009091 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01009092 }
pbrook53a59602006-03-25 19:31:22 +00009093 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009094 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009095 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9096 }
9097 break;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009098 case TARGET_NR_rt_tgsigqueueinfo:
9099 {
9100 siginfo_t uinfo;
9101
9102 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9103 if (!p) {
9104 goto efault;
9105 }
9106 target_to_host_siginfo(&uinfo, p);
9107 unlock_user(p, arg4, 0);
9108 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9109 }
9110 break;
thse5febef2007-04-01 18:31:35 +00009111#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009112 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009113 if (block_signals()) {
9114 ret = -TARGET_ERESTARTSYS;
9115 } else {
9116 ret = do_sigreturn(cpu_env);
9117 }
bellard66fb9762003-03-23 01:06:05 +00009118 break;
thse5febef2007-04-01 18:31:35 +00009119#endif
bellard66fb9762003-03-23 01:06:05 +00009120 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009121 if (block_signals()) {
9122 ret = -TARGET_ERESTARTSYS;
9123 } else {
9124 ret = do_rt_sigreturn(cpu_env);
9125 }
bellard66fb9762003-03-23 01:06:05 +00009126 break;
bellard31e31b82003-02-18 22:55:36 +00009127 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009128 if (!(p = lock_user_string(arg1)))
9129 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009130 ret = get_errno(sethostname(p, arg2));
9131 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009132 break;
9133 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009134 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009135 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009136 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009137 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009138 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
9139 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009140 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9141 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009142 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00009143 ret = get_errno(setrlimit(resource, &rlim));
9144 }
9145 break;
bellard31e31b82003-02-18 22:55:36 +00009146 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009147 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009148 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009149 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009150 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009151
bellard9de5e442003-03-23 16:49:39 +00009152 ret = get_errno(getrlimit(resource, &rlim));
9153 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009154 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9155 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009156 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9157 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009158 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009159 }
9160 }
9161 break;
bellard31e31b82003-02-18 22:55:36 +00009162 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009163 {
9164 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009165 ret = get_errno(getrusage(arg1, &rusage));
9166 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009167 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009168 }
9169 }
9170 break;
bellard31e31b82003-02-18 22:55:36 +00009171 case TARGET_NR_gettimeofday:
9172 {
bellard31e31b82003-02-18 22:55:36 +00009173 struct timeval tv;
9174 ret = get_errno(gettimeofday(&tv, NULL));
9175 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00009176 if (copy_to_user_timeval(arg1, &tv))
9177 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009178 }
9179 }
9180 break;
9181 case TARGET_NR_settimeofday:
9182 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009183 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009184 struct timezone tz, *ptz = NULL;
9185
Paul Burtonb67d8032014-06-22 11:25:41 +01009186 if (arg1) {
9187 if (copy_from_user_timeval(&tv, arg1)) {
9188 goto efault;
9189 }
9190 ptv = &tv;
9191 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009192
9193 if (arg2) {
9194 if (copy_from_user_timezone(&tz, arg2)) {
9195 goto efault;
9196 }
9197 ptz = &tz;
9198 }
9199
Paul Burtonb67d8032014-06-22 11:25:41 +01009200 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009201 }
9202 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009203#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009204 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009205#if defined(TARGET_WANT_NI_OLD_SELECT)
9206 /* some architectures used to have old_select here
9207 * but now ENOSYS it.
9208 */
9209 ret = -TARGET_ENOSYS;
9210#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9211 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009212#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009213 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009214#endif
bellardf2674e32003-07-09 12:26:09 +00009215 break;
bellard048f6b42005-11-26 18:47:20 +00009216#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009217#ifdef TARGET_NR_pselect6
9218 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04009219 {
9220 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
9221 fd_set rfds, wfds, efds;
9222 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
9223 struct timespec ts, *ts_ptr;
9224
9225 /*
9226 * The 6th arg is actually two args smashed together,
9227 * so we cannot use the C library.
9228 */
9229 sigset_t set;
9230 struct {
9231 sigset_t *set;
9232 size_t size;
9233 } sig, *sig_ptr;
9234
9235 abi_ulong arg_sigset, arg_sigsize, *arg7;
9236 target_sigset_t *target_sigset;
9237
9238 n = arg1;
9239 rfd_addr = arg2;
9240 wfd_addr = arg3;
9241 efd_addr = arg4;
9242 ts_addr = arg5;
9243
9244 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9245 if (ret) {
9246 goto fail;
9247 }
9248 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9249 if (ret) {
9250 goto fail;
9251 }
9252 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9253 if (ret) {
9254 goto fail;
9255 }
9256
9257 /*
9258 * This takes a timespec, and not a timeval, so we cannot
9259 * use the do_select() helper ...
9260 */
9261 if (ts_addr) {
9262 if (target_to_host_timespec(&ts, ts_addr)) {
9263 goto efault;
9264 }
9265 ts_ptr = &ts;
9266 } else {
9267 ts_ptr = NULL;
9268 }
9269
9270 /* Extract the two packed args for the sigset */
9271 if (arg6) {
9272 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009273 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009274
9275 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9276 if (!arg7) {
9277 goto efault;
9278 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009279 arg_sigset = tswapal(arg7[0]);
9280 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009281 unlock_user(arg7, arg6, 0);
9282
9283 if (arg_sigset) {
9284 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009285 if (arg_sigsize != sizeof(*target_sigset)) {
9286 /* Like the kernel, we enforce correct size sigsets */
9287 ret = -TARGET_EINVAL;
9288 goto fail;
9289 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009290 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9291 sizeof(*target_sigset), 1);
9292 if (!target_sigset) {
9293 goto efault;
9294 }
9295 target_to_host_sigset(&set, target_sigset);
9296 unlock_user(target_sigset, arg_sigset, 0);
9297 } else {
9298 sig.set = NULL;
9299 }
9300 } else {
9301 sig_ptr = NULL;
9302 }
9303
Peter Maydell6df9d382016-05-12 18:47:51 +01009304 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9305 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009306
9307 if (!is_error(ret)) {
9308 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9309 goto efault;
9310 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9311 goto efault;
9312 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9313 goto efault;
9314
9315 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9316 goto efault;
9317 }
9318 }
9319 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009320#endif
Chen Gang704eff62015-08-21 05:37:33 +08009321#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009322 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009323 {
9324 void *p2;
9325 p = lock_user_string(arg1);
9326 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009327 if (!p || !p2)
9328 ret = -TARGET_EFAULT;
9329 else
9330 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009331 unlock_user(p2, arg2, 0);
9332 unlock_user(p, arg1, 0);
9333 }
bellard31e31b82003-02-18 22:55:36 +00009334 break;
Chen Gang704eff62015-08-21 05:37:33 +08009335#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009336#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009337 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009338 {
bellard579a97f2007-11-11 14:26:47 +00009339 void *p2;
thsf0b62432007-09-24 09:25:40 +00009340 p = lock_user_string(arg1);
9341 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009342 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009343 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009344 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009345 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009346 unlock_user(p2, arg3, 0);
9347 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009348 }
9349 break;
9350#endif
bellardebc05482003-09-30 21:08:41 +00009351#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009352 case TARGET_NR_oldlstat:
9353 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009354#endif
Chen Gang704eff62015-08-21 05:37:33 +08009355#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009356 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009357 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009358 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009359 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009360 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009361 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009362 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009363 } else if (!arg3) {
9364 /* Short circuit this for the magic exe check. */
9365 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009366 } else if (is_proc_myself((const char *)p, "exe")) {
9367 char real[PATH_MAX], *temp;
9368 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009369 /* Return value is # of bytes that we wrote to the buffer. */
9370 if (temp == NULL) {
9371 ret = get_errno(-1);
9372 } else {
9373 /* Don't worry about sign mismatch as earlier mapping
9374 * logic would have thrown a bad address error. */
9375 ret = MIN(strlen(real), arg3);
9376 /* We cannot NUL terminate the string. */
9377 memcpy(p2, real, ret);
9378 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009379 } else {
9380 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009381 }
pbrook53a59602006-03-25 19:31:22 +00009382 unlock_user(p2, arg2, ret);
9383 unlock_user(p, arg1, 0);
9384 }
bellard31e31b82003-02-18 22:55:36 +00009385 break;
Chen Gang704eff62015-08-21 05:37:33 +08009386#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009387#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009388 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009389 {
bellard579a97f2007-11-11 14:26:47 +00009390 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009391 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009392 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009393 if (!p || !p2) {
9394 ret = -TARGET_EFAULT;
9395 } else if (is_proc_myself((const char *)p, "exe")) {
9396 char real[PATH_MAX], *temp;
9397 temp = realpath(exec_path, real);
9398 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9399 snprintf((char *)p2, arg4, "%s", real);
9400 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009401 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009402 }
bellard579a97f2007-11-11 14:26:47 +00009403 unlock_user(p2, arg3, ret);
9404 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009405 }
9406 break;
9407#endif
thse5febef2007-04-01 18:31:35 +00009408#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009409 case TARGET_NR_uselib:
9410 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009411#endif
9412#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009413 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009414 if (!(p = lock_user_string(arg1)))
9415 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009416 ret = get_errno(swapon(p, arg2));
9417 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009418 break;
thse5febef2007-04-01 18:31:35 +00009419#endif
bellard31e31b82003-02-18 22:55:36 +00009420 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009421 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9422 /* arg4 must be ignored in all other cases */
9423 p = lock_user_string(arg4);
9424 if (!p) {
9425 goto efault;
9426 }
9427 ret = get_errno(reboot(arg1, arg2, arg3, p));
9428 unlock_user(p, arg4, 0);
9429 } else {
9430 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9431 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009432 break;
thse5febef2007-04-01 18:31:35 +00009433#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009434 case TARGET_NR_readdir:
9435 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009436#endif
9437#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009438 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009439#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9440 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009441 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9442 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009443 {
blueswir1992f48a2007-10-14 16:27:31 +00009444 abi_ulong *v;
9445 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009446 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9447 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009448 v1 = tswapal(v[0]);
9449 v2 = tswapal(v[1]);
9450 v3 = tswapal(v[2]);
9451 v4 = tswapal(v[3]);
9452 v5 = tswapal(v[4]);
9453 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009454 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009455 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009456 target_to_host_bitmask(v4, mmap_flags_tbl),
9457 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009458 }
bellard31e31b82003-02-18 22:55:36 +00009459#else
ths5fafdf22007-09-16 21:08:06 +00009460 ret = get_errno(target_mmap(arg1, arg2, arg3,
9461 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009462 arg5,
9463 arg6));
bellard31e31b82003-02-18 22:55:36 +00009464#endif
bellard6fb883e2003-07-09 17:12:39 +00009465 break;
thse5febef2007-04-01 18:31:35 +00009466#endif
bellarda315a142005-01-30 22:59:18 +00009467#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009468 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009469#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009470#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009471#endif
ths5fafdf22007-09-16 21:08:06 +00009472 ret = get_errno(target_mmap(arg1, arg2, arg3,
9473 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009474 arg5,
bellardc573ff62004-01-04 15:51:36 +00009475 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009476 break;
bellarda315a142005-01-30 22:59:18 +00009477#endif
bellard31e31b82003-02-18 22:55:36 +00009478 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009479 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009480 break;
bellard9de5e442003-03-23 16:49:39 +00009481 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009482 {
Andreas Färber0429a972013-08-26 18:14:44 +02009483 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009484 /* Special hack to detect libc making the stack executable. */
9485 if ((arg3 & PROT_GROWSDOWN)
9486 && arg1 >= ts->info->stack_limit
9487 && arg1 <= ts->info->start_stack) {
9488 arg3 &= ~PROT_GROWSDOWN;
9489 arg2 = arg2 + arg1 - ts->info->stack_limit;
9490 arg1 = ts->info->stack_limit;
9491 }
9492 }
bellard54936002003-05-13 00:25:15 +00009493 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009494 break;
thse5febef2007-04-01 18:31:35 +00009495#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009496 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009497 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009498 break;
thse5febef2007-04-01 18:31:35 +00009499#endif
pbrook53a59602006-03-25 19:31:22 +00009500 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009501#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009502 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009503 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009504 break;
thse5febef2007-04-01 18:31:35 +00009505#endif
9506#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009507 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009508 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009509 break;
thse5febef2007-04-01 18:31:35 +00009510#endif
9511#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009512 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009513 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009514 break;
thse5febef2007-04-01 18:31:35 +00009515#endif
9516#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009517 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009518 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009519 break;
thse5febef2007-04-01 18:31:35 +00009520#endif
9521#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009522 case TARGET_NR_munlockall:
9523 ret = get_errno(munlockall());
9524 break;
thse5febef2007-04-01 18:31:35 +00009525#endif
bellard31e31b82003-02-18 22:55:36 +00009526 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009527 if (!(p = lock_user_string(arg1)))
9528 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009529 ret = get_errno(truncate(p, arg2));
9530 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009531 break;
9532 case TARGET_NR_ftruncate:
9533 ret = get_errno(ftruncate(arg1, arg2));
9534 break;
9535 case TARGET_NR_fchmod:
9536 ret = get_errno(fchmod(arg1, arg2));
9537 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009538#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009539 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009540 if (!(p = lock_user_string(arg2)))
9541 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009542 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009543 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009544 break;
9545#endif
bellard31e31b82003-02-18 22:55:36 +00009546 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009547 /* Note that negative values are valid for getpriority, so we must
9548 differentiate based on errno settings. */
9549 errno = 0;
9550 ret = getpriority(arg1, arg2);
9551 if (ret == -1 && errno != 0) {
9552 ret = -host_to_target_errno(errno);
9553 break;
9554 }
9555#ifdef TARGET_ALPHA
9556 /* Return value is the unbiased priority. Signal no error. */
9557 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9558#else
9559 /* Return value is a biased priority to avoid negative numbers. */
9560 ret = 20 - ret;
9561#endif
bellard31e31b82003-02-18 22:55:36 +00009562 break;
9563 case TARGET_NR_setpriority:
9564 ret = get_errno(setpriority(arg1, arg2, arg3));
9565 break;
bellardebc05482003-09-30 21:08:41 +00009566#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009567 case TARGET_NR_profil:
9568 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009569#endif
bellard31e31b82003-02-18 22:55:36 +00009570 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009571 if (!(p = lock_user_string(arg1)))
9572 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009573 ret = get_errno(statfs(path(p), &stfs));
9574 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009575 convert_statfs:
9576 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009577 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009578
bellard579a97f2007-11-11 14:26:47 +00009579 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9580 goto efault;
9581 __put_user(stfs.f_type, &target_stfs->f_type);
9582 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9583 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9584 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9585 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9586 __put_user(stfs.f_files, &target_stfs->f_files);
9587 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9588 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9589 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9590 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009591 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05009592#ifdef _STATFS_F_FLAGS
9593 __put_user(stfs.f_flags, &target_stfs->f_flags);
9594#else
9595 __put_user(0, &target_stfs->f_flags);
9596#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009597 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009598 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009599 }
9600 break;
9601 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009602 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009603 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009604#ifdef TARGET_NR_statfs64
9605 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009606 if (!(p = lock_user_string(arg1)))
9607 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009608 ret = get_errno(statfs(path(p), &stfs));
9609 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009610 convert_statfs64:
9611 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009612 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009613
bellard579a97f2007-11-11 14:26:47 +00009614 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9615 goto efault;
9616 __put_user(stfs.f_type, &target_stfs->f_type);
9617 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9618 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9619 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9620 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9621 __put_user(stfs.f_files, &target_stfs->f_files);
9622 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9623 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9624 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9625 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009626 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9627 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009628 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009629 }
9630 break;
9631 case TARGET_NR_fstatfs64:
9632 ret = get_errno(fstatfs(arg1, &stfs));
9633 goto convert_statfs64;
9634#endif
bellardebc05482003-09-30 21:08:41 +00009635#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009636 case TARGET_NR_ioperm:
9637 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009638#endif
thse5febef2007-04-01 18:31:35 +00009639#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009640 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009641 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009642 break;
thse5febef2007-04-01 18:31:35 +00009643#endif
bellard3532fa72006-06-24 15:06:03 +00009644#ifdef TARGET_NR_accept
9645 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009646 ret = do_accept4(arg1, arg2, arg3, 0);
9647 break;
9648#endif
9649#ifdef TARGET_NR_accept4
9650 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009651 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009652 break;
9653#endif
9654#ifdef TARGET_NR_bind
9655 case TARGET_NR_bind:
9656 ret = do_bind(arg1, arg2, arg3);
9657 break;
9658#endif
9659#ifdef TARGET_NR_connect
9660 case TARGET_NR_connect:
9661 ret = do_connect(arg1, arg2, arg3);
9662 break;
9663#endif
9664#ifdef TARGET_NR_getpeername
9665 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009666 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009667 break;
9668#endif
9669#ifdef TARGET_NR_getsockname
9670 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009671 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009672 break;
9673#endif
9674#ifdef TARGET_NR_getsockopt
9675 case TARGET_NR_getsockopt:
9676 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9677 break;
9678#endif
9679#ifdef TARGET_NR_listen
9680 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009681 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009682 break;
9683#endif
9684#ifdef TARGET_NR_recv
9685 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009686 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009687 break;
9688#endif
9689#ifdef TARGET_NR_recvfrom
9690 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009691 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009692 break;
9693#endif
9694#ifdef TARGET_NR_recvmsg
9695 case TARGET_NR_recvmsg:
9696 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9697 break;
9698#endif
9699#ifdef TARGET_NR_send
9700 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009701 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009702 break;
9703#endif
9704#ifdef TARGET_NR_sendmsg
9705 case TARGET_NR_sendmsg:
9706 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9707 break;
9708#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009709#ifdef TARGET_NR_sendmmsg
9710 case TARGET_NR_sendmmsg:
9711 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9712 break;
9713 case TARGET_NR_recvmmsg:
9714 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9715 break;
9716#endif
bellard3532fa72006-06-24 15:06:03 +00009717#ifdef TARGET_NR_sendto
9718 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009719 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009720 break;
9721#endif
9722#ifdef TARGET_NR_shutdown
9723 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009724 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009725 break;
9726#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009727#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9728 case TARGET_NR_getrandom:
9729 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9730 if (!p) {
9731 goto efault;
9732 }
9733 ret = get_errno(getrandom(p, arg2, arg3));
9734 unlock_user(p, arg1, ret);
9735 break;
9736#endif
bellard3532fa72006-06-24 15:06:03 +00009737#ifdef TARGET_NR_socket
9738 case TARGET_NR_socket:
9739 ret = do_socket(arg1, arg2, arg3);
9740 break;
9741#endif
9742#ifdef TARGET_NR_socketpair
9743 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009744 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009745 break;
9746#endif
9747#ifdef TARGET_NR_setsockopt
9748 case TARGET_NR_setsockopt:
9749 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9750 break;
9751#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009752#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009753 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009754 {
9755 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009756
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009757 switch (arg1) {
9758 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9759 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9760 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9761 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9762 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9763 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9764 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9765 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9766 {
9767 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9768 }
9769 break;
9770 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9771 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9772 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9773 {
9774 ret = -TARGET_EINVAL;
9775 if (len < 0) {
9776 goto fail;
9777 }
9778 ret = 0;
9779 if (len == 0) {
9780 break;
9781 }
9782 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9783 if (!p) {
9784 ret = -TARGET_EFAULT;
9785 goto fail;
9786 }
9787 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9788 unlock_user(p, arg2, arg3);
9789 }
9790 break;
9791 default:
9792 ret = -EINVAL;
9793 break;
9794 }
9795 }
9796 break;
9797#endif
bellard31e31b82003-02-18 22:55:36 +00009798 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009799 {
bellard66fb9762003-03-23 01:06:05 +00009800 struct itimerval value, ovalue, *pvalue;
9801
pbrook53a59602006-03-25 19:31:22 +00009802 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009803 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009804 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9805 || copy_from_user_timeval(&pvalue->it_value,
9806 arg2 + sizeof(struct target_timeval)))
9807 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009808 } else {
9809 pvalue = NULL;
9810 }
9811 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009812 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009813 if (copy_to_user_timeval(arg3,
9814 &ovalue.it_interval)
9815 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9816 &ovalue.it_value))
9817 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009818 }
9819 }
9820 break;
bellard31e31b82003-02-18 22:55:36 +00009821 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009822 {
bellard66fb9762003-03-23 01:06:05 +00009823 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009824
bellard66fb9762003-03-23 01:06:05 +00009825 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009826 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009827 if (copy_to_user_timeval(arg2,
9828 &value.it_interval)
9829 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9830 &value.it_value))
9831 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009832 }
9833 }
9834 break;
Chen Gang704eff62015-08-21 05:37:33 +08009835#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009836 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009837 if (!(p = lock_user_string(arg1)))
9838 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009839 ret = get_errno(stat(path(p), &st));
9840 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009841 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009842#endif
9843#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009844 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009845 if (!(p = lock_user_string(arg1)))
9846 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009847 ret = get_errno(lstat(path(p), &st));
9848 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009849 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009850#endif
bellard31e31b82003-02-18 22:55:36 +00009851 case TARGET_NR_fstat:
9852 {
9853 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009854#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009855 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009856#endif
bellard31e31b82003-02-18 22:55:36 +00009857 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009858 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009859
bellard579a97f2007-11-11 14:26:47 +00009860 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9861 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009862 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009863 __put_user(st.st_dev, &target_st->st_dev);
9864 __put_user(st.st_ino, &target_st->st_ino);
9865 __put_user(st.st_mode, &target_st->st_mode);
9866 __put_user(st.st_uid, &target_st->st_uid);
9867 __put_user(st.st_gid, &target_st->st_gid);
9868 __put_user(st.st_nlink, &target_st->st_nlink);
9869 __put_user(st.st_rdev, &target_st->st_rdev);
9870 __put_user(st.st_size, &target_st->st_size);
9871 __put_user(st.st_blksize, &target_st->st_blksize);
9872 __put_user(st.st_blocks, &target_st->st_blocks);
9873 __put_user(st.st_atime, &target_st->target_st_atime);
9874 __put_user(st.st_mtime, &target_st->target_st_mtime);
9875 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009876 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009877 }
9878 }
9879 break;
bellardebc05482003-09-30 21:08:41 +00009880#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009881 case TARGET_NR_olduname:
9882 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009883#endif
9884#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009885 case TARGET_NR_iopl:
9886 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009887#endif
bellard31e31b82003-02-18 22:55:36 +00009888 case TARGET_NR_vhangup:
9889 ret = get_errno(vhangup());
9890 break;
bellardebc05482003-09-30 21:08:41 +00009891#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009892 case TARGET_NR_idle:
9893 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009894#endif
bellard42ad6ae2005-01-03 22:48:11 +00009895#ifdef TARGET_NR_syscall
9896 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009897 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9898 arg6, arg7, arg8, 0);
9899 break;
bellard42ad6ae2005-01-03 22:48:11 +00009900#endif
bellard31e31b82003-02-18 22:55:36 +00009901 case TARGET_NR_wait4:
9902 {
9903 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009904 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009905 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009906 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009907 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009908 if (target_rusage)
9909 rusage_ptr = &rusage;
9910 else
9911 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009912 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009913 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009914 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009915 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009916 if (put_user_s32(status, status_ptr))
9917 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009918 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009919 if (target_rusage) {
9920 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9921 if (rusage_err) {
9922 ret = rusage_err;
9923 }
9924 }
bellard31e31b82003-02-18 22:55:36 +00009925 }
9926 }
9927 break;
thse5febef2007-04-01 18:31:35 +00009928#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009929 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009930 if (!(p = lock_user_string(arg1)))
9931 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009932 ret = get_errno(swapoff(p));
9933 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009934 break;
thse5febef2007-04-01 18:31:35 +00009935#endif
bellard31e31b82003-02-18 22:55:36 +00009936 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009937 {
pbrook53a59602006-03-25 19:31:22 +00009938 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009939 struct sysinfo value;
9940 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009941 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009942 {
bellard579a97f2007-11-11 14:26:47 +00009943 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9944 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009945 __put_user(value.uptime, &target_value->uptime);
9946 __put_user(value.loads[0], &target_value->loads[0]);
9947 __put_user(value.loads[1], &target_value->loads[1]);
9948 __put_user(value.loads[2], &target_value->loads[2]);
9949 __put_user(value.totalram, &target_value->totalram);
9950 __put_user(value.freeram, &target_value->freeram);
9951 __put_user(value.sharedram, &target_value->sharedram);
9952 __put_user(value.bufferram, &target_value->bufferram);
9953 __put_user(value.totalswap, &target_value->totalswap);
9954 __put_user(value.freeswap, &target_value->freeswap);
9955 __put_user(value.procs, &target_value->procs);
9956 __put_user(value.totalhigh, &target_value->totalhigh);
9957 __put_user(value.freehigh, &target_value->freehigh);
9958 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009959 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009960 }
9961 }
9962 break;
thse5febef2007-04-01 18:31:35 +00009963#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009964 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +01009965 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
9966 break;
thse5febef2007-04-01 18:31:35 +00009967#endif
aurel32e5289082009-04-18 16:16:12 +00009968#ifdef TARGET_NR_semget
9969 case TARGET_NR_semget:
9970 ret = get_errno(semget(arg1, arg2, arg3));
9971 break;
9972#endif
9973#ifdef TARGET_NR_semop
9974 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009975 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009976 break;
9977#endif
9978#ifdef TARGET_NR_semctl
9979 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009980 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009981 break;
9982#endif
aurel32eeb438c2008-10-13 21:08:55 +00009983#ifdef TARGET_NR_msgctl
9984 case TARGET_NR_msgctl:
9985 ret = do_msgctl(arg1, arg2, arg3);
9986 break;
9987#endif
9988#ifdef TARGET_NR_msgget
9989 case TARGET_NR_msgget:
9990 ret = get_errno(msgget(arg1, arg2));
9991 break;
9992#endif
9993#ifdef TARGET_NR_msgrcv
9994 case TARGET_NR_msgrcv:
9995 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9996 break;
9997#endif
9998#ifdef TARGET_NR_msgsnd
9999 case TARGET_NR_msgsnd:
10000 ret = do_msgsnd(arg1, arg2, arg3, arg4);
10001 break;
10002#endif
Riku Voipio88a8c982009-04-03 10:42:00 +030010003#ifdef TARGET_NR_shmget
10004 case TARGET_NR_shmget:
10005 ret = get_errno(shmget(arg1, arg2, arg3));
10006 break;
10007#endif
10008#ifdef TARGET_NR_shmctl
10009 case TARGET_NR_shmctl:
10010 ret = do_shmctl(arg1, arg2, arg3);
10011 break;
10012#endif
10013#ifdef TARGET_NR_shmat
10014 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +010010015 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +030010016 break;
10017#endif
10018#ifdef TARGET_NR_shmdt
10019 case TARGET_NR_shmdt:
10020 ret = do_shmdt(arg1);
10021 break;
10022#endif
bellard31e31b82003-02-18 22:55:36 +000010023 case TARGET_NR_fsync:
10024 ret = get_errno(fsync(arg1));
10025 break;
bellard31e31b82003-02-18 22:55:36 +000010026 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +010010027 /* Linux manages to have three different orderings for its
10028 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
10029 * match the kernel's CONFIG_CLONE_* settings.
10030 * Microblaze is further special in that it uses a sixth
10031 * implicit argument to clone for the TLS pointer.
10032 */
10033#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020010034 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010010035#elif defined(TARGET_CLONE_BACKWARDS)
10036 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
10037#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010038 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010039#else
Peter Maydell4ce62432013-07-16 18:44:57 +010010040 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010041#endif
bellard1b6b0292003-03-22 17:31:38 +000010042 break;
bellardec86b0f2003-04-11 00:15:04 +000010043#ifdef __NR_exit_group
10044 /* new thread calls */
10045 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +020010046#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000010047 _mcleanup();
10048#endif
bellarde9009672005-04-26 20:42:36 +000010049 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +000010050 ret = get_errno(exit_group(arg1));
10051 break;
10052#endif
bellard31e31b82003-02-18 22:55:36 +000010053 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000010054 if (!(p = lock_user_string(arg1)))
10055 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010056 ret = get_errno(setdomainname(p, arg2));
10057 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010058 break;
10059 case TARGET_NR_uname:
10060 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000010061 {
10062 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000010063
bellard579a97f2007-11-11 14:26:47 +000010064 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
10065 goto efault;
bellard29e619b2004-09-13 21:41:04 +000010066 ret = get_errno(sys_uname(buf));
10067 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010010068 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000010069 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +010010070 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +000010071 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010010072 if (qemu_uname_release && *qemu_uname_release) {
10073 g_strlcpy(buf->release, qemu_uname_release,
10074 sizeof(buf->release));
10075 }
bellard29e619b2004-09-13 21:41:04 +000010076 }
pbrook53a59602006-03-25 19:31:22 +000010077 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000010078 }
bellard31e31b82003-02-18 22:55:36 +000010079 break;
bellard6dbad632003-03-16 18:05:05 +000010080#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000010081 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +000010082 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +000010083 break;
j_mayer84409dd2007-04-06 08:56:50 +000010084#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000010085 case TARGET_NR_vm86old:
10086 goto unimplemented;
10087 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +000010088 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000010089 break;
10090#endif
j_mayer84409dd2007-04-06 08:56:50 +000010091#endif
bellard31e31b82003-02-18 22:55:36 +000010092 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010093 {
10094 struct timex host_buf;
10095
10096 if (target_to_host_timex(&host_buf, arg1) != 0) {
10097 goto efault;
10098 }
10099 ret = get_errno(adjtimex(&host_buf));
10100 if (!is_error(ret)) {
10101 if (host_to_target_timex(arg1, &host_buf) != 0) {
10102 goto efault;
10103 }
10104 }
10105 }
10106 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010107#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10108 case TARGET_NR_clock_adjtime:
10109 {
10110 struct timex htx, *phtx = &htx;
10111
10112 if (target_to_host_timex(phtx, arg2) != 0) {
10113 goto efault;
10114 }
10115 ret = get_errno(clock_adjtime(arg1, phtx));
10116 if (!is_error(ret) && phtx) {
10117 if (host_to_target_timex(arg2, phtx) != 0) {
10118 goto efault;
10119 }
10120 }
10121 }
10122 break;
10123#endif
thse5febef2007-04-01 18:31:35 +000010124#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +000010125 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +000010126#endif
bellard31e31b82003-02-18 22:55:36 +000010127 case TARGET_NR_init_module:
10128 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +000010129#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +000010130 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +000010131#endif
bellard31e31b82003-02-18 22:55:36 +000010132 goto unimplemented;
10133 case TARGET_NR_quotactl:
10134 goto unimplemented;
10135 case TARGET_NR_getpgid:
10136 ret = get_errno(getpgid(arg1));
10137 break;
10138 case TARGET_NR_fchdir:
10139 ret = get_errno(fchdir(arg1));
10140 break;
j_mayer84409dd2007-04-06 08:56:50 +000010141#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +000010142 case TARGET_NR_bdflush:
10143 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +000010144#endif
thse5febef2007-04-01 18:31:35 +000010145#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +000010146 case TARGET_NR_sysfs:
10147 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010148#endif
bellard31e31b82003-02-18 22:55:36 +000010149 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +000010150 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +000010151 break;
thse5febef2007-04-01 18:31:35 +000010152#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +000010153 case TARGET_NR_afs_syscall:
10154 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010155#endif
j_mayer7a3148a2007-04-05 07:13:51 +000010156#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010157 case TARGET_NR__llseek:
10158 {
10159 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010160#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010161 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010162 if (res == -1) {
10163 ret = get_errno(res);
10164 } else {
10165 ret = 0;
10166 }
10167#else
bellard31e31b82003-02-18 22:55:36 +000010168 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010169#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010170 if ((ret == 0) && put_user_s64(res, arg4)) {
10171 goto efault;
10172 }
bellard31e31b82003-02-18 22:55:36 +000010173 }
10174 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010175#endif
Chen Gang704eff62015-08-21 05:37:33 +080010176#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010177 case TARGET_NR_getdents:
Peter Maydell2b3f64c2018-04-19 13:57:40 +010010178#ifdef EMULATE_GETDENTS_WITH_GETDENTS
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010179#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010180 {
pbrook53a59602006-03-25 19:31:22 +000010181 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010182 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010183 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010184
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010185 dirp = g_try_malloc(count);
10186 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +000010187 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010188 goto fail;
10189 }
ths3b46e622007-09-17 08:09:54 +000010190
bellard4add45b2003-06-05 01:52:59 +000010191 ret = get_errno(sys_getdents(arg1, dirp, count));
10192 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010193 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010194 struct target_dirent *tde;
10195 int len = ret;
10196 int reclen, treclen;
10197 int count1, tnamelen;
10198
10199 count1 = 0;
10200 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010201 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10202 goto efault;
bellard4add45b2003-06-05 01:52:59 +000010203 tde = target_dirp;
10204 while (len > 0) {
10205 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010206 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10207 assert(tnamelen >= 0);
10208 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10209 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010210 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010211 tde->d_ino = tswapal(de->d_ino);
10212 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010213 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010214 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010215 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010216 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010217 count1 += treclen;
10218 }
10219 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010220 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010221 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010222 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010223 }
10224#else
bellard31e31b82003-02-18 22:55:36 +000010225 {
aurel326556a832008-10-13 21:08:17 +000010226 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010227 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010228
bellard579a97f2007-11-11 14:26:47 +000010229 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10230 goto efault;
bellard72f03902003-02-18 23:33:18 +000010231 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010232 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010233 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010234 int len = ret;
10235 int reclen;
10236 de = dirp;
10237 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010238 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010239 if (reclen > len)
10240 break;
bellard8083a3e2003-03-24 23:12:16 +000010241 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010242 tswapls(&de->d_ino);
10243 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010244 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010245 len -= reclen;
10246 }
10247 }
pbrook53a59602006-03-25 19:31:22 +000010248 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010249 }
bellard4add45b2003-06-05 01:52:59 +000010250#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010251#else
10252 /* Implement getdents in terms of getdents64 */
10253 {
10254 struct linux_dirent64 *dirp;
10255 abi_long count = arg3;
10256
10257 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10258 if (!dirp) {
10259 goto efault;
10260 }
10261 ret = get_errno(sys_getdents64(arg1, dirp, count));
10262 if (!is_error(ret)) {
10263 /* Convert the dirent64 structs to target dirent. We do this
10264 * in-place, since we can guarantee that a target_dirent is no
10265 * larger than a dirent64; however this means we have to be
10266 * careful to read everything before writing in the new format.
10267 */
10268 struct linux_dirent64 *de;
10269 struct target_dirent *tde;
10270 int len = ret;
10271 int tlen = 0;
10272
10273 de = dirp;
10274 tde = (struct target_dirent *)dirp;
10275 while (len > 0) {
10276 int namelen, treclen;
10277 int reclen = de->d_reclen;
10278 uint64_t ino = de->d_ino;
10279 int64_t off = de->d_off;
10280 uint8_t type = de->d_type;
10281
10282 namelen = strlen(de->d_name);
10283 treclen = offsetof(struct target_dirent, d_name)
10284 + namelen + 2;
10285 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10286
10287 memmove(tde->d_name, de->d_name, namelen + 1);
10288 tde->d_ino = tswapal(ino);
10289 tde->d_off = tswapal(off);
10290 tde->d_reclen = tswap16(treclen);
10291 /* The target_dirent type is in what was formerly a padding
10292 * byte at the end of the structure:
10293 */
10294 *(((char *)tde) + treclen - 1) = type;
10295
10296 de = (struct linux_dirent64 *)((char *)de + reclen);
10297 tde = (struct target_dirent *)((char *)tde + treclen);
10298 len -= reclen;
10299 tlen += treclen;
10300 }
10301 ret = tlen;
10302 }
10303 unlock_user(dirp, arg2, ret);
10304 }
10305#endif
bellard31e31b82003-02-18 22:55:36 +000010306 break;
Chen Gang704eff62015-08-21 05:37:33 +080010307#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010308#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010309 case TARGET_NR_getdents64:
10310 {
aurel326556a832008-10-13 21:08:17 +000010311 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010312 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010313 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10314 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010315 ret = get_errno(sys_getdents64(arg1, dirp, count));
10316 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010317 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010318 int len = ret;
10319 int reclen;
10320 de = dirp;
10321 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010322 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010323 if (reclen > len)
10324 break;
bellard8083a3e2003-03-24 23:12:16 +000010325 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010326 tswap64s((uint64_t *)&de->d_ino);
10327 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010328 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010329 len -= reclen;
10330 }
10331 }
pbrook53a59602006-03-25 19:31:22 +000010332 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010333 }
10334 break;
bellarda541f292004-04-12 20:39:29 +000010335#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010336#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010337 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010338 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010339 break;
thse5febef2007-04-01 18:31:35 +000010340#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010341#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10342# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010343 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010344# endif
10345# ifdef TARGET_NR_ppoll
10346 case TARGET_NR_ppoll:
10347# endif
bellard9de5e442003-03-23 16:49:39 +000010348 {
pbrook53a59602006-03-25 19:31:22 +000010349 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010350 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010351 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010352 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010353
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010354 pfd = NULL;
10355 target_pfd = NULL;
10356 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010357 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10358 ret = -TARGET_EINVAL;
10359 break;
10360 }
10361
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010362 target_pfd = lock_user(VERIFY_WRITE, arg1,
10363 sizeof(struct target_pollfd) * nfds, 1);
10364 if (!target_pfd) {
10365 goto efault;
10366 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010367
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010368 pfd = alloca(sizeof(struct pollfd) * nfds);
10369 for (i = 0; i < nfds; i++) {
10370 pfd[i].fd = tswap32(target_pfd[i].fd);
10371 pfd[i].events = tswap16(target_pfd[i].events);
10372 }
bellard9de5e442003-03-23 16:49:39 +000010373 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010374
Peter Maydella6130232016-06-06 19:58:10 +010010375 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010376# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010377 case TARGET_NR_ppoll:
10378 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010379 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10380 target_sigset_t *target_set;
10381 sigset_t _set, *set = &_set;
10382
10383 if (arg3) {
10384 if (target_to_host_timespec(timeout_ts, arg3)) {
10385 unlock_user(target_pfd, arg1, 0);
10386 goto efault;
10387 }
10388 } else {
10389 timeout_ts = NULL;
10390 }
10391
10392 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010393 if (arg5 != sizeof(target_sigset_t)) {
10394 unlock_user(target_pfd, arg1, 0);
10395 ret = -TARGET_EINVAL;
10396 break;
10397 }
10398
Mike Frysingerd8035d42011-02-07 01:05:51 -050010399 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10400 if (!target_set) {
10401 unlock_user(target_pfd, arg1, 0);
10402 goto efault;
10403 }
10404 target_to_host_sigset(set, target_set);
10405 } else {
10406 set = NULL;
10407 }
10408
Peter Maydella6130232016-06-06 19:58:10 +010010409 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10410 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010411
10412 if (!is_error(ret) && arg3) {
10413 host_to_target_timespec(arg3, timeout_ts);
10414 }
10415 if (arg4) {
10416 unlock_user(target_set, arg4, 0);
10417 }
Peter Maydella6130232016-06-06 19:58:10 +010010418 break;
10419 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010420# endif
Peter Maydella6130232016-06-06 19:58:10 +010010421# ifdef TARGET_NR_poll
10422 case TARGET_NR_poll:
10423 {
10424 struct timespec ts, *pts;
10425
10426 if (arg3 >= 0) {
10427 /* Convert ms to secs, ns */
10428 ts.tv_sec = arg3 / 1000;
10429 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10430 pts = &ts;
10431 } else {
10432 /* -ve poll() timeout means "infinite" */
10433 pts = NULL;
10434 }
10435 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10436 break;
10437 }
10438# endif
10439 default:
10440 g_assert_not_reached();
10441 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010442
bellard9de5e442003-03-23 16:49:39 +000010443 if (!is_error(ret)) {
10444 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010445 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010446 }
10447 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010448 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010449 }
10450 break;
thse5febef2007-04-01 18:31:35 +000010451#endif
bellard31e31b82003-02-18 22:55:36 +000010452 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010453 /* NOTE: the flock constant seems to be the same for every
10454 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010455 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010456 break;
10457 case TARGET_NR_readv:
10458 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010459 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10460 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010461 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010462 unlock_iovec(vec, arg2, arg3, 1);
10463 } else {
10464 ret = -host_to_target_errno(errno);
10465 }
bellard31e31b82003-02-18 22:55:36 +000010466 }
10467 break;
10468 case TARGET_NR_writev:
10469 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010470 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10471 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010472 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010473 unlock_iovec(vec, arg2, arg3, 0);
10474 } else {
10475 ret = -host_to_target_errno(errno);
10476 }
bellard31e31b82003-02-18 22:55:36 +000010477 }
10478 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010479#if defined(TARGET_NR_preadv)
10480 case TARGET_NR_preadv:
10481 {
10482 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10483 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010484 unsigned long low, high;
10485
10486 target_to_host_low_high(arg4, arg5, &low, &high);
10487 ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010488 unlock_iovec(vec, arg2, arg3, 1);
10489 } else {
10490 ret = -host_to_target_errno(errno);
10491 }
10492 }
10493 break;
10494#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010495#if defined(TARGET_NR_pwritev)
10496 case TARGET_NR_pwritev:
10497 {
10498 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10499 if (vec != NULL) {
Max Filippov9ac22512018-04-04 17:30:41 -070010500 unsigned long low, high;
10501
10502 target_to_host_low_high(arg4, arg5, &low, &high);
10503 ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010504 unlock_iovec(vec, arg2, arg3, 0);
10505 } else {
10506 ret = -host_to_target_errno(errno);
10507 }
10508 }
10509 break;
10510#endif
bellard31e31b82003-02-18 22:55:36 +000010511 case TARGET_NR_getsid:
10512 ret = get_errno(getsid(arg1));
10513 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010514#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010515 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010516 ret = get_errno(fdatasync(arg1));
10517 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010518#endif
Chen Gang704eff62015-08-21 05:37:33 +080010519#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010520 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010521 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010522 return value. */
ths0da46a62007-10-20 20:23:07 +000010523 ret = -TARGET_ENOTDIR;
10524 break;
Chen Gang704eff62015-08-21 05:37:33 +080010525#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010526 case TARGET_NR_sched_getaffinity:
10527 {
10528 unsigned int mask_size;
10529 unsigned long *mask;
10530
10531 /*
10532 * sched_getaffinity needs multiples of ulong, so need to take
10533 * care of mismatches between target ulong and host ulong sizes.
10534 */
10535 if (arg2 & (sizeof(abi_ulong) - 1)) {
10536 ret = -TARGET_EINVAL;
10537 break;
10538 }
10539 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10540
10541 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010542 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010543 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10544
10545 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010546 if (ret > arg2) {
10547 /* More data returned than the caller's buffer will fit.
10548 * This only happens if sizeof(abi_long) < sizeof(long)
10549 * and the caller passed us a buffer holding an odd number
10550 * of abi_longs. If the host kernel is actually using the
10551 * extra 4 bytes then fail EINVAL; otherwise we can just
10552 * ignore them and only copy the interesting part.
10553 */
10554 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10555 if (numcpus > arg2 * 8) {
10556 ret = -TARGET_EINVAL;
10557 break;
10558 }
10559 ret = arg2;
10560 }
10561
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010562 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
10563 goto efault;
10564 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010565 }
10566 }
10567 break;
10568 case TARGET_NR_sched_setaffinity:
10569 {
10570 unsigned int mask_size;
10571 unsigned long *mask;
10572
10573 /*
10574 * sched_setaffinity needs multiples of ulong, so need to take
10575 * care of mismatches between target ulong and host ulong sizes.
10576 */
10577 if (arg2 & (sizeof(abi_ulong) - 1)) {
10578 ret = -TARGET_EINVAL;
10579 break;
10580 }
10581 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010582 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010583
10584 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10585 if (ret) {
10586 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010587 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010588
10589 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10590 }
10591 break;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010592 case TARGET_NR_getcpu:
10593 {
10594 unsigned cpu, node;
10595 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
10596 arg2 ? &node : NULL,
10597 NULL));
10598 if (is_error(ret)) {
10599 goto fail;
10600 }
10601 if (arg1 && put_user_u32(cpu, arg1)) {
10602 goto efault;
10603 }
10604 if (arg2 && put_user_u32(node, arg2)) {
10605 goto efault;
10606 }
10607 }
10608 break;
bellard31e31b82003-02-18 22:55:36 +000010609 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010610 {
pbrook53a59602006-03-25 19:31:22 +000010611 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010612 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010613
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010614 if (arg2 == 0) {
10615 return -TARGET_EINVAL;
10616 }
bellard579a97f2007-11-11 14:26:47 +000010617 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10618 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010619 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010620 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010621 ret = get_errno(sched_setparam(arg1, &schp));
10622 }
10623 break;
bellard31e31b82003-02-18 22:55:36 +000010624 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010625 {
pbrook53a59602006-03-25 19:31:22 +000010626 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010627 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010628
10629 if (arg2 == 0) {
10630 return -TARGET_EINVAL;
10631 }
bellard5cd43932003-03-29 16:54:36 +000010632 ret = get_errno(sched_getparam(arg1, &schp));
10633 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010634 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10635 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010636 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010637 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010638 }
10639 }
10640 break;
bellard31e31b82003-02-18 22:55:36 +000010641 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010642 {
pbrook53a59602006-03-25 19:31:22 +000010643 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010644 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010645 if (arg3 == 0) {
10646 return -TARGET_EINVAL;
10647 }
bellard579a97f2007-11-11 14:26:47 +000010648 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10649 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010650 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010651 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010652 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10653 }
10654 break;
bellard31e31b82003-02-18 22:55:36 +000010655 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010656 ret = get_errno(sched_getscheduler(arg1));
10657 break;
bellard31e31b82003-02-18 22:55:36 +000010658 case TARGET_NR_sched_yield:
10659 ret = get_errno(sched_yield());
10660 break;
10661 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010662 ret = get_errno(sched_get_priority_max(arg1));
10663 break;
bellard31e31b82003-02-18 22:55:36 +000010664 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010665 ret = get_errno(sched_get_priority_min(arg1));
10666 break;
bellard31e31b82003-02-18 22:55:36 +000010667 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010668 {
bellard5cd43932003-03-29 16:54:36 +000010669 struct timespec ts;
10670 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10671 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010672 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010673 }
10674 }
10675 break;
bellard31e31b82003-02-18 22:55:36 +000010676 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010677 {
bellard1b6b0292003-03-22 17:31:38 +000010678 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010679 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010680 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010681 if (is_error(ret) && arg2) {
10682 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010683 }
10684 }
10685 break;
thse5febef2007-04-01 18:31:35 +000010686#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010687 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010688 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010689#endif
10690#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010691 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010692 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010693#endif
bellard31e31b82003-02-18 22:55:36 +000010694 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010695 switch (arg1) {
10696 case PR_GET_PDEATHSIG:
10697 {
10698 int deathsig;
10699 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10700 if (!is_error(ret) && arg2
10701 && put_user_ual(deathsig, arg2)) {
10702 goto efault;
thse5574482007-02-11 20:03:13 +000010703 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010704 break;
10705 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010706#ifdef PR_GET_NAME
10707 case PR_GET_NAME:
10708 {
10709 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10710 if (!name) {
10711 goto efault;
10712 }
10713 ret = get_errno(prctl(arg1, (unsigned long)name,
10714 arg3, arg4, arg5));
10715 unlock_user(name, arg2, 16);
10716 break;
10717 }
10718 case PR_SET_NAME:
10719 {
10720 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10721 if (!name) {
10722 goto efault;
10723 }
10724 ret = get_errno(prctl(arg1, (unsigned long)name,
10725 arg3, arg4, arg5));
10726 unlock_user(name, arg2, 0);
10727 break;
10728 }
10729#endif
Richard Henderson85fc7162018-03-09 17:09:43 +000010730#ifdef TARGET_AARCH64
10731 case TARGET_PR_SVE_SET_VL:
10732 /* We cannot support either PR_SVE_SET_VL_ONEXEC
10733 or PR_SVE_VL_INHERIT. Therefore, anything above
10734 ARM_MAX_VQ results in EINVAL. */
10735 ret = -TARGET_EINVAL;
10736 if (arm_feature(cpu_env, ARM_FEATURE_SVE)
10737 && arg2 >= 0 && arg2 <= ARM_MAX_VQ * 16 && !(arg2 & 15)) {
10738 CPUARMState *env = cpu_env;
10739 int old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
10740 int vq = MAX(arg2 / 16, 1);
10741
10742 if (vq < old_vq) {
10743 aarch64_sve_narrow_vq(env, vq);
10744 }
10745 env->vfp.zcr_el[1] = vq - 1;
10746 ret = vq * 16;
10747 }
10748 break;
10749 case TARGET_PR_SVE_GET_VL:
10750 ret = -TARGET_EINVAL;
10751 if (arm_feature(cpu_env, ARM_FEATURE_SVE)) {
10752 CPUARMState *env = cpu_env;
10753 ret = ((env->vfp.zcr_el[1] & 0xf) + 1) * 16;
10754 }
10755 break;
10756#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +000010757 case PR_GET_SECCOMP:
10758 case PR_SET_SECCOMP:
10759 /* Disable seccomp to prevent the target disabling syscalls we
10760 * need. */
10761 ret = -TARGET_EINVAL;
10762 break;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010763 default:
10764 /* Most prctl options have no pointer arguments */
10765 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10766 break;
10767 }
ths39b9aae2007-02-11 18:36:44 +000010768 break;
bellardd2fd1af2007-11-14 18:08:56 +000010769#ifdef TARGET_NR_arch_prctl
10770 case TARGET_NR_arch_prctl:
10771#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10772 ret = do_arch_prctl(cpu_env, arg1, arg2);
10773 break;
10774#else
10775 goto unimplemented;
10776#endif
10777#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010778#ifdef TARGET_NR_pread64
10779 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010780 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010781 arg4 = arg5;
10782 arg5 = arg6;
10783 }
aurel32f2c7ba12008-03-28 22:32:06 +000010784 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10785 goto efault;
10786 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10787 unlock_user(p, arg2, ret);
10788 break;
10789 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010790 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010791 arg4 = arg5;
10792 arg5 = arg6;
10793 }
aurel32f2c7ba12008-03-28 22:32:06 +000010794 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10795 goto efault;
10796 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10797 unlock_user(p, arg2, 0);
10798 break;
10799#endif
bellard31e31b82003-02-18 22:55:36 +000010800 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010801 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10802 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010803 ret = get_errno(sys_getcwd1(p, arg2));
10804 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010805 break;
10806 case TARGET_NR_capget:
10807 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010808 {
10809 struct target_user_cap_header *target_header;
10810 struct target_user_cap_data *target_data = NULL;
10811 struct __user_cap_header_struct header;
10812 struct __user_cap_data_struct data[2];
10813 struct __user_cap_data_struct *dataptr = NULL;
10814 int i, target_datalen;
10815 int data_items = 1;
10816
10817 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10818 goto efault;
10819 }
10820 header.version = tswap32(target_header->version);
10821 header.pid = tswap32(target_header->pid);
10822
Peter Maydellec864872014-03-19 16:07:30 +000010823 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010824 /* Version 2 and up takes pointer to two user_data structs */
10825 data_items = 2;
10826 }
10827
10828 target_datalen = sizeof(*target_data) * data_items;
10829
10830 if (arg2) {
10831 if (num == TARGET_NR_capget) {
10832 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10833 } else {
10834 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10835 }
10836 if (!target_data) {
10837 unlock_user_struct(target_header, arg1, 0);
10838 goto efault;
10839 }
10840
10841 if (num == TARGET_NR_capset) {
10842 for (i = 0; i < data_items; i++) {
10843 data[i].effective = tswap32(target_data[i].effective);
10844 data[i].permitted = tswap32(target_data[i].permitted);
10845 data[i].inheritable = tswap32(target_data[i].inheritable);
10846 }
10847 }
10848
10849 dataptr = data;
10850 }
10851
10852 if (num == TARGET_NR_capget) {
10853 ret = get_errno(capget(&header, dataptr));
10854 } else {
10855 ret = get_errno(capset(&header, dataptr));
10856 }
10857
10858 /* The kernel always updates version for both capget and capset */
10859 target_header->version = tswap32(header.version);
10860 unlock_user_struct(target_header, arg1, 1);
10861
10862 if (arg2) {
10863 if (num == TARGET_NR_capget) {
10864 for (i = 0; i < data_items; i++) {
10865 target_data[i].effective = tswap32(data[i].effective);
10866 target_data[i].permitted = tswap32(data[i].permitted);
10867 target_data[i].inheritable = tswap32(data[i].inheritable);
10868 }
10869 unlock_user(target_data, arg2, target_datalen);
10870 } else {
10871 unlock_user(target_data, arg2, 0);
10872 }
10873 }
10874 break;
10875 }
bellard31e31b82003-02-18 22:55:36 +000010876 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010877 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010878 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010879
10880#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010881 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010882 {
10883 off_t *offp = NULL;
10884 off_t off;
10885 if (arg3) {
10886 ret = get_user_sal(off, arg3);
10887 if (is_error(ret)) {
10888 break;
10889 }
10890 offp = &off;
10891 }
10892 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10893 if (!is_error(ret) && arg3) {
10894 abi_long ret2 = put_user_sal(off, arg3);
10895 if (is_error(ret2)) {
10896 ret = ret2;
10897 }
10898 }
10899 break;
10900 }
10901#ifdef TARGET_NR_sendfile64
10902 case TARGET_NR_sendfile64:
10903 {
10904 off_t *offp = NULL;
10905 off_t off;
10906 if (arg3) {
10907 ret = get_user_s64(off, arg3);
10908 if (is_error(ret)) {
10909 break;
10910 }
10911 offp = &off;
10912 }
10913 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10914 if (!is_error(ret) && arg3) {
10915 abi_long ret2 = put_user_s64(off, arg3);
10916 if (is_error(ret2)) {
10917 ret = ret2;
10918 }
10919 }
10920 break;
10921 }
10922#endif
10923#else
10924 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010925#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010926 case TARGET_NR_sendfile64:
10927#endif
bellard5cd43932003-03-29 16:54:36 +000010928 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010929#endif
10930
bellardebc05482003-09-30 21:08:41 +000010931#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010932 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010933 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010934#endif
10935#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010936 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010937 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010938#endif
bellard048f6b42005-11-26 18:47:20 +000010939#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010940 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010010941 ret = get_errno(do_fork(cpu_env,
10942 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000010943 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010944 break;
bellard048f6b42005-11-26 18:47:20 +000010945#endif
bellardebc05482003-09-30 21:08:41 +000010946#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010947 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010948 {
10949 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010950 int resource = target_to_host_resource(arg1);
10951 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010952 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010953 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010954 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10955 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010956 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10957 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010958 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010959 }
10960 break;
10961 }
bellardebc05482003-09-30 21:08:41 +000010962#endif
bellarda315a142005-01-30 22:59:18 +000010963#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010964 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010965 if (!(p = lock_user_string(arg1)))
10966 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010967 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10968 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010969 break;
bellarda315a142005-01-30 22:59:18 +000010970#endif
10971#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010972 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010973 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010974 break;
bellarda315a142005-01-30 22:59:18 +000010975#endif
10976#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010977 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010978 if (!(p = lock_user_string(arg1)))
10979 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010980 ret = get_errno(stat(path(p), &st));
10981 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010982 if (!is_error(ret))
10983 ret = host_to_target_stat64(cpu_env, arg2, &st);
10984 break;
bellarda315a142005-01-30 22:59:18 +000010985#endif
10986#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010987 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010988 if (!(p = lock_user_string(arg1)))
10989 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010990 ret = get_errno(lstat(path(p), &st));
10991 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010992 if (!is_error(ret))
10993 ret = host_to_target_stat64(cpu_env, arg2, &st);
10994 break;
bellarda315a142005-01-30 22:59:18 +000010995#endif
10996#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010997 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010998 ret = get_errno(fstat(arg1, &st));
10999 if (!is_error(ret))
11000 ret = host_to_target_stat64(cpu_env, arg2, &st);
11001 break;
bellardec86b0f2003-04-11 00:15:04 +000011002#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010011003#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000011004#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000011005 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000011006#endif
11007#ifdef TARGET_NR_newfstatat
11008 case TARGET_NR_newfstatat:
11009#endif
balrog6a24a772008-09-20 02:23:36 +000011010 if (!(p = lock_user_string(arg2)))
11011 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011012 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000011013 if (!is_error(ret))
11014 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000011015 break;
bellarda315a142005-01-30 22:59:18 +000011016#endif
Chen Gang704eff62015-08-21 05:37:33 +080011017#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000011018 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000011019 if (!(p = lock_user_string(arg1)))
11020 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011021 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
11022 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011023 break;
Chen Gang704eff62015-08-21 05:37:33 +080011024#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030011025#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000011026 case TARGET_NR_getuid:
11027 ret = get_errno(high2lowuid(getuid()));
11028 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011029#endif
11030#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000011031 case TARGET_NR_getgid:
11032 ret = get_errno(high2lowgid(getgid()));
11033 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011034#endif
11035#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000011036 case TARGET_NR_geteuid:
11037 ret = get_errno(high2lowuid(geteuid()));
11038 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011039#endif
11040#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011041 case TARGET_NR_getegid:
11042 ret = get_errno(high2lowgid(getegid()));
11043 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011044#endif
bellard67867302003-11-23 17:05:30 +000011045 case TARGET_NR_setreuid:
11046 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
11047 break;
11048 case TARGET_NR_setregid:
11049 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
11050 break;
11051 case TARGET_NR_getgroups:
11052 {
11053 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011054 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000011055 gid_t *grouplist;
11056 int i;
11057
11058 grouplist = alloca(gidsetsize * sizeof(gid_t));
11059 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011060 if (gidsetsize == 0)
11061 break;
bellard67867302003-11-23 17:05:30 +000011062 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000011063 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000011064 if (!target_grouplist)
11065 goto efault;
balroga2155fc2008-09-20 02:12:08 +000011066 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030011067 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011068 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000011069 }
11070 }
11071 break;
11072 case TARGET_NR_setgroups:
11073 {
11074 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011075 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011076 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011077 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011078 if (gidsetsize) {
11079 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011080 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011081 if (!target_grouplist) {
11082 ret = -TARGET_EFAULT;
11083 goto fail;
11084 }
11085 for (i = 0; i < gidsetsize; i++) {
11086 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11087 }
11088 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000011089 }
bellard67867302003-11-23 17:05:30 +000011090 ret = get_errno(setgroups(gidsetsize, grouplist));
11091 }
11092 break;
11093 case TARGET_NR_fchown:
11094 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
11095 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011096#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011097 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011098 if (!(p = lock_user_string(arg2)))
11099 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011100 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11101 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011102 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000011103 break;
11104#endif
bellard67867302003-11-23 17:05:30 +000011105#ifdef TARGET_NR_setresuid
11106 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011107 ret = get_errno(sys_setresuid(low2highuid(arg1),
11108 low2highuid(arg2),
11109 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011110 break;
11111#endif
11112#ifdef TARGET_NR_getresuid
11113 case TARGET_NR_getresuid:
11114 {
pbrook53a59602006-03-25 19:31:22 +000011115 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011116 ret = get_errno(getresuid(&ruid, &euid, &suid));
11117 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011118 if (put_user_id(high2lowuid(ruid), arg1)
11119 || put_user_id(high2lowuid(euid), arg2)
11120 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000011121 goto efault;
bellard67867302003-11-23 17:05:30 +000011122 }
11123 }
11124 break;
11125#endif
11126#ifdef TARGET_NR_getresgid
11127 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011128 ret = get_errno(sys_setresgid(low2highgid(arg1),
11129 low2highgid(arg2),
11130 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011131 break;
11132#endif
11133#ifdef TARGET_NR_getresgid
11134 case TARGET_NR_getresgid:
11135 {
pbrook53a59602006-03-25 19:31:22 +000011136 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011137 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11138 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011139 if (put_user_id(high2lowgid(rgid), arg1)
11140 || put_user_id(high2lowgid(egid), arg2)
11141 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000011142 goto efault;
bellard67867302003-11-23 17:05:30 +000011143 }
11144 }
11145 break;
11146#endif
Chen Gang704eff62015-08-21 05:37:33 +080011147#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011148 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011149 if (!(p = lock_user_string(arg1)))
11150 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011151 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11152 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011153 break;
Chen Gang704eff62015-08-21 05:37:33 +080011154#endif
bellard67867302003-11-23 17:05:30 +000011155 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011156 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011157 break;
11158 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011159 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011160 break;
11161 case TARGET_NR_setfsuid:
11162 ret = get_errno(setfsuid(arg1));
11163 break;
11164 case TARGET_NR_setfsgid:
11165 ret = get_errno(setfsgid(arg1));
11166 break;
bellard67867302003-11-23 17:05:30 +000011167
bellarda315a142005-01-30 22:59:18 +000011168#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011169 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011170 if (!(p = lock_user_string(arg1)))
11171 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011172 ret = get_errno(lchown(p, arg2, arg3));
11173 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011174 break;
bellarda315a142005-01-30 22:59:18 +000011175#endif
11176#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011177 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000011178 ret = get_errno(getuid());
11179 break;
bellarda315a142005-01-30 22:59:18 +000011180#endif
aurel3264b4d282008-11-14 17:20:15 +000011181
11182#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11183 /* Alpha specific */
11184 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011185 {
11186 uid_t euid;
11187 euid=geteuid();
11188 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11189 }
aurel3264b4d282008-11-14 17:20:15 +000011190 ret = get_errno(getuid());
11191 break;
11192#endif
11193#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11194 /* Alpha specific */
11195 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011196 {
11197 uid_t egid;
11198 egid=getegid();
11199 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11200 }
aurel3264b4d282008-11-14 17:20:15 +000011201 ret = get_errno(getgid());
11202 break;
11203#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011204#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11205 /* Alpha specific */
11206 case TARGET_NR_osf_getsysinfo:
11207 ret = -TARGET_EOPNOTSUPP;
11208 switch (arg1) {
11209 case TARGET_GSI_IEEE_FP_CONTROL:
11210 {
11211 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
11212
11213 /* Copied from linux ieee_fpcr_to_swcr. */
11214 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
11215 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
11216 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
11217 | SWCR_TRAP_ENABLE_DZE
11218 | SWCR_TRAP_ENABLE_OVF);
11219 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
11220 | SWCR_TRAP_ENABLE_INE);
11221 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
11222 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
11223
11224 if (put_user_u64 (swcr, arg2))
11225 goto efault;
11226 ret = 0;
11227 }
11228 break;
11229
11230 /* case GSI_IEEE_STATE_AT_SIGNAL:
11231 -- Not implemented in linux kernel.
11232 case GSI_UACPROC:
11233 -- Retrieves current unaligned access state; not much used.
11234 case GSI_PROC_TYPE:
11235 -- Retrieves implver information; surely not used.
11236 case GSI_GET_HWRPB:
11237 -- Grabs a copy of the HWRPB; surely not used.
11238 */
11239 }
11240 break;
11241#endif
11242#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11243 /* Alpha specific */
11244 case TARGET_NR_osf_setsysinfo:
11245 ret = -TARGET_EOPNOTSUPP;
11246 switch (arg1) {
11247 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011248 {
11249 uint64_t swcr, fpcr, orig_fpcr;
11250
Richard Henderson6e06d512012-06-01 09:08:21 -070011251 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080011252 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070011253 }
11254 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011255 fpcr = orig_fpcr & FPCR_DYN_MASK;
11256
11257 /* Copied from linux ieee_swcr_to_fpcr. */
11258 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
11259 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
11260 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
11261 | SWCR_TRAP_ENABLE_DZE
11262 | SWCR_TRAP_ENABLE_OVF)) << 48;
11263 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
11264 | SWCR_TRAP_ENABLE_INE)) << 57;
11265 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
11266 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
11267
Richard Henderson6e06d512012-06-01 09:08:21 -070011268 cpu_alpha_store_fpcr(cpu_env, fpcr);
11269 ret = 0;
11270 }
11271 break;
11272
11273 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11274 {
11275 uint64_t exc, fpcr, orig_fpcr;
11276 int si_code;
11277
11278 if (get_user_u64(exc, arg2)) {
11279 goto efault;
11280 }
11281
11282 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
11283
11284 /* We only add to the exception status here. */
11285 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
11286
11287 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011288 ret = 0;
11289
Richard Henderson6e06d512012-06-01 09:08:21 -070011290 /* Old exceptions are not signaled. */
11291 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011292
Richard Henderson6e06d512012-06-01 09:08:21 -070011293 /* If any exceptions set by this call,
11294 and are unmasked, send a signal. */
11295 si_code = 0;
11296 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11297 si_code = TARGET_FPE_FLTRES;
11298 }
11299 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11300 si_code = TARGET_FPE_FLTUND;
11301 }
11302 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11303 si_code = TARGET_FPE_FLTOVF;
11304 }
11305 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11306 si_code = TARGET_FPE_FLTDIV;
11307 }
11308 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11309 si_code = TARGET_FPE_FLTINV;
11310 }
11311 if (si_code != 0) {
11312 target_siginfo_t info;
11313 info.si_signo = SIGFPE;
11314 info.si_errno = 0;
11315 info.si_code = si_code;
11316 info._sifields._sigfault._addr
11317 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011318 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11319 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011320 }
11321 }
11322 break;
11323
11324 /* case SSI_NVPAIRS:
11325 -- Used with SSIN_UACPROC to enable unaligned accesses.
11326 case SSI_IEEE_STATE_AT_SIGNAL:
11327 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11328 -- Not implemented in linux kernel
11329 */
11330 }
11331 break;
11332#endif
11333#ifdef TARGET_NR_osf_sigprocmask
11334 /* Alpha specific. */
11335 case TARGET_NR_osf_sigprocmask:
11336 {
11337 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011338 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011339 sigset_t set, oldset;
11340
11341 switch(arg1) {
11342 case TARGET_SIG_BLOCK:
11343 how = SIG_BLOCK;
11344 break;
11345 case TARGET_SIG_UNBLOCK:
11346 how = SIG_UNBLOCK;
11347 break;
11348 case TARGET_SIG_SETMASK:
11349 how = SIG_SETMASK;
11350 break;
11351 default:
11352 ret = -TARGET_EINVAL;
11353 goto fail;
11354 }
11355 mask = arg2;
11356 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011357 ret = do_sigprocmask(how, &set, &oldset);
11358 if (!ret) {
11359 host_to_target_old_sigset(&mask, &oldset);
11360 ret = mask;
11361 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011362 }
11363 break;
11364#endif
aurel3264b4d282008-11-14 17:20:15 +000011365
bellarda315a142005-01-30 22:59:18 +000011366#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011367 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011368 ret = get_errno(getgid());
11369 break;
bellarda315a142005-01-30 22:59:18 +000011370#endif
11371#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011372 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011373 ret = get_errno(geteuid());
11374 break;
bellarda315a142005-01-30 22:59:18 +000011375#endif
11376#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011377 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011378 ret = get_errno(getegid());
11379 break;
bellarda315a142005-01-30 22:59:18 +000011380#endif
11381#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011382 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011383 ret = get_errno(setreuid(arg1, arg2));
11384 break;
bellarda315a142005-01-30 22:59:18 +000011385#endif
11386#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011387 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011388 ret = get_errno(setregid(arg1, arg2));
11389 break;
bellarda315a142005-01-30 22:59:18 +000011390#endif
11391#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011392 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011393 {
11394 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011395 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011396 gid_t *grouplist;
11397 int i;
11398
11399 grouplist = alloca(gidsetsize * sizeof(gid_t));
11400 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011401 if (gidsetsize == 0)
11402 break;
bellard99c475a2005-01-31 20:45:13 +000011403 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011404 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11405 if (!target_grouplist) {
11406 ret = -TARGET_EFAULT;
11407 goto fail;
11408 }
balroga2155fc2008-09-20 02:12:08 +000011409 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011410 target_grouplist[i] = tswap32(grouplist[i]);
11411 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011412 }
11413 }
11414 break;
bellarda315a142005-01-30 22:59:18 +000011415#endif
11416#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011417 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011418 {
11419 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011420 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011421 gid_t *grouplist;
11422 int i;
ths3b46e622007-09-17 08:09:54 +000011423
bellard99c475a2005-01-31 20:45:13 +000011424 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011425 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11426 if (!target_grouplist) {
11427 ret = -TARGET_EFAULT;
11428 goto fail;
11429 }
bellard99c475a2005-01-31 20:45:13 +000011430 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011431 grouplist[i] = tswap32(target_grouplist[i]);
11432 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011433 ret = get_errno(setgroups(gidsetsize, grouplist));
11434 }
11435 break;
bellarda315a142005-01-30 22:59:18 +000011436#endif
11437#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011438 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011439 ret = get_errno(fchown(arg1, arg2, arg3));
11440 break;
bellarda315a142005-01-30 22:59:18 +000011441#endif
11442#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011443 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011444 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011445 break;
bellarda315a142005-01-30 22:59:18 +000011446#endif
11447#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011448 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011449 {
pbrook53a59602006-03-25 19:31:22 +000011450 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011451 ret = get_errno(getresuid(&ruid, &euid, &suid));
11452 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011453 if (put_user_u32(ruid, arg1)
11454 || put_user_u32(euid, arg2)
11455 || put_user_u32(suid, arg3))
11456 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011457 }
11458 }
11459 break;
bellarda315a142005-01-30 22:59:18 +000011460#endif
11461#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011462 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011463 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011464 break;
bellarda315a142005-01-30 22:59:18 +000011465#endif
11466#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011467 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011468 {
pbrook53a59602006-03-25 19:31:22 +000011469 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011470 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11471 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011472 if (put_user_u32(rgid, arg1)
11473 || put_user_u32(egid, arg2)
11474 || put_user_u32(sgid, arg3))
11475 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011476 }
11477 }
11478 break;
bellarda315a142005-01-30 22:59:18 +000011479#endif
11480#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011481 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011482 if (!(p = lock_user_string(arg1)))
11483 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011484 ret = get_errno(chown(p, arg2, arg3));
11485 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011486 break;
bellarda315a142005-01-30 22:59:18 +000011487#endif
11488#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011489 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011490 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011491 break;
bellarda315a142005-01-30 22:59:18 +000011492#endif
11493#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011494 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011495 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011496 break;
bellarda315a142005-01-30 22:59:18 +000011497#endif
11498#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011499 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011500 ret = get_errno(setfsuid(arg1));
11501 break;
bellarda315a142005-01-30 22:59:18 +000011502#endif
11503#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011504 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011505 ret = get_errno(setfsgid(arg1));
11506 break;
bellarda315a142005-01-30 22:59:18 +000011507#endif
bellard67867302003-11-23 17:05:30 +000011508
bellard31e31b82003-02-18 22:55:36 +000011509 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011510 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011511#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011512 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011513 {
11514 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011515 ret = -TARGET_ENOMEM;
11516 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11517 if (!a) {
11518 goto fail;
11519 }
aurel3204bb9ac2008-10-01 21:46:41 +000011520 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011521 p = lock_user_string(arg3);
11522 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011523 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011524 }
aurel3204bb9ac2008-10-01 21:46:41 +000011525 ret = get_errno(mincore(a, arg2, p));
11526 unlock_user(p, arg3, ret);
11527 mincore_fail:
11528 unlock_user(a, arg1, 0);
11529 }
11530 break;
bellardffa65c32004-01-04 23:57:22 +000011531#endif
aurel32408321b2008-10-01 21:46:32 +000011532#ifdef TARGET_NR_arm_fadvise64_64
11533 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011534 /* arm_fadvise64_64 looks like fadvise64_64 but
11535 * with different argument order: fd, advice, offset, len
11536 * rather than the usual fd, offset, len, advice.
11537 * Note that offset and len are both 64-bit so appear as
11538 * pairs of 32-bit registers.
11539 */
11540 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11541 target_offset64(arg5, arg6), arg2);
11542 ret = -host_to_target_errno(ret);
11543 break;
aurel32408321b2008-10-01 21:46:32 +000011544#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011545
11546#if TARGET_ABI_BITS == 32
11547
11548#ifdef TARGET_NR_fadvise64_64
11549 case TARGET_NR_fadvise64_64:
Max Filippov64a563d2018-04-01 15:02:34 -070011550#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
Laurent Vivier43046b52017-03-02 01:11:45 +010011551 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11552 ret = arg2;
11553 arg2 = arg3;
11554 arg3 = arg4;
11555 arg4 = arg5;
11556 arg5 = arg6;
11557 arg6 = ret;
11558#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011559 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011560 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011561 /* offset is in (3,4), len in (5,6) and advice in 7 */
11562 arg2 = arg3;
11563 arg3 = arg4;
11564 arg4 = arg5;
11565 arg5 = arg6;
11566 arg6 = arg7;
11567 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011568#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011569 ret = -host_to_target_errno(posix_fadvise(arg1,
11570 target_offset64(arg2, arg3),
11571 target_offset64(arg4, arg5),
11572 arg6));
11573 break;
11574#endif
11575
11576#ifdef TARGET_NR_fadvise64
11577 case TARGET_NR_fadvise64:
11578 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011579 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011580 /* offset is in (3,4), len in 5 and advice in 6 */
11581 arg2 = arg3;
11582 arg3 = arg4;
11583 arg4 = arg5;
11584 arg5 = arg6;
11585 }
11586 ret = -host_to_target_errno(posix_fadvise(arg1,
11587 target_offset64(arg2, arg3),
11588 arg4, arg5));
11589 break;
11590#endif
11591
11592#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011593#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011594#ifdef TARGET_NR_fadvise64_64
11595 case TARGET_NR_fadvise64_64:
11596#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011597#ifdef TARGET_NR_fadvise64
11598 case TARGET_NR_fadvise64:
11599#endif
11600#ifdef TARGET_S390X
11601 switch (arg4) {
11602 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11603 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11604 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11605 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11606 default: break;
11607 }
11608#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011609 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11610 break;
aurel32408321b2008-10-01 21:46:32 +000011611#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011612#endif /* end of 64-bit ABI fadvise handling */
11613
bellardffa65c32004-01-04 23:57:22 +000011614#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011615 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011616 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011617 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011618 This will break MADV_DONTNEED.
11619 This is a hint, so ignoring and returning success is ok. */
11620 ret = get_errno(0);
11621 break;
bellardffa65c32004-01-04 23:57:22 +000011622#endif
blueswir1992f48a2007-10-14 16:27:31 +000011623#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011624 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011625 {
thsb1e341e2007-03-20 21:50:52 +000011626 int cmd;
bellard77e46722003-04-29 20:39:06 +000011627 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011628 from_flock64_fn *copyfrom = copy_from_user_flock64;
11629 to_flock64_fn *copyto = copy_to_user_flock64;
11630
pbrookce4defa2006-02-09 16:49:55 +000011631#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010011632 if (((CPUARMState *)cpu_env)->eabi) {
11633 copyfrom = copy_from_user_eabi_flock64;
11634 copyto = copy_to_user_eabi_flock64;
11635 }
pbrookce4defa2006-02-09 16:49:55 +000011636#endif
bellard77e46722003-04-29 20:39:06 +000011637
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011638 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011639 if (cmd == -TARGET_EINVAL) {
11640 ret = cmd;
11641 break;
11642 }
thsb1e341e2007-03-20 21:50:52 +000011643
bellard60cd49d2003-03-16 22:53:56 +000011644 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011645 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011646 ret = copyfrom(&fl, arg3);
11647 if (ret) {
11648 break;
ths58134272007-03-31 18:59:32 +000011649 }
thsb1e341e2007-03-20 21:50:52 +000011650 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011651 if (ret == 0) {
11652 ret = copyto(arg3, &fl);
11653 }
bellard77e46722003-04-29 20:39:06 +000011654 break;
11655
thsb1e341e2007-03-20 21:50:52 +000011656 case TARGET_F_SETLK64:
11657 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011658 ret = copyfrom(&fl, arg3);
11659 if (ret) {
11660 break;
pbrookce4defa2006-02-09 16:49:55 +000011661 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011662 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011663 break;
bellard60cd49d2003-03-16 22:53:56 +000011664 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011665 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011666 break;
11667 }
bellard77e46722003-04-29 20:39:06 +000011668 break;
11669 }
bellard60cd49d2003-03-16 22:53:56 +000011670#endif
ths7d600c82006-12-08 01:32:58 +000011671#ifdef TARGET_NR_cacheflush
11672 case TARGET_NR_cacheflush:
11673 /* self-modifying code is handled automatically, so nothing needed */
11674 ret = 0;
11675 break;
11676#endif
bellardebc05482003-09-30 21:08:41 +000011677#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011678 case TARGET_NR_security:
11679 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011680#endif
bellardc573ff62004-01-04 15:51:36 +000011681#ifdef TARGET_NR_getpagesize
11682 case TARGET_NR_getpagesize:
11683 ret = TARGET_PAGE_SIZE;
11684 break;
11685#endif
bellard31e31b82003-02-18 22:55:36 +000011686 case TARGET_NR_gettid:
11687 ret = get_errno(gettid());
11688 break;
thse5febef2007-04-01 18:31:35 +000011689#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011690 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011691#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011692 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011693 arg2 = arg3;
11694 arg3 = arg4;
11695 arg4 = arg5;
11696 }
Lena Djokic77c68502016-11-24 17:08:56 +010011697 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011698#else
11699 ret = get_errno(readahead(arg1, arg2, arg3));
11700#endif
11701 break;
thse5febef2007-04-01 18:31:35 +000011702#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011703#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011704#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011705 case TARGET_NR_listxattr:
11706 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011707 {
11708 void *p, *b = 0;
11709 if (arg2) {
11710 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11711 if (!b) {
11712 ret = -TARGET_EFAULT;
11713 break;
11714 }
11715 }
11716 p = lock_user_string(arg1);
11717 if (p) {
11718 if (num == TARGET_NR_listxattr) {
11719 ret = get_errno(listxattr(p, b, arg3));
11720 } else {
11721 ret = get_errno(llistxattr(p, b, arg3));
11722 }
11723 } else {
11724 ret = -TARGET_EFAULT;
11725 }
11726 unlock_user(p, arg1, 0);
11727 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011728 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011729 }
11730 case TARGET_NR_flistxattr:
11731 {
11732 void *b = 0;
11733 if (arg2) {
11734 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11735 if (!b) {
11736 ret = -TARGET_EFAULT;
11737 break;
11738 }
11739 }
11740 ret = get_errno(flistxattr(arg1, b, arg3));
11741 unlock_user(b, arg2, arg3);
11742 break;
11743 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011744 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011745 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011746 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011747 void *p, *n, *v = 0;
11748 if (arg3) {
11749 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11750 if (!v) {
11751 ret = -TARGET_EFAULT;
11752 break;
11753 }
11754 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011755 p = lock_user_string(arg1);
11756 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011757 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011758 if (num == TARGET_NR_setxattr) {
11759 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11760 } else {
11761 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11762 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011763 } else {
11764 ret = -TARGET_EFAULT;
11765 }
11766 unlock_user(p, arg1, 0);
11767 unlock_user(n, arg2, 0);
11768 unlock_user(v, arg3, 0);
11769 }
11770 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011771 case TARGET_NR_fsetxattr:
11772 {
11773 void *n, *v = 0;
11774 if (arg3) {
11775 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11776 if (!v) {
11777 ret = -TARGET_EFAULT;
11778 break;
11779 }
11780 }
11781 n = lock_user_string(arg2);
11782 if (n) {
11783 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11784 } else {
11785 ret = -TARGET_EFAULT;
11786 }
11787 unlock_user(n, arg2, 0);
11788 unlock_user(v, arg3, 0);
11789 }
11790 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011791 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011792 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011793 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011794 void *p, *n, *v = 0;
11795 if (arg3) {
11796 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11797 if (!v) {
11798 ret = -TARGET_EFAULT;
11799 break;
11800 }
11801 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011802 p = lock_user_string(arg1);
11803 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011804 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011805 if (num == TARGET_NR_getxattr) {
11806 ret = get_errno(getxattr(p, n, v, arg4));
11807 } else {
11808 ret = get_errno(lgetxattr(p, n, v, arg4));
11809 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011810 } else {
11811 ret = -TARGET_EFAULT;
11812 }
11813 unlock_user(p, arg1, 0);
11814 unlock_user(n, arg2, 0);
11815 unlock_user(v, arg3, arg4);
11816 }
11817 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011818 case TARGET_NR_fgetxattr:
11819 {
11820 void *n, *v = 0;
11821 if (arg3) {
11822 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11823 if (!v) {
11824 ret = -TARGET_EFAULT;
11825 break;
11826 }
11827 }
11828 n = lock_user_string(arg2);
11829 if (n) {
11830 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11831 } else {
11832 ret = -TARGET_EFAULT;
11833 }
11834 unlock_user(n, arg2, 0);
11835 unlock_user(v, arg3, arg4);
11836 }
11837 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011838 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011839 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011840 {
11841 void *p, *n;
11842 p = lock_user_string(arg1);
11843 n = lock_user_string(arg2);
11844 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011845 if (num == TARGET_NR_removexattr) {
11846 ret = get_errno(removexattr(p, n));
11847 } else {
11848 ret = get_errno(lremovexattr(p, n));
11849 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011850 } else {
11851 ret = -TARGET_EFAULT;
11852 }
11853 unlock_user(p, arg1, 0);
11854 unlock_user(n, arg2, 0);
11855 }
11856 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011857 case TARGET_NR_fremovexattr:
11858 {
11859 void *n;
11860 n = lock_user_string(arg2);
11861 if (n) {
11862 ret = get_errno(fremovexattr(arg1, n));
11863 } else {
11864 ret = -TARGET_EFAULT;
11865 }
11866 unlock_user(n, arg2, 0);
11867 }
11868 break;
bellardebc05482003-09-30 21:08:41 +000011869#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011870#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011871#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011872 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011873#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011874 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011875 ret = 0;
11876 break;
edgar_iglef967792009-01-07 14:19:38 +000011877#elif defined(TARGET_CRIS)
11878 if (arg1 & 0xff)
11879 ret = -TARGET_EINVAL;
11880 else {
11881 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11882 ret = 0;
11883 }
11884 break;
bellard8d18e892007-11-14 15:18:40 +000011885#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11886 ret = do_set_thread_area(cpu_env, arg1);
11887 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011888#elif defined(TARGET_M68K)
11889 {
Andreas Färber0429a972013-08-26 18:14:44 +020011890 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011891 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011892 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011893 break;
11894 }
ths6f5b89a2007-03-02 20:48:00 +000011895#else
11896 goto unimplemented_nowarn;
11897#endif
11898#endif
11899#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011900 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011901#if defined(TARGET_I386) && defined(TARGET_ABI32)
11902 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011903 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011904#elif defined(TARGET_M68K)
11905 {
Andreas Färber0429a972013-08-26 18:14:44 +020011906 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011907 ret = ts->tp_value;
11908 break;
11909 }
bellard8d18e892007-11-14 15:18:40 +000011910#else
bellard5cd43932003-03-29 16:54:36 +000011911 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011912#endif
bellard8d18e892007-11-14 15:18:40 +000011913#endif
bellard48dc41e2006-06-21 18:15:50 +000011914#ifdef TARGET_NR_getdomainname
11915 case TARGET_NR_getdomainname:
11916 goto unimplemented_nowarn;
11917#endif
ths6f5b89a2007-03-02 20:48:00 +000011918
Max Filippov12e33402018-04-01 13:13:49 -070011919#ifdef TARGET_NR_clock_settime
11920 case TARGET_NR_clock_settime:
11921 {
11922 struct timespec ts;
11923
11924 ret = target_to_host_timespec(&ts, arg2);
11925 if (!is_error(ret)) {
11926 ret = get_errno(clock_settime(arg1, &ts));
11927 }
11928 break;
11929 }
11930#endif
thsb5906f92007-03-19 13:32:45 +000011931#ifdef TARGET_NR_clock_gettime
11932 case TARGET_NR_clock_gettime:
11933 {
11934 struct timespec ts;
11935 ret = get_errno(clock_gettime(arg1, &ts));
11936 if (!is_error(ret)) {
Max Filippovb9f99082018-04-01 13:14:04 -070011937 ret = host_to_target_timespec(arg2, &ts);
thsb5906f92007-03-19 13:32:45 +000011938 }
11939 break;
11940 }
11941#endif
11942#ifdef TARGET_NR_clock_getres
11943 case TARGET_NR_clock_getres:
11944 {
11945 struct timespec ts;
11946 ret = get_errno(clock_getres(arg1, &ts));
11947 if (!is_error(ret)) {
11948 host_to_target_timespec(arg2, &ts);
11949 }
11950 break;
11951 }
11952#endif
pbrook63d76512008-05-29 13:43:29 +000011953#ifdef TARGET_NR_clock_nanosleep
11954 case TARGET_NR_clock_nanosleep:
11955 {
11956 struct timespec ts;
11957 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011958 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11959 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011960 if (arg4)
11961 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011962
11963#if defined(TARGET_PPC)
11964 /* clock_nanosleep is odd in that it returns positive errno values.
11965 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011966 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011967 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11968 }
11969#endif
pbrook63d76512008-05-29 13:43:29 +000011970 break;
11971 }
11972#endif
thsb5906f92007-03-19 13:32:45 +000011973
ths6f5b89a2007-03-02 20:48:00 +000011974#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11975 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011976 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11977 break;
ths6f5b89a2007-03-02 20:48:00 +000011978#endif
11979
ths4cae1d12007-07-12 11:06:53 +000011980 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011981 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011982 break;
ths4cae1d12007-07-12 11:06:53 +000011983
ths71455572007-06-21 21:45:30 +000011984 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011985 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011986 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011987 break;
ths71455572007-06-21 21:45:30 +000011988
ths4f2b1fe2007-06-21 21:57:12 +000011989#ifdef TARGET_NR_set_robust_list
11990 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011991 case TARGET_NR_get_robust_list:
11992 /* The ABI for supporting robust futexes has userspace pass
11993 * the kernel a pointer to a linked list which is updated by
11994 * userspace after the syscall; the list is walked by the kernel
11995 * when the thread exits. Since the linked list in QEMU guest
11996 * memory isn't a valid linked list for the host and we have
11997 * no way to reliably intercept the thread-death event, we can't
11998 * support these. Silently return ENOSYS so that guest userspace
11999 * falls back to a non-robust futex implementation (which should
12000 * be OK except in the corner case of the guest crashing while
12001 * holding a mutex that is shared with another process via
12002 * shared memory).
12003 */
12004 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000012005#endif
12006
Peter Maydell1acae9f2013-07-02 14:04:12 +010012007#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000012008 case TARGET_NR_utimensat:
12009 {
Riku Voipioebc996f2009-04-21 15:01:51 +030012010 struct timespec *tsp, ts[2];
12011 if (!arg3) {
12012 tsp = NULL;
12013 } else {
12014 target_to_host_timespec(ts, arg3);
12015 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
12016 tsp = ts;
12017 }
ths9007f0e2007-09-25 17:50:37 +000012018 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030012019 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000012020 else {
bellard579a97f2007-11-11 14:26:47 +000012021 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000012022 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000012023 goto fail;
12024 }
Riku Voipioebc996f2009-04-21 15:01:51 +030012025 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000012026 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000012027 }
12028 }
12029 break;
12030#endif
pbrookbd0c5662008-05-29 14:34:11 +000012031 case TARGET_NR_futex:
12032 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
12033 break;
aurel32dbfe4c32009-04-08 21:29:30 +000012034#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000012035 case TARGET_NR_inotify_init:
12036 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012037 if (ret >= 0) {
12038 fd_trans_register(ret, &target_inotify_trans);
12039 }
aurel3239b59762008-10-01 21:46:50 +000012040 break;
12041#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012042#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000012043#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
12044 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010012045 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
12046 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012047 if (ret >= 0) {
12048 fd_trans_register(ret, &target_inotify_trans);
12049 }
Riku Voipioc05c7a72010-03-26 15:25:11 +000012050 break;
12051#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012052#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012053#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012054 case TARGET_NR_inotify_add_watch:
12055 p = lock_user_string(arg2);
12056 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
12057 unlock_user(p, arg2, 0);
12058 break;
12059#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012060#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012061 case TARGET_NR_inotify_rm_watch:
12062 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
12063 break;
12064#endif
ths9007f0e2007-09-25 17:50:37 +000012065
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012066#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012067 case TARGET_NR_mq_open:
12068 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012069 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012070 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012071 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012072
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012073 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012074 pposix_mq_attr = NULL;
12075 if (arg4) {
12076 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
12077 goto efault;
12078 }
12079 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012080 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012081 p = lock_user_string(arg1 - 1);
12082 if (!p) {
12083 goto efault;
12084 }
Lena Djokic26400772016-11-24 17:08:58 +010012085 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012086 unlock_user (p, arg1, 0);
12087 }
12088 break;
12089
12090 case TARGET_NR_mq_unlink:
12091 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012092 if (!p) {
12093 ret = -TARGET_EFAULT;
12094 break;
12095 }
aurel3224e10032009-04-15 16:11:43 +000012096 ret = get_errno(mq_unlink(p));
12097 unlock_user (p, arg1, 0);
12098 break;
12099
12100 case TARGET_NR_mq_timedsend:
12101 {
12102 struct timespec ts;
12103
12104 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12105 if (arg5 != 0) {
12106 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012107 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000012108 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012109 } else {
12110 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012111 }
aurel3224e10032009-04-15 16:11:43 +000012112 unlock_user (p, arg2, arg3);
12113 }
12114 break;
12115
12116 case TARGET_NR_mq_timedreceive:
12117 {
12118 struct timespec ts;
12119 unsigned int prio;
12120
12121 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12122 if (arg5 != 0) {
12123 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012124 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12125 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000012126 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012127 } else {
12128 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12129 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000012130 }
aurel3224e10032009-04-15 16:11:43 +000012131 unlock_user (p, arg2, arg3);
12132 if (arg4 != 0)
12133 put_user_u32(prio, arg4);
12134 }
12135 break;
12136
12137 /* Not implemented for now... */
12138/* case TARGET_NR_mq_notify: */
12139/* break; */
12140
12141 case TARGET_NR_mq_getsetattr:
12142 {
12143 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
12144 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000012145 if (arg2 != 0) {
12146 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070012147 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
12148 &posix_mq_attr_out));
12149 } else if (arg3 != 0) {
12150 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000012151 }
Max Filippova23ea402018-03-31 08:20:15 -070012152 if (ret == 0 && arg3 != 0) {
12153 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
12154 }
aurel3224e10032009-04-15 16:11:43 +000012155 }
12156 break;
12157#endif
12158
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012159#ifdef CONFIG_SPLICE
12160#ifdef TARGET_NR_tee
12161 case TARGET_NR_tee:
12162 {
12163 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12164 }
12165 break;
12166#endif
12167#ifdef TARGET_NR_splice
12168 case TARGET_NR_splice:
12169 {
12170 loff_t loff_in, loff_out;
12171 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012172 if (arg2) {
12173 if (get_user_u64(loff_in, arg2)) {
12174 goto efault;
12175 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012176 ploff_in = &loff_in;
12177 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012178 if (arg4) {
12179 if (get_user_u64(loff_out, arg4)) {
12180 goto efault;
12181 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012182 ploff_out = &loff_out;
12183 }
12184 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012185 if (arg2) {
12186 if (put_user_u64(loff_in, arg2)) {
12187 goto efault;
12188 }
12189 }
12190 if (arg4) {
12191 if (put_user_u64(loff_out, arg4)) {
12192 goto efault;
12193 }
12194 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012195 }
12196 break;
12197#endif
12198#ifdef TARGET_NR_vmsplice
12199 case TARGET_NR_vmsplice:
12200 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012201 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12202 if (vec != NULL) {
12203 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12204 unlock_iovec(vec, arg2, arg3, 0);
12205 } else {
12206 ret = -host_to_target_errno(errno);
12207 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012208 }
12209 break;
12210#endif
12211#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012212#ifdef CONFIG_EVENTFD
12213#if defined(TARGET_NR_eventfd)
12214 case TARGET_NR_eventfd:
12215 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012216 if (ret >= 0) {
12217 fd_trans_register(ret, &target_eventfd_trans);
12218 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012219 break;
12220#endif
12221#if defined(TARGET_NR_eventfd2)
12222 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012223 {
12224 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12225 if (arg2 & TARGET_O_NONBLOCK) {
12226 host_flags |= O_NONBLOCK;
12227 }
12228 if (arg2 & TARGET_O_CLOEXEC) {
12229 host_flags |= O_CLOEXEC;
12230 }
12231 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012232 if (ret >= 0) {
12233 fd_trans_register(ret, &target_eventfd_trans);
12234 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012235 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012236 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012237#endif
12238#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012239#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12240 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012241#if TARGET_ABI_BITS == 32
12242 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12243 target_offset64(arg5, arg6)));
12244#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012245 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012246#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030012247 break;
12248#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012249#if defined(CONFIG_SYNC_FILE_RANGE)
12250#if defined(TARGET_NR_sync_file_range)
12251 case TARGET_NR_sync_file_range:
12252#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012253#if defined(TARGET_MIPS)
12254 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12255 target_offset64(arg5, arg6), arg7));
12256#else
Peter Maydellc727f472011-01-06 11:05:10 +000012257 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12258 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012259#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012260#else
12261 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12262#endif
12263 break;
12264#endif
12265#if defined(TARGET_NR_sync_file_range2)
12266 case TARGET_NR_sync_file_range2:
12267 /* This is like sync_file_range but the arguments are reordered */
12268#if TARGET_ABI_BITS == 32
12269 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12270 target_offset64(arg5, arg6), arg2));
12271#else
12272 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12273#endif
12274 break;
12275#endif
12276#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012277#if defined(TARGET_NR_signalfd4)
12278 case TARGET_NR_signalfd4:
12279 ret = do_signalfd4(arg1, arg2, arg4);
12280 break;
12281#endif
12282#if defined(TARGET_NR_signalfd)
12283 case TARGET_NR_signalfd:
12284 ret = do_signalfd4(arg1, arg2, 0);
12285 break;
12286#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012287#if defined(CONFIG_EPOLL)
12288#if defined(TARGET_NR_epoll_create)
12289 case TARGET_NR_epoll_create:
12290 ret = get_errno(epoll_create(arg1));
12291 break;
12292#endif
12293#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12294 case TARGET_NR_epoll_create1:
12295 ret = get_errno(epoll_create1(arg1));
12296 break;
12297#endif
12298#if defined(TARGET_NR_epoll_ctl)
12299 case TARGET_NR_epoll_ctl:
12300 {
12301 struct epoll_event ep;
12302 struct epoll_event *epp = 0;
12303 if (arg4) {
12304 struct target_epoll_event *target_ep;
12305 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
12306 goto efault;
12307 }
12308 ep.events = tswap32(target_ep->events);
12309 /* The epoll_data_t union is just opaque data to the kernel,
12310 * so we transfer all 64 bits across and need not worry what
12311 * actual data type it is.
12312 */
12313 ep.data.u64 = tswap64(target_ep->data.u64);
12314 unlock_user_struct(target_ep, arg4, 0);
12315 epp = &ep;
12316 }
12317 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12318 break;
12319 }
12320#endif
12321
Peter Maydell227f0212016-06-06 19:58:11 +010012322#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012323#if defined(TARGET_NR_epoll_wait)
12324 case TARGET_NR_epoll_wait:
12325#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012326#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012327 case TARGET_NR_epoll_pwait:
12328#endif
12329 {
12330 struct target_epoll_event *target_ep;
12331 struct epoll_event *ep;
12332 int epfd = arg1;
12333 int maxevents = arg3;
12334 int timeout = arg4;
12335
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012336 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12337 ret = -TARGET_EINVAL;
12338 break;
12339 }
12340
Peter Maydell3b6edd12011-02-15 18:35:05 +000012341 target_ep = lock_user(VERIFY_WRITE, arg2,
12342 maxevents * sizeof(struct target_epoll_event), 1);
12343 if (!target_ep) {
12344 goto efault;
12345 }
12346
Peter Maydell04c95f42016-07-18 15:36:00 +010012347 ep = g_try_new(struct epoll_event, maxevents);
12348 if (!ep) {
12349 unlock_user(target_ep, arg2, 0);
12350 ret = -TARGET_ENOMEM;
12351 break;
12352 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012353
12354 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012355#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012356 case TARGET_NR_epoll_pwait:
12357 {
12358 target_sigset_t *target_set;
12359 sigset_t _set, *set = &_set;
12360
12361 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012362 if (arg6 != sizeof(target_sigset_t)) {
12363 ret = -TARGET_EINVAL;
12364 break;
12365 }
12366
Peter Maydell3b6edd12011-02-15 18:35:05 +000012367 target_set = lock_user(VERIFY_READ, arg5,
12368 sizeof(target_sigset_t), 1);
12369 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012370 ret = -TARGET_EFAULT;
12371 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012372 }
12373 target_to_host_sigset(set, target_set);
12374 unlock_user(target_set, arg5, 0);
12375 } else {
12376 set = NULL;
12377 }
12378
Peter Maydell227f0212016-06-06 19:58:11 +010012379 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12380 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012381 break;
12382 }
12383#endif
12384#if defined(TARGET_NR_epoll_wait)
12385 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012386 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12387 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012388 break;
12389#endif
12390 default:
12391 ret = -TARGET_ENOSYS;
12392 }
12393 if (!is_error(ret)) {
12394 int i;
12395 for (i = 0; i < ret; i++) {
12396 target_ep[i].events = tswap32(ep[i].events);
12397 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12398 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012399 unlock_user(target_ep, arg2,
12400 ret * sizeof(struct target_epoll_event));
12401 } else {
12402 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012403 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012404 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012405 break;
12406 }
12407#endif
12408#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012409#ifdef TARGET_NR_prlimit64
12410 case TARGET_NR_prlimit64:
12411 {
12412 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12413 struct target_rlimit64 *target_rnew, *target_rold;
12414 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012415 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012416 if (arg3) {
12417 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12418 goto efault;
12419 }
12420 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12421 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12422 unlock_user_struct(target_rnew, arg3, 0);
12423 rnewp = &rnew;
12424 }
12425
Felix Janda95018012014-12-02 22:11:17 +010012426 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012427 if (!is_error(ret) && arg4) {
12428 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12429 goto efault;
12430 }
12431 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12432 target_rold->rlim_max = tswap64(rold.rlim_max);
12433 unlock_user_struct(target_rold, arg4, 1);
12434 }
12435 break;
12436 }
12437#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012438#ifdef TARGET_NR_gethostname
12439 case TARGET_NR_gethostname:
12440 {
12441 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12442 if (name) {
12443 ret = get_errno(gethostname(name, arg2));
12444 unlock_user(name, arg1, arg2);
12445 } else {
12446 ret = -TARGET_EFAULT;
12447 }
12448 break;
12449 }
12450#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012451#ifdef TARGET_NR_atomic_cmpxchg_32
12452 case TARGET_NR_atomic_cmpxchg_32:
12453 {
12454 /* should use start_exclusive from main.c */
12455 abi_ulong mem_value;
12456 if (get_user_u32(mem_value, arg6)) {
12457 target_siginfo_t info;
12458 info.si_signo = SIGSEGV;
12459 info.si_errno = 0;
12460 info.si_code = TARGET_SEGV_MAPERR;
12461 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012462 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12463 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012464 ret = 0xdeadbeef;
12465
12466 }
12467 if (mem_value == arg2)
12468 put_user_u32(arg1, arg6);
12469 ret = mem_value;
12470 break;
12471 }
12472#endif
12473#ifdef TARGET_NR_atomic_barrier
12474 case TARGET_NR_atomic_barrier:
12475 {
12476 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012477 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012478 break;
12479 }
12480#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012481
12482#ifdef TARGET_NR_timer_create
12483 case TARGET_NR_timer_create:
12484 {
12485 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12486
12487 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012488
12489 int clkid = arg1;
12490 int timer_index = next_free_host_timer();
12491
12492 if (timer_index < 0) {
12493 ret = -TARGET_EAGAIN;
12494 } else {
12495 timer_t *phtimer = g_posix_timers + timer_index;
12496
12497 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012498 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012499 ret = target_to_host_sigevent(phost_sevp, arg2);
12500 if (ret != 0) {
12501 break;
12502 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012503 }
12504
12505 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12506 if (ret) {
12507 phtimer = NULL;
12508 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012509 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012510 goto efault;
12511 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012512 }
12513 }
12514 break;
12515 }
12516#endif
12517
12518#ifdef TARGET_NR_timer_settime
12519 case TARGET_NR_timer_settime:
12520 {
12521 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12522 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012523 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012524
Alexander Grafaecc8862014-11-10 21:33:03 +010012525 if (timerid < 0) {
12526 ret = timerid;
12527 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012528 ret = -TARGET_EINVAL;
12529 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012530 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012531 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12532
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012533 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12534 goto efault;
12535 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012536 ret = get_errno(
12537 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012538 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12539 goto efault;
12540 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012541 }
12542 break;
12543 }
12544#endif
12545
12546#ifdef TARGET_NR_timer_gettime
12547 case TARGET_NR_timer_gettime:
12548 {
12549 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012550 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012551
Alexander Grafaecc8862014-11-10 21:33:03 +010012552 if (timerid < 0) {
12553 ret = timerid;
12554 } else if (!arg2) {
12555 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012556 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012557 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012558 struct itimerspec hspec;
12559 ret = get_errno(timer_gettime(htimer, &hspec));
12560
12561 if (host_to_target_itimerspec(arg2, &hspec)) {
12562 ret = -TARGET_EFAULT;
12563 }
12564 }
12565 break;
12566 }
12567#endif
12568
12569#ifdef TARGET_NR_timer_getoverrun
12570 case TARGET_NR_timer_getoverrun:
12571 {
12572 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012573 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012574
Alexander Grafaecc8862014-11-10 21:33:03 +010012575 if (timerid < 0) {
12576 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012577 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012578 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012579 ret = get_errno(timer_getoverrun(htimer));
12580 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012581 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012582 break;
12583 }
12584#endif
12585
12586#ifdef TARGET_NR_timer_delete
12587 case TARGET_NR_timer_delete:
12588 {
12589 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012590 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012591
Alexander Grafaecc8862014-11-10 21:33:03 +010012592 if (timerid < 0) {
12593 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012594 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012595 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012596 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012597 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012598 }
12599 break;
12600 }
12601#endif
12602
Riku Voipio51834342014-06-22 11:25:42 +010012603#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12604 case TARGET_NR_timerfd_create:
12605 ret = get_errno(timerfd_create(arg1,
12606 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12607 break;
12608#endif
12609
12610#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12611 case TARGET_NR_timerfd_gettime:
12612 {
12613 struct itimerspec its_curr;
12614
12615 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12616
12617 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12618 goto efault;
12619 }
12620 }
12621 break;
12622#endif
12623
12624#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12625 case TARGET_NR_timerfd_settime:
12626 {
12627 struct itimerspec its_new, its_old, *p_new;
12628
12629 if (arg3) {
12630 if (target_to_host_itimerspec(&its_new, arg3)) {
12631 goto efault;
12632 }
12633 p_new = &its_new;
12634 } else {
12635 p_new = NULL;
12636 }
12637
12638 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12639
12640 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12641 goto efault;
12642 }
12643 }
12644 break;
12645#endif
12646
Paul Burtonab31cda2014-06-22 11:25:43 +010012647#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12648 case TARGET_NR_ioprio_get:
12649 ret = get_errno(ioprio_get(arg1, arg2));
12650 break;
12651#endif
12652
12653#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12654 case TARGET_NR_ioprio_set:
12655 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12656 break;
12657#endif
12658
Riku Voipio9af5c902014-08-12 15:58:57 +030012659#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12660 case TARGET_NR_setns:
12661 ret = get_errno(setns(arg1, arg2));
12662 break;
12663#endif
12664#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12665 case TARGET_NR_unshare:
12666 ret = get_errno(unshare(arg1));
12667 break;
12668#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012669#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12670 case TARGET_NR_kcmp:
12671 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12672 break;
12673#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012674
bellard31e31b82003-02-18 22:55:36 +000012675 default:
12676 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000012677 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012678#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 +000012679 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012680#endif
ths0da46a62007-10-20 20:23:07 +000012681 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012682 break;
12683 }
bellard579a97f2007-11-11 14:26:47 +000012684fail:
bellardc573ff62004-01-04 15:51:36 +000012685#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012686 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012687#endif
thsb92c47c2007-11-01 00:07:38 +000012688 if(do_strace)
12689 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020012690 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012691 return ret;
bellard579a97f2007-11-11 14:26:47 +000012692efault:
12693 ret = -TARGET_EFAULT;
12694 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012695}