blob: d51e2a00ee31e70b60a18f3d70d83c141264b69e [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
Chen Gang704eff62015-08-21 05:37:33 +0800262#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000263_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100264#endif
265#if !defined(__NR_getdents) || \
266 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000267_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
268#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700269#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000270_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
271 loff_t *, res, uint, wh);
272#endif
Miloš Stojanovićc1a402a2017-05-15 16:59:45 +0200273_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +0200274_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
275 siginfo_t *, uinfo)
aurel323b3f24a2009-04-15 16:12:13 +0000276_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000277#ifdef __NR_exit_group
278_syscall1(int,exit_group,int,error_code)
279#endif
280#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
281_syscall1(int,set_tid_address,int *,tidptr)
282#endif
aurel323b3f24a2009-04-15 16:12:13 +0000283#if defined(TARGET_NR_futex) && defined(__NR_futex)
284_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
285 const struct timespec *,timeout,int *,uaddr2,int,val3)
286#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500287#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
288_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
289 unsigned long *, user_mask_ptr);
290#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
291_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
292 unsigned long *, user_mask_ptr);
Samuel Thibaultb827c3e2018-01-12 09:14:35 +0100293#define __NR_sys_getcpu __NR_getcpu
294_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200295_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
296 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000297_syscall2(int, capget, struct __user_cap_header_struct *, header,
298 struct __user_cap_data_struct *, data);
299_syscall2(int, capset, struct __user_cap_header_struct *, header,
300 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100301#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
302_syscall2(int, ioprio_get, int, which, int, who)
303#endif
304#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
305_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
306#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100307#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
308_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
309#endif
aurel323b3f24a2009-04-15 16:12:13 +0000310
Laurent Vivier2f147882016-09-25 22:20:20 +0200311#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
312_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
313 unsigned long, idx1, unsigned long, idx2)
314#endif
315
aurel323b3f24a2009-04-15 16:12:13 +0000316static bitmask_transtbl fcntl_flags_tbl[] = {
317 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
318 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
319 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
320 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
321 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
322 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
323 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
324 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700325 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000326 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
327 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
328 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
329 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000330#if defined(O_DIRECT)
331 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
332#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700333#if defined(O_NOATIME)
334 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
335#endif
336#if defined(O_CLOEXEC)
337 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
338#endif
339#if defined(O_PATH)
340 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
341#endif
Riku Voipio5f9cee42017-08-08 16:01:19 +0300342#if defined(O_TMPFILE)
343 { TARGET_O_TMPFILE, TARGET_O_TMPFILE, O_TMPFILE, O_TMPFILE },
344#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700345 /* Don't terminate the list prematurely on 64-bit host+guest. */
346#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
347 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
348#endif
aurel323b3f24a2009-04-15 16:12:13 +0000349 { 0, 0, 0, 0 }
350};
351
Michal Privoznik60c6b792016-08-19 10:06:40 +0200352enum {
353 QEMU_IFLA_BR_UNSPEC,
354 QEMU_IFLA_BR_FORWARD_DELAY,
355 QEMU_IFLA_BR_HELLO_TIME,
356 QEMU_IFLA_BR_MAX_AGE,
357 QEMU_IFLA_BR_AGEING_TIME,
358 QEMU_IFLA_BR_STP_STATE,
359 QEMU_IFLA_BR_PRIORITY,
360 QEMU_IFLA_BR_VLAN_FILTERING,
361 QEMU_IFLA_BR_VLAN_PROTOCOL,
362 QEMU_IFLA_BR_GROUP_FWD_MASK,
363 QEMU_IFLA_BR_ROOT_ID,
364 QEMU_IFLA_BR_BRIDGE_ID,
365 QEMU_IFLA_BR_ROOT_PORT,
366 QEMU_IFLA_BR_ROOT_PATH_COST,
367 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
368 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
369 QEMU_IFLA_BR_HELLO_TIMER,
370 QEMU_IFLA_BR_TCN_TIMER,
371 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
372 QEMU_IFLA_BR_GC_TIMER,
373 QEMU_IFLA_BR_GROUP_ADDR,
374 QEMU_IFLA_BR_FDB_FLUSH,
375 QEMU_IFLA_BR_MCAST_ROUTER,
376 QEMU_IFLA_BR_MCAST_SNOOPING,
377 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
378 QEMU_IFLA_BR_MCAST_QUERIER,
379 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
380 QEMU_IFLA_BR_MCAST_HASH_MAX,
381 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
382 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
383 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
384 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
385 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
386 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
387 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
388 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
389 QEMU_IFLA_BR_NF_CALL_IPTABLES,
390 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
391 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
392 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
393 QEMU_IFLA_BR_PAD,
394 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
395 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
396 QEMU___IFLA_BR_MAX,
397};
398
399enum {
400 QEMU_IFLA_UNSPEC,
401 QEMU_IFLA_ADDRESS,
402 QEMU_IFLA_BROADCAST,
403 QEMU_IFLA_IFNAME,
404 QEMU_IFLA_MTU,
405 QEMU_IFLA_LINK,
406 QEMU_IFLA_QDISC,
407 QEMU_IFLA_STATS,
408 QEMU_IFLA_COST,
409 QEMU_IFLA_PRIORITY,
410 QEMU_IFLA_MASTER,
411 QEMU_IFLA_WIRELESS,
412 QEMU_IFLA_PROTINFO,
413 QEMU_IFLA_TXQLEN,
414 QEMU_IFLA_MAP,
415 QEMU_IFLA_WEIGHT,
416 QEMU_IFLA_OPERSTATE,
417 QEMU_IFLA_LINKMODE,
418 QEMU_IFLA_LINKINFO,
419 QEMU_IFLA_NET_NS_PID,
420 QEMU_IFLA_IFALIAS,
421 QEMU_IFLA_NUM_VF,
422 QEMU_IFLA_VFINFO_LIST,
423 QEMU_IFLA_STATS64,
424 QEMU_IFLA_VF_PORTS,
425 QEMU_IFLA_PORT_SELF,
426 QEMU_IFLA_AF_SPEC,
427 QEMU_IFLA_GROUP,
428 QEMU_IFLA_NET_NS_FD,
429 QEMU_IFLA_EXT_MASK,
430 QEMU_IFLA_PROMISCUITY,
431 QEMU_IFLA_NUM_TX_QUEUES,
432 QEMU_IFLA_NUM_RX_QUEUES,
433 QEMU_IFLA_CARRIER,
434 QEMU_IFLA_PHYS_PORT_ID,
435 QEMU_IFLA_CARRIER_CHANGES,
436 QEMU_IFLA_PHYS_SWITCH_ID,
437 QEMU_IFLA_LINK_NETNSID,
438 QEMU_IFLA_PHYS_PORT_NAME,
439 QEMU_IFLA_PROTO_DOWN,
440 QEMU_IFLA_GSO_MAX_SEGS,
441 QEMU_IFLA_GSO_MAX_SIZE,
442 QEMU_IFLA_PAD,
443 QEMU_IFLA_XDP,
444 QEMU___IFLA_MAX
445};
446
447enum {
448 QEMU_IFLA_BRPORT_UNSPEC,
449 QEMU_IFLA_BRPORT_STATE,
450 QEMU_IFLA_BRPORT_PRIORITY,
451 QEMU_IFLA_BRPORT_COST,
452 QEMU_IFLA_BRPORT_MODE,
453 QEMU_IFLA_BRPORT_GUARD,
454 QEMU_IFLA_BRPORT_PROTECT,
455 QEMU_IFLA_BRPORT_FAST_LEAVE,
456 QEMU_IFLA_BRPORT_LEARNING,
457 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
458 QEMU_IFLA_BRPORT_PROXYARP,
459 QEMU_IFLA_BRPORT_LEARNING_SYNC,
460 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
461 QEMU_IFLA_BRPORT_ROOT_ID,
462 QEMU_IFLA_BRPORT_BRIDGE_ID,
463 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
464 QEMU_IFLA_BRPORT_DESIGNATED_COST,
465 QEMU_IFLA_BRPORT_ID,
466 QEMU_IFLA_BRPORT_NO,
467 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
468 QEMU_IFLA_BRPORT_CONFIG_PENDING,
469 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
470 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
471 QEMU_IFLA_BRPORT_HOLD_TIMER,
472 QEMU_IFLA_BRPORT_FLUSH,
473 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
474 QEMU_IFLA_BRPORT_PAD,
475 QEMU___IFLA_BRPORT_MAX
476};
477
478enum {
479 QEMU_IFLA_INFO_UNSPEC,
480 QEMU_IFLA_INFO_KIND,
481 QEMU_IFLA_INFO_DATA,
482 QEMU_IFLA_INFO_XSTATS,
483 QEMU_IFLA_INFO_SLAVE_KIND,
484 QEMU_IFLA_INFO_SLAVE_DATA,
485 QEMU___IFLA_INFO_MAX,
486};
487
488enum {
489 QEMU_IFLA_INET_UNSPEC,
490 QEMU_IFLA_INET_CONF,
491 QEMU___IFLA_INET_MAX,
492};
493
494enum {
495 QEMU_IFLA_INET6_UNSPEC,
496 QEMU_IFLA_INET6_FLAGS,
497 QEMU_IFLA_INET6_CONF,
498 QEMU_IFLA_INET6_STATS,
499 QEMU_IFLA_INET6_MCAST,
500 QEMU_IFLA_INET6_CACHEINFO,
501 QEMU_IFLA_INET6_ICMP6STATS,
502 QEMU_IFLA_INET6_TOKEN,
503 QEMU_IFLA_INET6_ADDR_GEN_MODE,
504 QEMU___IFLA_INET6_MAX
505};
506
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100507typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100508typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200509typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100510 TargetFdDataFunc host_to_target_data;
511 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100512 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200513} TargetFdTrans;
514
515static TargetFdTrans **target_fd_trans;
516
517static unsigned int target_fd_max;
518
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200519static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
520{
521 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
522 return target_fd_trans[fd]->target_to_host_data;
523 }
524 return NULL;
525}
526
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100527static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200528{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100529 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100530 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200531 }
532 return NULL;
533}
534
Laurent Vivier7b36f782015-10-28 21:40:44 +0100535static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
536{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100537 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100538 return target_fd_trans[fd]->target_to_host_addr;
539 }
540 return NULL;
541}
542
Laurent Viviere36800c2015-10-02 14:48:09 +0200543static void fd_trans_register(int fd, TargetFdTrans *trans)
544{
545 unsigned int oldmax;
546
547 if (fd >= target_fd_max) {
548 oldmax = target_fd_max;
549 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100550 target_fd_trans = g_renew(TargetFdTrans *,
551 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200552 memset((void *)(target_fd_trans + oldmax), 0,
553 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
554 }
555 target_fd_trans[fd] = trans;
556}
557
558static void fd_trans_unregister(int fd)
559{
560 if (fd >= 0 && fd < target_fd_max) {
561 target_fd_trans[fd] = NULL;
562 }
563}
564
565static void fd_trans_dup(int oldfd, int newfd)
566{
567 fd_trans_unregister(newfd);
568 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
569 fd_trans_register(newfd, target_fd_trans[oldfd]);
570 }
571}
572
aurel323b3f24a2009-04-15 16:12:13 +0000573static int sys_getcwd1(char *buf, size_t size)
574{
575 if (getcwd(buf, size) == NULL) {
576 /* getcwd() sets errno */
577 return (-1);
578 }
aurel32aaf4ad32009-04-16 14:17:14 +0000579 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000580}
581
Peter Maydell1acae9f2013-07-02 14:04:12 +0100582#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100583#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100584#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000585_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
586 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100587#else
588static int sys_utimensat(int dirfd, const char *pathname,
589 const struct timespec times[2], int flags)
590{
591 errno = ENOSYS;
592 return -1;
593}
ths9007f0e2007-09-25 17:50:37 +0000594#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100595#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000596
Andreas Schwab95d03072018-01-23 11:53:31 +0100597#ifdef TARGET_NR_renameat2
598#if defined(__NR_renameat2)
599#define __NR_sys_renameat2 __NR_renameat2
600_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
601 const char *, new, unsigned int, flags)
602#else
603static int sys_renameat2(int oldfd, const char *old,
604 int newfd, const char *new, int flags)
605{
606 if (flags == 0) {
607 return renameat(oldfd, old, newfd, new);
608 }
609 errno = ENOSYS;
610 return -1;
611}
612#endif
613#endif /* TARGET_NR_renameat2 */
614
aurel323b3f24a2009-04-15 16:12:13 +0000615#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000616#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000617
aurel3239b59762008-10-01 21:46:50 +0000618#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000619static int sys_inotify_init(void)
620{
621 return (inotify_init());
622}
aurel3239b59762008-10-01 21:46:50 +0000623#endif
624#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000625static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
626{
627 return (inotify_add_watch(fd, pathname, mask));
628}
aurel3239b59762008-10-01 21:46:50 +0000629#endif
630#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000631static int sys_inotify_rm_watch(int fd, int32_t wd)
632{
aurel328690e422009-04-17 13:50:32 +0000633 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000634}
aurel3239b59762008-10-01 21:46:50 +0000635#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000636#ifdef CONFIG_INOTIFY1
637#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
638static int sys_inotify_init1(int flags)
639{
640 return (inotify_init1(flags));
641}
642#endif
643#endif
aurel323b3f24a2009-04-15 16:12:13 +0000644#else
645/* Userspace can usually survive runtime without inotify */
646#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000647#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000648#undef TARGET_NR_inotify_add_watch
649#undef TARGET_NR_inotify_rm_watch
650#endif /* CONFIG_INOTIFY */
651
Peter Maydell163a05a2011-06-27 17:44:52 +0100652#if defined(TARGET_NR_prlimit64)
653#ifndef __NR_prlimit64
654# define __NR_prlimit64 -1
655#endif
656#define __NR_sys_prlimit64 __NR_prlimit64
657/* The glibc rlimit structure may not be that used by the underlying syscall */
658struct host_rlimit64 {
659 uint64_t rlim_cur;
660 uint64_t rlim_max;
661};
662_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
663 const struct host_rlimit64 *, new_limit,
664 struct host_rlimit64 *, old_limit)
665#endif
666
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100667
668#if defined(TARGET_NR_timer_create)
669/* Maxiumum of 32 active POSIX timers allowed at any one time. */
670static timer_t g_posix_timers[32] = { 0, } ;
671
672static inline int next_free_host_timer(void)
673{
674 int k ;
675 /* FIXME: Does finding the next free slot require a lock? */
676 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
677 if (g_posix_timers[k] == 0) {
678 g_posix_timers[k] = (timer_t) 1;
679 return k;
680 }
681 }
682 return -1;
683}
684#endif
685
Riku Voipio48e515d2011-07-12 15:40:51 +0300686/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000687#ifdef TARGET_ARM
James Clarke8bf8e9d2017-09-15 20:33:13 +0100688static inline int regpairs_aligned(void *cpu_env, int num)
689{
Riku Voipio48e515d2011-07-12 15:40:51 +0300690 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
691}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200692#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
James Clarke8bf8e9d2017-09-15 20:33:13 +0100693static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000694#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
695/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
696 * of registers which translates to the same as ARM/MIPS, because we start with
697 * r3 as arg1 */
James Clarke8bf8e9d2017-09-15 20:33:13 +0100698static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
699#elif defined(TARGET_SH4)
700/* SH4 doesn't align register pairs, except for p{read,write}64 */
701static inline int regpairs_aligned(void *cpu_env, int num)
702{
703 switch (num) {
704 case TARGET_NR_pread64:
705 case TARGET_NR_pwrite64:
706 return 1;
707
708 default:
709 return 0;
710 }
711}
Max Filippovba7651f2017-01-25 10:54:11 -0800712#elif defined(TARGET_XTENSA)
713static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300714#else
James Clarke8bf8e9d2017-09-15 20:33:13 +0100715static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300716#endif
717
thsb92c47c2007-11-01 00:07:38 +0000718#define ERRNO_TABLE_SIZE 1200
719
720/* target_to_host_errno_table[] is initialized from
721 * host_to_target_errno_table[] in syscall_init(). */
722static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
723};
724
ths637947f2007-06-01 12:09:19 +0000725/*
thsfe8f0962007-07-12 10:59:21 +0000726 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000727 * minus the errnos that are not actually generic to all archs.
728 */
thsb92c47c2007-11-01 00:07:38 +0000729static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800730 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000731 [EIDRM] = TARGET_EIDRM,
732 [ECHRNG] = TARGET_ECHRNG,
733 [EL2NSYNC] = TARGET_EL2NSYNC,
734 [EL3HLT] = TARGET_EL3HLT,
735 [EL3RST] = TARGET_EL3RST,
736 [ELNRNG] = TARGET_ELNRNG,
737 [EUNATCH] = TARGET_EUNATCH,
738 [ENOCSI] = TARGET_ENOCSI,
739 [EL2HLT] = TARGET_EL2HLT,
740 [EDEADLK] = TARGET_EDEADLK,
741 [ENOLCK] = TARGET_ENOLCK,
742 [EBADE] = TARGET_EBADE,
743 [EBADR] = TARGET_EBADR,
744 [EXFULL] = TARGET_EXFULL,
745 [ENOANO] = TARGET_ENOANO,
746 [EBADRQC] = TARGET_EBADRQC,
747 [EBADSLT] = TARGET_EBADSLT,
748 [EBFONT] = TARGET_EBFONT,
749 [ENOSTR] = TARGET_ENOSTR,
750 [ENODATA] = TARGET_ENODATA,
751 [ETIME] = TARGET_ETIME,
752 [ENOSR] = TARGET_ENOSR,
753 [ENONET] = TARGET_ENONET,
754 [ENOPKG] = TARGET_ENOPKG,
755 [EREMOTE] = TARGET_EREMOTE,
756 [ENOLINK] = TARGET_ENOLINK,
757 [EADV] = TARGET_EADV,
758 [ESRMNT] = TARGET_ESRMNT,
759 [ECOMM] = TARGET_ECOMM,
760 [EPROTO] = TARGET_EPROTO,
761 [EDOTDOT] = TARGET_EDOTDOT,
762 [EMULTIHOP] = TARGET_EMULTIHOP,
763 [EBADMSG] = TARGET_EBADMSG,
764 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
765 [EOVERFLOW] = TARGET_EOVERFLOW,
766 [ENOTUNIQ] = TARGET_ENOTUNIQ,
767 [EBADFD] = TARGET_EBADFD,
768 [EREMCHG] = TARGET_EREMCHG,
769 [ELIBACC] = TARGET_ELIBACC,
770 [ELIBBAD] = TARGET_ELIBBAD,
771 [ELIBSCN] = TARGET_ELIBSCN,
772 [ELIBMAX] = TARGET_ELIBMAX,
773 [ELIBEXEC] = TARGET_ELIBEXEC,
774 [EILSEQ] = TARGET_EILSEQ,
775 [ENOSYS] = TARGET_ENOSYS,
776 [ELOOP] = TARGET_ELOOP,
777 [ERESTART] = TARGET_ERESTART,
778 [ESTRPIPE] = TARGET_ESTRPIPE,
779 [ENOTEMPTY] = TARGET_ENOTEMPTY,
780 [EUSERS] = TARGET_EUSERS,
781 [ENOTSOCK] = TARGET_ENOTSOCK,
782 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
783 [EMSGSIZE] = TARGET_EMSGSIZE,
784 [EPROTOTYPE] = TARGET_EPROTOTYPE,
785 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
786 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
787 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
788 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
789 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
790 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
791 [EADDRINUSE] = TARGET_EADDRINUSE,
792 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
793 [ENETDOWN] = TARGET_ENETDOWN,
794 [ENETUNREACH] = TARGET_ENETUNREACH,
795 [ENETRESET] = TARGET_ENETRESET,
796 [ECONNABORTED] = TARGET_ECONNABORTED,
797 [ECONNRESET] = TARGET_ECONNRESET,
798 [ENOBUFS] = TARGET_ENOBUFS,
799 [EISCONN] = TARGET_EISCONN,
800 [ENOTCONN] = TARGET_ENOTCONN,
801 [EUCLEAN] = TARGET_EUCLEAN,
802 [ENOTNAM] = TARGET_ENOTNAM,
803 [ENAVAIL] = TARGET_ENAVAIL,
804 [EISNAM] = TARGET_EISNAM,
805 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200806 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000807 [ESHUTDOWN] = TARGET_ESHUTDOWN,
808 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
809 [ETIMEDOUT] = TARGET_ETIMEDOUT,
810 [ECONNREFUSED] = TARGET_ECONNREFUSED,
811 [EHOSTDOWN] = TARGET_EHOSTDOWN,
812 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
813 [EALREADY] = TARGET_EALREADY,
814 [EINPROGRESS] = TARGET_EINPROGRESS,
815 [ESTALE] = TARGET_ESTALE,
816 [ECANCELED] = TARGET_ECANCELED,
817 [ENOMEDIUM] = TARGET_ENOMEDIUM,
818 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000819#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000820 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000821#endif
822#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000823 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000824#endif
825#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000826 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000827#endif
828#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000829 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000830#endif
831#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000832 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000833#endif
834#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000835 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000836#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200837#ifdef ENOMSG
838 [ENOMSG] = TARGET_ENOMSG,
839#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800840#ifdef ERKFILL
841 [ERFKILL] = TARGET_ERFKILL,
842#endif
843#ifdef EHWPOISON
844 [EHWPOISON] = TARGET_EHWPOISON,
845#endif
thsb92c47c2007-11-01 00:07:38 +0000846};
ths637947f2007-06-01 12:09:19 +0000847
848static inline int host_to_target_errno(int err)
849{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100850 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
851 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000852 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100853 }
ths637947f2007-06-01 12:09:19 +0000854 return err;
855}
856
thsb92c47c2007-11-01 00:07:38 +0000857static inline int target_to_host_errno(int err)
858{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100859 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
860 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000861 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100862 }
thsb92c47c2007-11-01 00:07:38 +0000863 return err;
864}
865
blueswir1992f48a2007-10-14 16:27:31 +0000866static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000867{
868 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000869 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000870 else
871 return ret;
872}
873
blueswir1992f48a2007-10-14 16:27:31 +0000874static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000875{
blueswir1992f48a2007-10-14 16:27:31 +0000876 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000877}
878
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100879const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000880{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100881 if (err == TARGET_ERESTARTSYS) {
882 return "To be restarted";
883 }
884 if (err == TARGET_QEMU_ESIGRETURN) {
885 return "Successful exit from sigreturn";
886 }
887
Alexander Graf962b2892011-11-21 12:04:07 +0100888 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
889 return NULL;
890 }
thsb92c47c2007-11-01 00:07:38 +0000891 return strerror(target_to_host_errno(err));
892}
893
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100894#define safe_syscall0(type, name) \
895static type safe_##name(void) \
896{ \
897 return safe_syscall(__NR_##name); \
898}
899
900#define safe_syscall1(type, name, type1, arg1) \
901static type safe_##name(type1 arg1) \
902{ \
903 return safe_syscall(__NR_##name, arg1); \
904}
905
906#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
907static type safe_##name(type1 arg1, type2 arg2) \
908{ \
909 return safe_syscall(__NR_##name, arg1, arg2); \
910}
911
912#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
913static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
914{ \
915 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
916}
917
918#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
919 type4, arg4) \
920static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
921{ \
922 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
923}
924
925#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
926 type4, arg4, type5, arg5) \
927static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
928 type5 arg5) \
929{ \
930 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
931}
932
933#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
934 type4, arg4, type5, arg5, type6, arg6) \
935static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
936 type5 arg5, type6 arg6) \
937{ \
938 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
939}
940
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100941safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
942safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100943safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
944 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100945safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
946 struct rusage *, rusage)
947safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
948 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100949safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100950safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
951 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100952safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
953 struct timespec *, tsp, const sigset_t *, sigmask,
954 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100955safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
956 int, maxevents, int, timeout, const sigset_t *, sigmask,
957 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100958safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
959 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100960safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100961safe_syscall2(int, kill, pid_t, pid, int, sig)
962safe_syscall2(int, tkill, int, tid, int, sig)
963safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100964safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
965safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200966safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
967 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200968safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
969 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100970safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
971 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100972safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
973 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
974safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
975 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
976safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
977safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100978safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100979safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
980 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100981safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
982 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100983safe_syscall2(int, nanosleep, const struct timespec *, req,
984 struct timespec *, rem)
985#ifdef TARGET_NR_clock_nanosleep
986safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
987 const struct timespec *, req, struct timespec *, rem)
988#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100989#ifdef __NR_msgsnd
990safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
991 int, flags)
992safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
993 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100994safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
995 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100996#else
997/* This host kernel architecture uses a single ipc syscall; fake up
998 * wrappers for the sub-operations to hide this implementation detail.
999 * Annoyingly we can't include linux/ipc.h to get the constant definitions
1000 * for the call parameter because some structs in there conflict with the
1001 * sys/ipc.h ones. So we just define them here, and rely on them being
1002 * the same for all host architectures.
1003 */
Peter Maydellffb7ee72016-06-06 19:58:12 +01001004#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +01001005#define Q_MSGSND 11
1006#define Q_MSGRCV 12
1007#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
1008
1009safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
1010 void *, ptr, long, fifth)
1011static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
1012{
1013 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
1014}
1015static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
1016{
1017 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
1018}
Peter Maydellffb7ee72016-06-06 19:58:12 +01001019static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
1020 const struct timespec *timeout)
1021{
1022 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
1023 (long)timeout);
1024}
Peter Maydell89f9fe42016-06-06 19:58:05 +01001025#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +01001026#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1027safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
1028 size_t, len, unsigned, prio, const struct timespec *, timeout)
1029safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
1030 size_t, len, unsigned *, prio, const struct timespec *, timeout)
1031#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +01001032/* We do ioctl like this rather than via safe_syscall3 to preserve the
1033 * "third argument might be integer or pointer or not present" behaviour of
1034 * the libc function.
1035 */
1036#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +01001037/* Similarly for fcntl. Note that callers must always:
1038 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1039 * use the flock64 struct rather than unsuffixed flock
1040 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1041 */
1042#ifdef __NR_fcntl64
1043#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1044#else
1045#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1046#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001047
Paul Burton8289d112014-06-22 11:25:33 +01001048static inline int host_to_target_sock_type(int host_type)
1049{
1050 int target_type;
1051
1052 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1053 case SOCK_DGRAM:
1054 target_type = TARGET_SOCK_DGRAM;
1055 break;
1056 case SOCK_STREAM:
1057 target_type = TARGET_SOCK_STREAM;
1058 break;
1059 default:
1060 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1061 break;
1062 }
1063
1064#if defined(SOCK_CLOEXEC)
1065 if (host_type & SOCK_CLOEXEC) {
1066 target_type |= TARGET_SOCK_CLOEXEC;
1067 }
1068#endif
1069
1070#if defined(SOCK_NONBLOCK)
1071 if (host_type & SOCK_NONBLOCK) {
1072 target_type |= TARGET_SOCK_NONBLOCK;
1073 }
1074#endif
1075
1076 return target_type;
1077}
1078
blueswir1992f48a2007-10-14 16:27:31 +00001079static abi_ulong target_brk;
1080static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001081static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001082
blueswir1992f48a2007-10-14 16:27:31 +00001083void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001084{
blueswir14c1de732007-07-07 20:45:44 +00001085 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001086 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001087}
1088
vincent4d1de872011-06-14 21:56:33 +00001089//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1090#define DEBUGF_BRK(message, args...)
1091
ths0da46a62007-10-20 20:23:07 +00001092/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001093abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001094{
blueswir1992f48a2007-10-14 16:27:31 +00001095 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001096 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001097
Paul Brook3a0c6c42012-02-09 19:04:27 +00001098 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001099
vincent4d1de872011-06-14 21:56:33 +00001100 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001101 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001102 return target_brk;
1103 }
1104 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001105 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1106 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001107 return target_brk;
1108 }
bellard31e31b82003-02-18 22:55:36 +00001109
vincent4d1de872011-06-14 21:56:33 +00001110 /* If the new brk is less than the highest page reserved to the
1111 * target heap allocation, set it and we're almost done... */
1112 if (new_brk <= brk_page) {
1113 /* Heap contents are initialized to zero, as for anonymous
1114 * mapped pages. */
1115 if (new_brk > target_brk) {
1116 memset(g2h(target_brk), 0, new_brk - target_brk);
1117 }
bellard31e31b82003-02-18 22:55:36 +00001118 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001119 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001120 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001121 }
1122
Peter Maydell00faf082011-04-18 16:34:24 +01001123 /* We need to allocate more memory after the brk... Note that
1124 * we don't use MAP_FIXED because that will map over the top of
1125 * any existing mapping (like the one with the host libc or qemu
1126 * itself); instead we treat "mapped but at wrong address" as
1127 * a failure and unmap again.
1128 */
vincent4d1de872011-06-14 21:56:33 +00001129 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001130 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001131 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001132 MAP_ANON|MAP_PRIVATE, 0, 0));
1133
1134 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001135 /* Heap contents are initialized to zero, as for anonymous
1136 * mapped pages. Technically the new pages are already
1137 * initialized to zero since they *are* anonymous mapped
1138 * pages, however we have to take care with the contents that
1139 * come from the remaining part of the previous page: it may
1140 * contains garbage data due to a previous heap usage (grown
1141 * then shrunken). */
1142 memset(g2h(target_brk), 0, brk_page - target_brk);
1143
Peter Maydell00faf082011-04-18 16:34:24 +01001144 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001145 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001146 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1147 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001148 return target_brk;
1149 } else if (mapped_addr != -1) {
1150 /* Mapped but at wrong address, meaning there wasn't actually
1151 * enough space for this brk.
1152 */
1153 target_munmap(mapped_addr, new_alloc_size);
1154 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001155 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001156 }
1157 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001158 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001159 }
balrog7ab240a2008-04-26 12:17:34 +00001160
Richard Henderson7dd46c02010-05-03 10:07:49 -07001161#if defined(TARGET_ALPHA)
1162 /* We (partially) emulate OSF/1 on Alpha, which requires we
1163 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001164 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001165#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001166 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001167 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001168}
1169
ths26edcf42007-12-09 02:25:24 +00001170static inline abi_long copy_from_user_fdset(fd_set *fds,
1171 abi_ulong target_fds_addr,
1172 int n)
bellard31e31b82003-02-18 22:55:36 +00001173{
ths26edcf42007-12-09 02:25:24 +00001174 int i, nw, j, k;
1175 abi_ulong b, *target_fds;
1176
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001177 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001178 if (!(target_fds = lock_user(VERIFY_READ,
1179 target_fds_addr,
1180 sizeof(abi_ulong) * nw,
1181 1)))
1182 return -TARGET_EFAULT;
1183
1184 FD_ZERO(fds);
1185 k = 0;
1186 for (i = 0; i < nw; i++) {
1187 /* grab the abi_ulong */
1188 __get_user(b, &target_fds[i]);
1189 for (j = 0; j < TARGET_ABI_BITS; j++) {
1190 /* check the bit inside the abi_ulong */
1191 if ((b >> j) & 1)
1192 FD_SET(k, fds);
1193 k++;
bellard31e31b82003-02-18 22:55:36 +00001194 }
bellard31e31b82003-02-18 22:55:36 +00001195 }
ths26edcf42007-12-09 02:25:24 +00001196
1197 unlock_user(target_fds, target_fds_addr, 0);
1198
1199 return 0;
bellard31e31b82003-02-18 22:55:36 +00001200}
1201
Mike Frysinger055e0902011-06-03 17:01:49 -04001202static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1203 abi_ulong target_fds_addr,
1204 int n)
1205{
1206 if (target_fds_addr) {
1207 if (copy_from_user_fdset(fds, target_fds_addr, n))
1208 return -TARGET_EFAULT;
1209 *fds_ptr = fds;
1210 } else {
1211 *fds_ptr = NULL;
1212 }
1213 return 0;
1214}
1215
ths26edcf42007-12-09 02:25:24 +00001216static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1217 const fd_set *fds,
1218 int n)
bellard31e31b82003-02-18 22:55:36 +00001219{
bellard31e31b82003-02-18 22:55:36 +00001220 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001221 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001222 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001223
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001224 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001225 if (!(target_fds = lock_user(VERIFY_WRITE,
1226 target_fds_addr,
1227 sizeof(abi_ulong) * nw,
1228 0)))
1229 return -TARGET_EFAULT;
1230
1231 k = 0;
1232 for (i = 0; i < nw; i++) {
1233 v = 0;
1234 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001235 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001236 k++;
bellard31e31b82003-02-18 22:55:36 +00001237 }
ths26edcf42007-12-09 02:25:24 +00001238 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001239 }
ths26edcf42007-12-09 02:25:24 +00001240
1241 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1242
1243 return 0;
bellard31e31b82003-02-18 22:55:36 +00001244}
1245
bellardc596ed12003-07-13 17:32:31 +00001246#if defined(__alpha__)
1247#define HOST_HZ 1024
1248#else
1249#define HOST_HZ 100
1250#endif
1251
blueswir1992f48a2007-10-14 16:27:31 +00001252static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001253{
1254#if HOST_HZ == TARGET_HZ
1255 return ticks;
1256#else
1257 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1258#endif
1259}
1260
bellard579a97f2007-11-11 14:26:47 +00001261static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1262 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001263{
pbrook53a59602006-03-25 19:31:22 +00001264 struct target_rusage *target_rusage;
1265
bellard579a97f2007-11-11 14:26:47 +00001266 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1267 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001268 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1269 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1270 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1271 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1272 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1273 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1274 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1275 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1276 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1277 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1278 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1279 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1280 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1281 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1282 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1283 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1284 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1285 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001286 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001287
1288 return 0;
bellardb4091862003-05-16 15:39:34 +00001289}
1290
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001291static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001292{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001293 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001294 rlim_t result;
1295
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001296 target_rlim_swap = tswapal(target_rlim);
1297 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1298 return RLIM_INFINITY;
1299
1300 result = target_rlim_swap;
1301 if (target_rlim_swap != (rlim_t)result)
1302 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001303
1304 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001305}
1306
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001307static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001308{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001309 abi_ulong target_rlim_swap;
1310 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001311
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001312 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001313 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001314 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001315 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001316 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001317
1318 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001319}
1320
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001321static inline int target_to_host_resource(int code)
1322{
1323 switch (code) {
1324 case TARGET_RLIMIT_AS:
1325 return RLIMIT_AS;
1326 case TARGET_RLIMIT_CORE:
1327 return RLIMIT_CORE;
1328 case TARGET_RLIMIT_CPU:
1329 return RLIMIT_CPU;
1330 case TARGET_RLIMIT_DATA:
1331 return RLIMIT_DATA;
1332 case TARGET_RLIMIT_FSIZE:
1333 return RLIMIT_FSIZE;
1334 case TARGET_RLIMIT_LOCKS:
1335 return RLIMIT_LOCKS;
1336 case TARGET_RLIMIT_MEMLOCK:
1337 return RLIMIT_MEMLOCK;
1338 case TARGET_RLIMIT_MSGQUEUE:
1339 return RLIMIT_MSGQUEUE;
1340 case TARGET_RLIMIT_NICE:
1341 return RLIMIT_NICE;
1342 case TARGET_RLIMIT_NOFILE:
1343 return RLIMIT_NOFILE;
1344 case TARGET_RLIMIT_NPROC:
1345 return RLIMIT_NPROC;
1346 case TARGET_RLIMIT_RSS:
1347 return RLIMIT_RSS;
1348 case TARGET_RLIMIT_RTPRIO:
1349 return RLIMIT_RTPRIO;
1350 case TARGET_RLIMIT_SIGPENDING:
1351 return RLIMIT_SIGPENDING;
1352 case TARGET_RLIMIT_STACK:
1353 return RLIMIT_STACK;
1354 default:
1355 return code;
1356 }
1357}
1358
ths788f5ec2007-12-09 02:37:05 +00001359static inline abi_long copy_from_user_timeval(struct timeval *tv,
1360 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001361{
pbrook53a59602006-03-25 19:31:22 +00001362 struct target_timeval *target_tv;
1363
ths788f5ec2007-12-09 02:37:05 +00001364 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001365 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001366
1367 __get_user(tv->tv_sec, &target_tv->tv_sec);
1368 __get_user(tv->tv_usec, &target_tv->tv_usec);
1369
1370 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001371
1372 return 0;
bellard31e31b82003-02-18 22:55:36 +00001373}
1374
ths788f5ec2007-12-09 02:37:05 +00001375static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1376 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001377{
pbrook53a59602006-03-25 19:31:22 +00001378 struct target_timeval *target_tv;
1379
ths788f5ec2007-12-09 02:37:05 +00001380 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001381 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001382
1383 __put_user(tv->tv_sec, &target_tv->tv_sec);
1384 __put_user(tv->tv_usec, &target_tv->tv_usec);
1385
1386 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001387
1388 return 0;
bellard31e31b82003-02-18 22:55:36 +00001389}
1390
Paul Burtonef4467e2014-06-22 11:25:40 +01001391static inline abi_long copy_from_user_timezone(struct timezone *tz,
1392 abi_ulong target_tz_addr)
1393{
1394 struct target_timezone *target_tz;
1395
1396 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1397 return -TARGET_EFAULT;
1398 }
1399
1400 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1401 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1402
1403 unlock_user_struct(target_tz, target_tz_addr, 0);
1404
1405 return 0;
1406}
1407
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001408#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1409#include <mqueue.h>
1410
aurel3224e10032009-04-15 16:11:43 +00001411static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1412 abi_ulong target_mq_attr_addr)
1413{
1414 struct target_mq_attr *target_mq_attr;
1415
1416 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1417 target_mq_attr_addr, 1))
1418 return -TARGET_EFAULT;
1419
1420 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1421 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1422 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1423 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1424
1425 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1426
1427 return 0;
1428}
1429
1430static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1431 const struct mq_attr *attr)
1432{
1433 struct target_mq_attr *target_mq_attr;
1434
1435 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1436 target_mq_attr_addr, 0))
1437 return -TARGET_EFAULT;
1438
1439 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1440 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1441 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1442 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1443
1444 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1445
1446 return 0;
1447}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001448#endif
bellard31e31b82003-02-18 22:55:36 +00001449
Mike Frysinger055e0902011-06-03 17:01:49 -04001450#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001451/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001452static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001453 abi_ulong rfd_addr, abi_ulong wfd_addr,
1454 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001455{
1456 fd_set rfds, wfds, efds;
1457 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001458 struct timeval tv;
1459 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001460 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001461
Mike Frysinger055e0902011-06-03 17:01:49 -04001462 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1463 if (ret) {
1464 return ret;
pbrook53a59602006-03-25 19:31:22 +00001465 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001466 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1467 if (ret) {
1468 return ret;
pbrook53a59602006-03-25 19:31:22 +00001469 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001470 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1471 if (ret) {
1472 return ret;
pbrook53a59602006-03-25 19:31:22 +00001473 }
ths3b46e622007-09-17 08:09:54 +00001474
ths26edcf42007-12-09 02:25:24 +00001475 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001476 if (copy_from_user_timeval(&tv, target_tv_addr))
1477 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001478 ts.tv_sec = tv.tv_sec;
1479 ts.tv_nsec = tv.tv_usec * 1000;
1480 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001481 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001482 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001483 }
ths26edcf42007-12-09 02:25:24 +00001484
Peter Maydell6df9d382016-05-12 18:47:51 +01001485 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1486 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001487
ths26edcf42007-12-09 02:25:24 +00001488 if (!is_error(ret)) {
1489 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1490 return -TARGET_EFAULT;
1491 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1492 return -TARGET_EFAULT;
1493 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1494 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001495
Peter Maydell6df9d382016-05-12 18:47:51 +01001496 if (target_tv_addr) {
1497 tv.tv_sec = ts.tv_sec;
1498 tv.tv_usec = ts.tv_nsec / 1000;
1499 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1500 return -TARGET_EFAULT;
1501 }
1502 }
bellard31e31b82003-02-18 22:55:36 +00001503 }
bellard579a97f2007-11-11 14:26:47 +00001504
bellard31e31b82003-02-18 22:55:36 +00001505 return ret;
1506}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001507
1508#if defined(TARGET_WANT_OLD_SYS_SELECT)
1509static abi_long do_old_select(abi_ulong arg1)
1510{
1511 struct target_sel_arg_struct *sel;
1512 abi_ulong inp, outp, exp, tvp;
1513 long nsel;
1514
1515 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1516 return -TARGET_EFAULT;
1517 }
1518
1519 nsel = tswapal(sel->n);
1520 inp = tswapal(sel->inp);
1521 outp = tswapal(sel->outp);
1522 exp = tswapal(sel->exp);
1523 tvp = tswapal(sel->tvp);
1524
1525 unlock_user_struct(sel, arg1, 0);
1526
1527 return do_select(nsel, inp, outp, exp, tvp);
1528}
1529#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001530#endif
bellard31e31b82003-02-18 22:55:36 +00001531
Riku Voipio099d6b02009-05-05 12:10:04 +03001532static abi_long do_pipe2(int host_pipe[], int flags)
1533{
1534#ifdef CONFIG_PIPE2
1535 return pipe2(host_pipe, flags);
1536#else
1537 return -ENOSYS;
1538#endif
1539}
1540
Richard Hendersonfb41a662010-05-03 10:07:52 -07001541static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1542 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001543{
1544 int host_pipe[2];
1545 abi_long ret;
1546 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1547
1548 if (is_error(ret))
1549 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001550
1551 /* Several targets have special calling conventions for the original
1552 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1553 if (!is_pipe2) {
1554#if defined(TARGET_ALPHA)
1555 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1556 return host_pipe[0];
1557#elif defined(TARGET_MIPS)
1558 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1559 return host_pipe[0];
1560#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001561 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001562 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001563#elif defined(TARGET_SPARC)
1564 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1565 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001566#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001567 }
1568
Riku Voipio099d6b02009-05-05 12:10:04 +03001569 if (put_user_s32(host_pipe[0], pipedes)
1570 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1571 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001572 return get_errno(ret);
1573}
1574
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001575static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1576 abi_ulong target_addr,
1577 socklen_t len)
1578{
1579 struct target_ip_mreqn *target_smreqn;
1580
1581 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1582 if (!target_smreqn)
1583 return -TARGET_EFAULT;
1584 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1585 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1586 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001587 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001588 unlock_user(target_smreqn, target_addr, 0);
1589
1590 return 0;
1591}
1592
Laurent Vivier7b36f782015-10-28 21:40:44 +01001593static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001594 abi_ulong target_addr,
1595 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001596{
aurel32607175e2009-04-15 16:11:59 +00001597 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1598 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001599 struct target_sockaddr *target_saddr;
1600
Laurent Vivier7b36f782015-10-28 21:40:44 +01001601 if (fd_trans_target_to_host_addr(fd)) {
1602 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1603 }
1604
bellard579a97f2007-11-11 14:26:47 +00001605 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1606 if (!target_saddr)
1607 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001608
1609 sa_family = tswap16(target_saddr->sa_family);
1610
1611 /* Oops. The caller might send a incomplete sun_path; sun_path
1612 * must be terminated by \0 (see the manual page), but
1613 * unfortunately it is quite common to specify sockaddr_un
1614 * length as "strlen(x->sun_path)" while it should be
1615 * "strlen(...) + 1". We'll fix that here if needed.
1616 * Linux kernel has a similar feature.
1617 */
1618
1619 if (sa_family == AF_UNIX) {
1620 if (len < unix_maxlen && len > 0) {
1621 char *cp = (char*)target_saddr;
1622
1623 if ( cp[len-1] && !cp[len] )
1624 len++;
1625 }
1626 if (len > unix_maxlen)
1627 len = unix_maxlen;
1628 }
1629
pbrook53a59602006-03-25 19:31:22 +00001630 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001631 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001632 if (sa_family == AF_NETLINK) {
1633 struct sockaddr_nl *nladdr;
1634
1635 nladdr = (struct sockaddr_nl *)addr;
1636 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1637 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1638 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001639 struct target_sockaddr_ll *lladdr;
1640
1641 lladdr = (struct target_sockaddr_ll *)addr;
1642 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1643 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1644 }
pbrook53a59602006-03-25 19:31:22 +00001645 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001646
1647 return 0;
bellard7854b052003-03-29 17:22:23 +00001648}
1649
bellard579a97f2007-11-11 14:26:47 +00001650static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1651 struct sockaddr *addr,
1652 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001653{
pbrook53a59602006-03-25 19:31:22 +00001654 struct target_sockaddr *target_saddr;
1655
Peter Maydella1e22192016-07-07 15:44:43 +01001656 if (len == 0) {
1657 return 0;
1658 }
Philippe Mathieu-Daudé68607102017-07-26 23:42:18 -03001659 assert(addr);
Peter Maydella1e22192016-07-07 15:44:43 +01001660
bellard579a97f2007-11-11 14:26:47 +00001661 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1662 if (!target_saddr)
1663 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001664 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001665 if (len >= offsetof(struct target_sockaddr, sa_family) +
1666 sizeof(target_saddr->sa_family)) {
1667 target_saddr->sa_family = tswap16(addr->sa_family);
1668 }
1669 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001670 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1671 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1672 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001673 } else if (addr->sa_family == AF_PACKET) {
1674 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1675 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1676 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001677 } else if (addr->sa_family == AF_INET6 &&
1678 len >= sizeof(struct target_sockaddr_in6)) {
1679 struct target_sockaddr_in6 *target_in6 =
1680 (struct target_sockaddr_in6 *)target_saddr;
1681 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001682 }
pbrook53a59602006-03-25 19:31:22 +00001683 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001684
1685 return 0;
bellard7854b052003-03-29 17:22:23 +00001686}
1687
bellard5a4a8982007-11-11 17:39:18 +00001688static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1689 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001690{
1691 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001692 abi_long msg_controllen;
1693 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001694 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001695 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001696
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001697 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001698 if (msg_controllen < sizeof (struct target_cmsghdr))
1699 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001700 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001701 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001702 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001703 if (!target_cmsg)
1704 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001705
1706 while (cmsg && target_cmsg) {
1707 void *data = CMSG_DATA(cmsg);
1708 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1709
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001710 int len = tswapal(target_cmsg->cmsg_len)
Peter Maydellad762b92017-12-15 13:52:56 +00001711 - sizeof(struct target_cmsghdr);
bellard7854b052003-03-29 17:22:23 +00001712
1713 space += CMSG_SPACE(len);
1714 if (space > msgh->msg_controllen) {
1715 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001716 /* This is a QEMU bug, since we allocated the payload
1717 * area ourselves (unlike overflow in host-to-target
1718 * conversion, which is just the guest giving us a buffer
1719 * that's too small). It can't happen for the payload types
1720 * we currently support; if it becomes an issue in future
1721 * we would need to improve our allocation strategy to
1722 * something more intelligent than "twice the size of the
1723 * target buffer we're reading from".
1724 */
bellard31febb72005-12-18 20:03:27 +00001725 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001726 break;
1727 }
1728
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001729 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1730 cmsg->cmsg_level = SOL_SOCKET;
1731 } else {
1732 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1733 }
bellard7854b052003-03-29 17:22:23 +00001734 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1735 cmsg->cmsg_len = CMSG_LEN(len);
1736
Alex Suykov30b8b682014-12-23 07:52:58 +02001737 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001738 int *fd = (int *)data;
1739 int *target_fd = (int *)target_data;
1740 int i, numfds = len / sizeof(int);
1741
Peter Maydell876e23c2015-05-26 19:46:32 +01001742 for (i = 0; i < numfds; i++) {
1743 __get_user(fd[i], target_fd + i);
1744 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001745 } else if (cmsg->cmsg_level == SOL_SOCKET
1746 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1747 struct ucred *cred = (struct ucred *)data;
1748 struct target_ucred *target_cred =
1749 (struct target_ucred *)target_data;
1750
Peter Maydell876e23c2015-05-26 19:46:32 +01001751 __get_user(cred->pid, &target_cred->pid);
1752 __get_user(cred->uid, &target_cred->uid);
1753 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001754 } else {
1755 gemu_log("Unsupported ancillary data: %d/%d\n",
1756 cmsg->cmsg_level, cmsg->cmsg_type);
1757 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001758 }
1759
1760 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001761 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1762 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001763 }
bellard5a4a8982007-11-11 17:39:18 +00001764 unlock_user(target_cmsg, target_cmsg_addr, 0);
1765 the_end:
bellard7854b052003-03-29 17:22:23 +00001766 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001767 return 0;
bellard7854b052003-03-29 17:22:23 +00001768}
1769
bellard5a4a8982007-11-11 17:39:18 +00001770static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1771 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001772{
1773 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001774 abi_long msg_controllen;
1775 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001776 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001777 socklen_t space = 0;
1778
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001779 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001780 if (msg_controllen < sizeof (struct target_cmsghdr))
1781 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001782 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001783 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001784 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001785 if (!target_cmsg)
1786 return -TARGET_EFAULT;
1787
bellard7854b052003-03-29 17:22:23 +00001788 while (cmsg && target_cmsg) {
1789 void *data = CMSG_DATA(cmsg);
1790 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1791
Peter Maydellad762b92017-12-15 13:52:56 +00001792 int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001793 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001794
Peter Maydellc2aeb252015-05-26 19:46:31 +01001795 /* We never copy a half-header but may copy half-data;
1796 * this is Linux's behaviour in put_cmsg(). Note that
1797 * truncation here is a guest problem (which we report
1798 * to the guest via the CTRUNC bit), unlike truncation
1799 * in target_to_host_cmsg, which is a QEMU bug.
1800 */
Peter Maydell71749702017-12-15 13:52:55 +00001801 if (msg_controllen < sizeof(struct target_cmsghdr)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001802 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001803 break;
1804 }
1805
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001806 if (cmsg->cmsg_level == SOL_SOCKET) {
1807 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1808 } else {
1809 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1810 }
bellard7854b052003-03-29 17:22:23 +00001811 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001812
Peter Maydellc2aeb252015-05-26 19:46:31 +01001813 /* Payload types which need a different size of payload on
1814 * the target must adjust tgt_len here.
1815 */
1816 switch (cmsg->cmsg_level) {
1817 case SOL_SOCKET:
1818 switch (cmsg->cmsg_type) {
1819 case SO_TIMESTAMP:
1820 tgt_len = sizeof(struct target_timeval);
1821 break;
1822 default:
1823 break;
1824 }
1825 default:
Peter Maydell71749702017-12-15 13:52:55 +00001826 tgt_len = len;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001827 break;
1828 }
1829
Peter Maydell71749702017-12-15 13:52:55 +00001830 if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
Peter Maydellc2aeb252015-05-26 19:46:31 +01001831 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
Peter Maydell71749702017-12-15 13:52:55 +00001832 tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001833 }
1834
1835 /* We must now copy-and-convert len bytes of payload
1836 * into tgt_len bytes of destination space. Bear in mind
1837 * that in both source and destination we may be dealing
1838 * with a truncated value!
1839 */
Huw Davies52b65492014-04-17 14:02:47 +01001840 switch (cmsg->cmsg_level) {
1841 case SOL_SOCKET:
1842 switch (cmsg->cmsg_type) {
1843 case SCM_RIGHTS:
1844 {
1845 int *fd = (int *)data;
1846 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001847 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001848
Peter Maydell876e23c2015-05-26 19:46:32 +01001849 for (i = 0; i < numfds; i++) {
1850 __put_user(fd[i], target_fd + i);
1851 }
Huw Davies52b65492014-04-17 14:02:47 +01001852 break;
1853 }
1854 case SO_TIMESTAMP:
1855 {
1856 struct timeval *tv = (struct timeval *)data;
1857 struct target_timeval *target_tv =
1858 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001859
Peter Maydellc2aeb252015-05-26 19:46:31 +01001860 if (len != sizeof(struct timeval) ||
1861 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001862 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001863 }
Huw Davies52b65492014-04-17 14:02:47 +01001864
1865 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001866 __put_user(tv->tv_sec, &target_tv->tv_sec);
1867 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001868 break;
1869 }
Huw Davies4bc29752014-04-17 14:02:48 +01001870 case SCM_CREDENTIALS:
1871 {
1872 struct ucred *cred = (struct ucred *)data;
1873 struct target_ucred *target_cred =
1874 (struct target_ucred *)target_data;
1875
1876 __put_user(cred->pid, &target_cred->pid);
1877 __put_user(cred->uid, &target_cred->uid);
1878 __put_user(cred->gid, &target_cred->gid);
1879 break;
1880 }
Huw Davies52b65492014-04-17 14:02:47 +01001881 default:
1882 goto unimplemented;
1883 }
1884 break;
1885
Helge Delleree1ac3a2017-02-18 23:31:30 +01001886 case SOL_IP:
1887 switch (cmsg->cmsg_type) {
1888 case IP_TTL:
1889 {
1890 uint32_t *v = (uint32_t *)data;
1891 uint32_t *t_int = (uint32_t *)target_data;
1892
Peter Maydell71749702017-12-15 13:52:55 +00001893 if (len != sizeof(uint32_t) ||
1894 tgt_len != sizeof(uint32_t)) {
1895 goto unimplemented;
1896 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001897 __put_user(*v, t_int);
1898 break;
1899 }
1900 case IP_RECVERR:
1901 {
1902 struct errhdr_t {
1903 struct sock_extended_err ee;
1904 struct sockaddr_in offender;
1905 };
1906 struct errhdr_t *errh = (struct errhdr_t *)data;
1907 struct errhdr_t *target_errh =
1908 (struct errhdr_t *)target_data;
1909
Peter Maydell71749702017-12-15 13:52:55 +00001910 if (len != sizeof(struct errhdr_t) ||
1911 tgt_len != sizeof(struct errhdr_t)) {
1912 goto unimplemented;
1913 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001914 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1915 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1916 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1917 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1918 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1919 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1920 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1921 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1922 (void *) &errh->offender, sizeof(errh->offender));
1923 break;
1924 }
1925 default:
1926 goto unimplemented;
1927 }
1928 break;
1929
1930 case SOL_IPV6:
1931 switch (cmsg->cmsg_type) {
1932 case IPV6_HOPLIMIT:
1933 {
1934 uint32_t *v = (uint32_t *)data;
1935 uint32_t *t_int = (uint32_t *)target_data;
1936
Peter Maydell71749702017-12-15 13:52:55 +00001937 if (len != sizeof(uint32_t) ||
1938 tgt_len != sizeof(uint32_t)) {
1939 goto unimplemented;
1940 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001941 __put_user(*v, t_int);
1942 break;
1943 }
1944 case IPV6_RECVERR:
1945 {
1946 struct errhdr6_t {
1947 struct sock_extended_err ee;
1948 struct sockaddr_in6 offender;
1949 };
1950 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1951 struct errhdr6_t *target_errh =
1952 (struct errhdr6_t *)target_data;
1953
Peter Maydell71749702017-12-15 13:52:55 +00001954 if (len != sizeof(struct errhdr6_t) ||
1955 tgt_len != sizeof(struct errhdr6_t)) {
1956 goto unimplemented;
1957 }
Helge Delleree1ac3a2017-02-18 23:31:30 +01001958 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1959 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1960 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1961 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1962 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1963 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1964 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1965 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1966 (void *) &errh->offender, sizeof(errh->offender));
1967 break;
1968 }
1969 default:
1970 goto unimplemented;
1971 }
1972 break;
1973
Huw Davies52b65492014-04-17 14:02:47 +01001974 default:
1975 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001976 gemu_log("Unsupported ancillary data: %d/%d\n",
1977 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001978 memcpy(target_data, data, MIN(len, tgt_len));
1979 if (tgt_len > len) {
1980 memset(target_data + len, 0, tgt_len - len);
1981 }
bellard7854b052003-03-29 17:22:23 +00001982 }
1983
Peter Maydell71749702017-12-15 13:52:55 +00001984 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
1985 tgt_space = TARGET_CMSG_SPACE(tgt_len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001986 if (msg_controllen < tgt_space) {
1987 tgt_space = msg_controllen;
1988 }
1989 msg_controllen -= tgt_space;
1990 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001991 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001992 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1993 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001994 }
bellard5a4a8982007-11-11 17:39:18 +00001995 unlock_user(target_cmsg, target_cmsg_addr, space);
1996 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001997 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001998 return 0;
bellard7854b052003-03-29 17:22:23 +00001999}
2000
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002001static void tswap_nlmsghdr(struct nlmsghdr *nlh)
2002{
2003 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
2004 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
2005 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
2006 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
2007 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
2008}
2009
2010static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
2011 size_t len,
2012 abi_long (*host_to_target_nlmsg)
2013 (struct nlmsghdr *))
2014{
2015 uint32_t nlmsg_len;
2016 abi_long ret;
2017
2018 while (len > sizeof(struct nlmsghdr)) {
2019
2020 nlmsg_len = nlh->nlmsg_len;
2021 if (nlmsg_len < sizeof(struct nlmsghdr) ||
2022 nlmsg_len > len) {
2023 break;
2024 }
2025
2026 switch (nlh->nlmsg_type) {
2027 case NLMSG_DONE:
2028 tswap_nlmsghdr(nlh);
2029 return 0;
2030 case NLMSG_NOOP:
2031 break;
2032 case NLMSG_ERROR:
2033 {
2034 struct nlmsgerr *e = NLMSG_DATA(nlh);
2035 e->error = tswap32(e->error);
2036 tswap_nlmsghdr(&e->msg);
2037 tswap_nlmsghdr(nlh);
2038 return 0;
2039 }
2040 default:
2041 ret = host_to_target_nlmsg(nlh);
2042 if (ret < 0) {
2043 tswap_nlmsghdr(nlh);
2044 return ret;
2045 }
2046 break;
2047 }
2048 tswap_nlmsghdr(nlh);
2049 len -= NLMSG_ALIGN(nlmsg_len);
2050 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
2051 }
2052 return 0;
2053}
2054
2055static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
2056 size_t len,
2057 abi_long (*target_to_host_nlmsg)
2058 (struct nlmsghdr *))
2059{
2060 int ret;
2061
2062 while (len > sizeof(struct nlmsghdr)) {
2063 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
2064 tswap32(nlh->nlmsg_len) > len) {
2065 break;
2066 }
2067 tswap_nlmsghdr(nlh);
2068 switch (nlh->nlmsg_type) {
2069 case NLMSG_DONE:
2070 return 0;
2071 case NLMSG_NOOP:
2072 break;
2073 case NLMSG_ERROR:
2074 {
2075 struct nlmsgerr *e = NLMSG_DATA(nlh);
2076 e->error = tswap32(e->error);
2077 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02002078 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002079 }
2080 default:
2081 ret = target_to_host_nlmsg(nlh);
2082 if (ret < 0) {
2083 return ret;
2084 }
2085 }
2086 len -= NLMSG_ALIGN(nlh->nlmsg_len);
2087 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
2088 }
2089 return 0;
2090}
2091
Laurent Vivier575b22b2016-06-02 22:14:15 +02002092#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02002093static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
2094 size_t len, void *context,
2095 abi_long (*host_to_target_nlattr)
2096 (struct nlattr *,
2097 void *context))
2098{
2099 unsigned short nla_len;
2100 abi_long ret;
2101
2102 while (len > sizeof(struct nlattr)) {
2103 nla_len = nlattr->nla_len;
2104 if (nla_len < sizeof(struct nlattr) ||
2105 nla_len > len) {
2106 break;
2107 }
2108 ret = host_to_target_nlattr(nlattr, context);
2109 nlattr->nla_len = tswap16(nlattr->nla_len);
2110 nlattr->nla_type = tswap16(nlattr->nla_type);
2111 if (ret < 0) {
2112 return ret;
2113 }
2114 len -= NLA_ALIGN(nla_len);
2115 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
2116 }
2117 return 0;
2118}
2119
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002120static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
2121 size_t len,
2122 abi_long (*host_to_target_rtattr)
2123 (struct rtattr *))
2124{
2125 unsigned short rta_len;
2126 abi_long ret;
2127
2128 while (len > sizeof(struct rtattr)) {
2129 rta_len = rtattr->rta_len;
2130 if (rta_len < sizeof(struct rtattr) ||
2131 rta_len > len) {
2132 break;
2133 }
2134 ret = host_to_target_rtattr(rtattr);
2135 rtattr->rta_len = tswap16(rtattr->rta_len);
2136 rtattr->rta_type = tswap16(rtattr->rta_type);
2137 if (ret < 0) {
2138 return ret;
2139 }
2140 len -= RTA_ALIGN(rta_len);
2141 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2142 }
2143 return 0;
2144}
2145
Laurent Vivierc5dff282016-06-27 18:54:30 +02002146#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2147
2148static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2149 void *context)
2150{
2151 uint16_t *u16;
2152 uint32_t *u32;
2153 uint64_t *u64;
2154
2155 switch (nlattr->nla_type) {
2156 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002157 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002158 break;
2159 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002160 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002161 break;
2162 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002163 case QEMU_IFLA_BR_VLAN_FILTERING:
2164 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2165 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2166 case QEMU_IFLA_BR_MCAST_ROUTER:
2167 case QEMU_IFLA_BR_MCAST_SNOOPING:
2168 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2169 case QEMU_IFLA_BR_MCAST_QUERIER:
2170 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2171 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2172 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002173 break;
2174 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002175 case QEMU_IFLA_BR_PRIORITY:
2176 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2177 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2178 case QEMU_IFLA_BR_ROOT_PORT:
2179 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002180 u16 = NLA_DATA(nlattr);
2181 *u16 = tswap16(*u16);
2182 break;
2183 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002184 case QEMU_IFLA_BR_FORWARD_DELAY:
2185 case QEMU_IFLA_BR_HELLO_TIME:
2186 case QEMU_IFLA_BR_MAX_AGE:
2187 case QEMU_IFLA_BR_AGEING_TIME:
2188 case QEMU_IFLA_BR_STP_STATE:
2189 case QEMU_IFLA_BR_ROOT_PATH_COST:
2190 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2191 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2192 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2193 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002194 u32 = NLA_DATA(nlattr);
2195 *u32 = tswap32(*u32);
2196 break;
2197 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002198 case QEMU_IFLA_BR_HELLO_TIMER:
2199 case QEMU_IFLA_BR_TCN_TIMER:
2200 case QEMU_IFLA_BR_GC_TIMER:
2201 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2202 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2203 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2204 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2205 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2206 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2207 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002208 u64 = NLA_DATA(nlattr);
2209 *u64 = tswap64(*u64);
2210 break;
2211 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002212 case QEMU_IFLA_BR_ROOT_ID:
2213 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002214 break;
2215 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002216 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002217 break;
2218 }
2219 return 0;
2220}
2221
2222static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2223 void *context)
2224{
2225 uint16_t *u16;
2226 uint32_t *u32;
2227 uint64_t *u64;
2228
2229 switch (nlattr->nla_type) {
2230 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002231 case QEMU_IFLA_BRPORT_STATE:
2232 case QEMU_IFLA_BRPORT_MODE:
2233 case QEMU_IFLA_BRPORT_GUARD:
2234 case QEMU_IFLA_BRPORT_PROTECT:
2235 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2236 case QEMU_IFLA_BRPORT_LEARNING:
2237 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2238 case QEMU_IFLA_BRPORT_PROXYARP:
2239 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2240 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2241 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2242 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2243 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002244 break;
2245 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002246 case QEMU_IFLA_BRPORT_PRIORITY:
2247 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2248 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2249 case QEMU_IFLA_BRPORT_ID:
2250 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002251 u16 = NLA_DATA(nlattr);
2252 *u16 = tswap16(*u16);
2253 break;
2254 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002255 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002256 u32 = NLA_DATA(nlattr);
2257 *u32 = tswap32(*u32);
2258 break;
2259 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002260 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2261 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2262 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002263 u64 = NLA_DATA(nlattr);
2264 *u64 = tswap64(*u64);
2265 break;
2266 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002267 case QEMU_IFLA_BRPORT_ROOT_ID:
2268 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002269 break;
2270 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002271 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002272 break;
2273 }
2274 return 0;
2275}
2276
2277struct linkinfo_context {
2278 int len;
2279 char *name;
2280 int slave_len;
2281 char *slave_name;
2282};
2283
2284static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2285 void *context)
2286{
2287 struct linkinfo_context *li_context = context;
2288
2289 switch (nlattr->nla_type) {
2290 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002291 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002292 li_context->name = NLA_DATA(nlattr);
2293 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2294 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002295 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002296 li_context->slave_name = NLA_DATA(nlattr);
2297 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2298 break;
2299 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002300 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002301 /* FIXME: only used by CAN */
2302 break;
2303 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002304 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002305 if (strncmp(li_context->name, "bridge",
2306 li_context->len) == 0) {
2307 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2308 nlattr->nla_len,
2309 NULL,
2310 host_to_target_data_bridge_nlattr);
2311 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002312 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002313 }
2314 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002315 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002316 if (strncmp(li_context->slave_name, "bridge",
2317 li_context->slave_len) == 0) {
2318 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2319 nlattr->nla_len,
2320 NULL,
2321 host_to_target_slave_data_bridge_nlattr);
2322 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002323 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002324 li_context->slave_name);
2325 }
2326 break;
2327 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002328 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002329 break;
2330 }
2331
2332 return 0;
2333}
2334
2335static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2336 void *context)
2337{
2338 uint32_t *u32;
2339 int i;
2340
2341 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002342 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002343 u32 = NLA_DATA(nlattr);
2344 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2345 i++) {
2346 u32[i] = tswap32(u32[i]);
2347 }
2348 break;
2349 default:
2350 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2351 }
2352 return 0;
2353}
2354
2355static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2356 void *context)
2357{
2358 uint32_t *u32;
2359 uint64_t *u64;
2360 struct ifla_cacheinfo *ci;
2361 int i;
2362
2363 switch (nlattr->nla_type) {
2364 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002365 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002366 break;
2367 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002368 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002369 break;
2370 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002371 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002372 u32 = NLA_DATA(nlattr);
2373 *u32 = tswap32(*u32);
2374 break;
2375 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002376 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002377 u32 = NLA_DATA(nlattr);
2378 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2379 i++) {
2380 u32[i] = tswap32(u32[i]);
2381 }
2382 break;
2383 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002384 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002385 ci = NLA_DATA(nlattr);
2386 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2387 ci->tstamp = tswap32(ci->tstamp);
2388 ci->reachable_time = tswap32(ci->reachable_time);
2389 ci->retrans_time = tswap32(ci->retrans_time);
2390 break;
2391 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002392 case QEMU_IFLA_INET6_STATS:
2393 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002394 u64 = NLA_DATA(nlattr);
2395 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2396 i++) {
2397 u64[i] = tswap64(u64[i]);
2398 }
2399 break;
2400 default:
2401 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2402 }
2403 return 0;
2404}
2405
2406static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2407 void *context)
2408{
2409 switch (nlattr->nla_type) {
2410 case AF_INET:
2411 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2412 NULL,
2413 host_to_target_data_inet_nlattr);
2414 case AF_INET6:
2415 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2416 NULL,
2417 host_to_target_data_inet6_nlattr);
2418 default:
2419 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2420 break;
2421 }
2422 return 0;
2423}
2424
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002425static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2426{
2427 uint32_t *u32;
2428 struct rtnl_link_stats *st;
2429 struct rtnl_link_stats64 *st64;
2430 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002431 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002432
2433 switch (rtattr->rta_type) {
2434 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002435 case QEMU_IFLA_ADDRESS:
2436 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002437 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002438 case QEMU_IFLA_IFNAME:
2439 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002440 break;
2441 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002442 case QEMU_IFLA_OPERSTATE:
2443 case QEMU_IFLA_LINKMODE:
2444 case QEMU_IFLA_CARRIER:
2445 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002446 break;
2447 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002448 case QEMU_IFLA_MTU:
2449 case QEMU_IFLA_LINK:
2450 case QEMU_IFLA_WEIGHT:
2451 case QEMU_IFLA_TXQLEN:
2452 case QEMU_IFLA_CARRIER_CHANGES:
2453 case QEMU_IFLA_NUM_RX_QUEUES:
2454 case QEMU_IFLA_NUM_TX_QUEUES:
2455 case QEMU_IFLA_PROMISCUITY:
2456 case QEMU_IFLA_EXT_MASK:
2457 case QEMU_IFLA_LINK_NETNSID:
2458 case QEMU_IFLA_GROUP:
2459 case QEMU_IFLA_MASTER:
2460 case QEMU_IFLA_NUM_VF:
Laurent Viviera1488b82016-10-27 03:00:49 +02002461 case QEMU_IFLA_GSO_MAX_SEGS:
2462 case QEMU_IFLA_GSO_MAX_SIZE:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002463 u32 = RTA_DATA(rtattr);
2464 *u32 = tswap32(*u32);
2465 break;
2466 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002467 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002468 st = RTA_DATA(rtattr);
2469 st->rx_packets = tswap32(st->rx_packets);
2470 st->tx_packets = tswap32(st->tx_packets);
2471 st->rx_bytes = tswap32(st->rx_bytes);
2472 st->tx_bytes = tswap32(st->tx_bytes);
2473 st->rx_errors = tswap32(st->rx_errors);
2474 st->tx_errors = tswap32(st->tx_errors);
2475 st->rx_dropped = tswap32(st->rx_dropped);
2476 st->tx_dropped = tswap32(st->tx_dropped);
2477 st->multicast = tswap32(st->multicast);
2478 st->collisions = tswap32(st->collisions);
2479
2480 /* detailed rx_errors: */
2481 st->rx_length_errors = tswap32(st->rx_length_errors);
2482 st->rx_over_errors = tswap32(st->rx_over_errors);
2483 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2484 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2485 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2486 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2487
2488 /* detailed tx_errors */
2489 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2490 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2491 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2492 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2493 st->tx_window_errors = tswap32(st->tx_window_errors);
2494
2495 /* for cslip etc */
2496 st->rx_compressed = tswap32(st->rx_compressed);
2497 st->tx_compressed = tswap32(st->tx_compressed);
2498 break;
2499 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002500 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002501 st64 = RTA_DATA(rtattr);
2502 st64->rx_packets = tswap64(st64->rx_packets);
2503 st64->tx_packets = tswap64(st64->tx_packets);
2504 st64->rx_bytes = tswap64(st64->rx_bytes);
2505 st64->tx_bytes = tswap64(st64->tx_bytes);
2506 st64->rx_errors = tswap64(st64->rx_errors);
2507 st64->tx_errors = tswap64(st64->tx_errors);
2508 st64->rx_dropped = tswap64(st64->rx_dropped);
2509 st64->tx_dropped = tswap64(st64->tx_dropped);
2510 st64->multicast = tswap64(st64->multicast);
2511 st64->collisions = tswap64(st64->collisions);
2512
2513 /* detailed rx_errors: */
2514 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2515 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2516 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2517 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2518 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2519 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2520
2521 /* detailed tx_errors */
2522 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2523 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2524 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2525 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2526 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2527
2528 /* for cslip etc */
2529 st64->rx_compressed = tswap64(st64->rx_compressed);
2530 st64->tx_compressed = tswap64(st64->tx_compressed);
2531 break;
2532 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002533 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002534 map = RTA_DATA(rtattr);
2535 map->mem_start = tswap64(map->mem_start);
2536 map->mem_end = tswap64(map->mem_end);
2537 map->base_addr = tswap64(map->base_addr);
2538 map->irq = tswap16(map->irq);
2539 break;
2540 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002541 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002542 memset(&li_context, 0, sizeof(li_context));
2543 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2544 &li_context,
2545 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002546 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002547 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2548 NULL,
2549 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002550 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002551 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002552 break;
2553 }
2554 return 0;
2555}
2556
2557static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2558{
2559 uint32_t *u32;
2560 struct ifa_cacheinfo *ci;
2561
2562 switch (rtattr->rta_type) {
2563 /* binary: depends on family type */
2564 case IFA_ADDRESS:
2565 case IFA_LOCAL:
2566 break;
2567 /* string */
2568 case IFA_LABEL:
2569 break;
2570 /* u32 */
2571 case IFA_FLAGS:
2572 case IFA_BROADCAST:
2573 u32 = RTA_DATA(rtattr);
2574 *u32 = tswap32(*u32);
2575 break;
2576 /* struct ifa_cacheinfo */
2577 case IFA_CACHEINFO:
2578 ci = RTA_DATA(rtattr);
2579 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2580 ci->ifa_valid = tswap32(ci->ifa_valid);
2581 ci->cstamp = tswap32(ci->cstamp);
2582 ci->tstamp = tswap32(ci->tstamp);
2583 break;
2584 default:
2585 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2586 break;
2587 }
2588 return 0;
2589}
2590
2591static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2592{
2593 uint32_t *u32;
2594 switch (rtattr->rta_type) {
2595 /* binary: depends on family type */
2596 case RTA_GATEWAY:
2597 case RTA_DST:
2598 case RTA_PREFSRC:
2599 break;
2600 /* u32 */
2601 case RTA_PRIORITY:
2602 case RTA_TABLE:
2603 case RTA_OIF:
2604 u32 = RTA_DATA(rtattr);
2605 *u32 = tswap32(*u32);
2606 break;
2607 default:
2608 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2609 break;
2610 }
2611 return 0;
2612}
2613
2614static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2615 uint32_t rtattr_len)
2616{
2617 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2618 host_to_target_data_link_rtattr);
2619}
2620
2621static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2622 uint32_t rtattr_len)
2623{
2624 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2625 host_to_target_data_addr_rtattr);
2626}
2627
2628static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2629 uint32_t rtattr_len)
2630{
2631 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2632 host_to_target_data_route_rtattr);
2633}
2634
2635static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2636{
2637 uint32_t nlmsg_len;
2638 struct ifinfomsg *ifi;
2639 struct ifaddrmsg *ifa;
2640 struct rtmsg *rtm;
2641
2642 nlmsg_len = nlh->nlmsg_len;
2643 switch (nlh->nlmsg_type) {
2644 case RTM_NEWLINK:
2645 case RTM_DELLINK:
2646 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002647 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2648 ifi = NLMSG_DATA(nlh);
2649 ifi->ifi_type = tswap16(ifi->ifi_type);
2650 ifi->ifi_index = tswap32(ifi->ifi_index);
2651 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2652 ifi->ifi_change = tswap32(ifi->ifi_change);
2653 host_to_target_link_rtattr(IFLA_RTA(ifi),
2654 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2655 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002656 break;
2657 case RTM_NEWADDR:
2658 case RTM_DELADDR:
2659 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002660 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2661 ifa = NLMSG_DATA(nlh);
2662 ifa->ifa_index = tswap32(ifa->ifa_index);
2663 host_to_target_addr_rtattr(IFA_RTA(ifa),
2664 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2665 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002666 break;
2667 case RTM_NEWROUTE:
2668 case RTM_DELROUTE:
2669 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002670 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2671 rtm = NLMSG_DATA(nlh);
2672 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2673 host_to_target_route_rtattr(RTM_RTA(rtm),
2674 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2675 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002676 break;
2677 default:
2678 return -TARGET_EINVAL;
2679 }
2680 return 0;
2681}
2682
2683static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2684 size_t len)
2685{
2686 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2687}
2688
2689static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2690 size_t len,
2691 abi_long (*target_to_host_rtattr)
2692 (struct rtattr *))
2693{
2694 abi_long ret;
2695
2696 while (len >= sizeof(struct rtattr)) {
2697 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2698 tswap16(rtattr->rta_len) > len) {
2699 break;
2700 }
2701 rtattr->rta_len = tswap16(rtattr->rta_len);
2702 rtattr->rta_type = tswap16(rtattr->rta_type);
2703 ret = target_to_host_rtattr(rtattr);
2704 if (ret < 0) {
2705 return ret;
2706 }
2707 len -= RTA_ALIGN(rtattr->rta_len);
2708 rtattr = (struct rtattr *)(((char *)rtattr) +
2709 RTA_ALIGN(rtattr->rta_len));
2710 }
2711 return 0;
2712}
2713
2714static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2715{
2716 switch (rtattr->rta_type) {
2717 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002718 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002719 break;
2720 }
2721 return 0;
2722}
2723
2724static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2725{
2726 switch (rtattr->rta_type) {
2727 /* binary: depends on family type */
2728 case IFA_LOCAL:
2729 case IFA_ADDRESS:
2730 break;
2731 default:
2732 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2733 break;
2734 }
2735 return 0;
2736}
2737
2738static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2739{
2740 uint32_t *u32;
2741 switch (rtattr->rta_type) {
2742 /* binary: depends on family type */
2743 case RTA_DST:
2744 case RTA_SRC:
2745 case RTA_GATEWAY:
2746 break;
2747 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002748 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002749 case RTA_OIF:
2750 u32 = RTA_DATA(rtattr);
2751 *u32 = tswap32(*u32);
2752 break;
2753 default:
2754 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2755 break;
2756 }
2757 return 0;
2758}
2759
2760static void target_to_host_link_rtattr(struct rtattr *rtattr,
2761 uint32_t rtattr_len)
2762{
2763 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2764 target_to_host_data_link_rtattr);
2765}
2766
2767static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2768 uint32_t rtattr_len)
2769{
2770 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2771 target_to_host_data_addr_rtattr);
2772}
2773
2774static void target_to_host_route_rtattr(struct rtattr *rtattr,
2775 uint32_t rtattr_len)
2776{
2777 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2778 target_to_host_data_route_rtattr);
2779}
2780
2781static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2782{
2783 struct ifinfomsg *ifi;
2784 struct ifaddrmsg *ifa;
2785 struct rtmsg *rtm;
2786
2787 switch (nlh->nlmsg_type) {
2788 case RTM_GETLINK:
2789 break;
2790 case RTM_NEWLINK:
2791 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002792 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2793 ifi = NLMSG_DATA(nlh);
2794 ifi->ifi_type = tswap16(ifi->ifi_type);
2795 ifi->ifi_index = tswap32(ifi->ifi_index);
2796 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2797 ifi->ifi_change = tswap32(ifi->ifi_change);
2798 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2799 NLMSG_LENGTH(sizeof(*ifi)));
2800 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002801 break;
2802 case RTM_GETADDR:
2803 case RTM_NEWADDR:
2804 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002805 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2806 ifa = NLMSG_DATA(nlh);
2807 ifa->ifa_index = tswap32(ifa->ifa_index);
2808 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2809 NLMSG_LENGTH(sizeof(*ifa)));
2810 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002811 break;
2812 case RTM_GETROUTE:
2813 break;
2814 case RTM_NEWROUTE:
2815 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002816 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2817 rtm = NLMSG_DATA(nlh);
2818 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2819 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2820 NLMSG_LENGTH(sizeof(*rtm)));
2821 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002822 break;
2823 default:
2824 return -TARGET_EOPNOTSUPP;
2825 }
2826 return 0;
2827}
2828
2829static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2830{
2831 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2832}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002833#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002834
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002835static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2836{
2837 switch (nlh->nlmsg_type) {
2838 default:
2839 gemu_log("Unknown host audit message type %d\n",
2840 nlh->nlmsg_type);
2841 return -TARGET_EINVAL;
2842 }
2843 return 0;
2844}
2845
2846static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2847 size_t len)
2848{
2849 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2850}
2851
2852static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2853{
2854 switch (nlh->nlmsg_type) {
2855 case AUDIT_USER:
2856 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2857 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2858 break;
2859 default:
2860 gemu_log("Unknown target audit message type %d\n",
2861 nlh->nlmsg_type);
2862 return -TARGET_EINVAL;
2863 }
2864
2865 return 0;
2866}
2867
2868static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2869{
2870 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2871}
2872
ths0da46a62007-10-20 20:23:07 +00002873/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002874static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002875 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002876{
blueswir1992f48a2007-10-14 16:27:31 +00002877 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002878 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002879 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002880 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002881
bellard8853f862004-02-22 14:57:26 +00002882 switch(level) {
2883 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002884 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002885 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002886 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002887
bellard2f619692007-11-16 10:46:05 +00002888 if (get_user_u32(val, optval_addr))
2889 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002890 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2891 break;
2892 case SOL_IP:
2893 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002894 case IP_TOS:
2895 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002896 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002897 case IP_ROUTER_ALERT:
2898 case IP_RECVOPTS:
2899 case IP_RETOPTS:
2900 case IP_PKTINFO:
2901 case IP_MTU_DISCOVER:
2902 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002903 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002904 case IP_RECVTOS:
2905#ifdef IP_FREEBIND
2906 case IP_FREEBIND:
2907#endif
2908 case IP_MULTICAST_TTL:
2909 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002910 val = 0;
2911 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002912 if (get_user_u32(val, optval_addr))
2913 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002914 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002915 if (get_user_u8(val, optval_addr))
2916 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002917 }
2918 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2919 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002920 case IP_ADD_MEMBERSHIP:
2921 case IP_DROP_MEMBERSHIP:
2922 if (optlen < sizeof (struct target_ip_mreq) ||
2923 optlen > sizeof (struct target_ip_mreqn))
2924 return -TARGET_EINVAL;
2925
2926 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2927 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2928 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2929 break;
2930
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002931 case IP_BLOCK_SOURCE:
2932 case IP_UNBLOCK_SOURCE:
2933 case IP_ADD_SOURCE_MEMBERSHIP:
2934 case IP_DROP_SOURCE_MEMBERSHIP:
2935 if (optlen != sizeof (struct target_ip_mreq_source))
2936 return -TARGET_EINVAL;
2937
2938 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2939 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2940 unlock_user (ip_mreq_source, optval_addr, 0);
2941 break;
2942
bellard8853f862004-02-22 14:57:26 +00002943 default:
2944 goto unimplemented;
2945 }
2946 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002947 case SOL_IPV6:
2948 switch (optname) {
2949 case IPV6_MTU_DISCOVER:
2950 case IPV6_MTU:
2951 case IPV6_V6ONLY:
2952 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002953 case IPV6_UNICAST_HOPS:
2954 case IPV6_RECVERR:
2955 case IPV6_RECVHOPLIMIT:
2956 case IPV6_2292HOPLIMIT:
2957 case IPV6_CHECKSUM:
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002958 val = 0;
2959 if (optlen < sizeof(uint32_t)) {
2960 return -TARGET_EINVAL;
2961 }
2962 if (get_user_u32(val, optval_addr)) {
2963 return -TARGET_EFAULT;
2964 }
2965 ret = get_errno(setsockopt(sockfd, level, optname,
2966 &val, sizeof(val)));
2967 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002968 case IPV6_PKTINFO:
2969 {
2970 struct in6_pktinfo pki;
2971
2972 if (optlen < sizeof(pki)) {
2973 return -TARGET_EINVAL;
2974 }
2975
2976 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2977 return -TARGET_EFAULT;
2978 }
2979
2980 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2981
2982 ret = get_errno(setsockopt(sockfd, level, optname,
2983 &pki, sizeof(pki)));
2984 break;
2985 }
2986 default:
2987 goto unimplemented;
2988 }
2989 break;
2990 case SOL_ICMPV6:
2991 switch (optname) {
2992 case ICMPV6_FILTER:
2993 {
2994 struct icmp6_filter icmp6f;
2995
2996 if (optlen > sizeof(icmp6f)) {
2997 optlen = sizeof(icmp6f);
2998 }
2999
3000 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
3001 return -TARGET_EFAULT;
3002 }
3003
3004 for (val = 0; val < 8; val++) {
3005 icmp6f.data[val] = tswap32(icmp6f.data[val]);
3006 }
3007
3008 ret = get_errno(setsockopt(sockfd, level, optname,
3009 &icmp6f, optlen));
3010 break;
3011 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02003012 default:
3013 goto unimplemented;
3014 }
3015 break;
Jing Huang920394d2012-07-24 13:59:23 +00003016 case SOL_RAW:
3017 switch (optname) {
3018 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01003019 case IPV6_CHECKSUM:
3020 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00003021 if (optlen < sizeof(uint32_t)) {
3022 return -TARGET_EINVAL;
3023 }
3024
3025 if (get_user_u32(val, optval_addr)) {
3026 return -TARGET_EFAULT;
3027 }
3028 ret = get_errno(setsockopt(sockfd, level, optname,
3029 &val, sizeof(val)));
3030 break;
3031
3032 default:
3033 goto unimplemented;
3034 }
3035 break;
bellard3532fa72006-06-24 15:06:03 +00003036 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00003037 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00003038 case TARGET_SO_RCVTIMEO:
3039 {
3040 struct timeval tv;
3041
3042 optname = SO_RCVTIMEO;
3043
3044set_timeout:
3045 if (optlen != sizeof(struct target_timeval)) {
3046 return -TARGET_EINVAL;
3047 }
3048
3049 if (copy_from_user_timeval(&tv, optval_addr)) {
3050 return -TARGET_EFAULT;
3051 }
3052
3053 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3054 &tv, sizeof(tv)));
3055 return ret;
3056 }
3057 case TARGET_SO_SNDTIMEO:
3058 optname = SO_SNDTIMEO;
3059 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02003060 case TARGET_SO_ATTACH_FILTER:
3061 {
3062 struct target_sock_fprog *tfprog;
3063 struct target_sock_filter *tfilter;
3064 struct sock_fprog fprog;
3065 struct sock_filter *filter;
3066 int i;
3067
3068 if (optlen != sizeof(*tfprog)) {
3069 return -TARGET_EINVAL;
3070 }
3071 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
3072 return -TARGET_EFAULT;
3073 }
3074 if (!lock_user_struct(VERIFY_READ, tfilter,
3075 tswapal(tfprog->filter), 0)) {
3076 unlock_user_struct(tfprog, optval_addr, 1);
3077 return -TARGET_EFAULT;
3078 }
3079
3080 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303081 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003082 if (filter == NULL) {
3083 unlock_user_struct(tfilter, tfprog->filter, 1);
3084 unlock_user_struct(tfprog, optval_addr, 1);
3085 return -TARGET_ENOMEM;
3086 }
3087 for (i = 0; i < fprog.len; i++) {
3088 filter[i].code = tswap16(tfilter[i].code);
3089 filter[i].jt = tfilter[i].jt;
3090 filter[i].jf = tfilter[i].jf;
3091 filter[i].k = tswap32(tfilter[i].k);
3092 }
3093 fprog.filter = filter;
3094
3095 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
3096 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303097 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003098
3099 unlock_user_struct(tfilter, tfprog->filter, 1);
3100 unlock_user_struct(tfprog, optval_addr, 1);
3101 return ret;
3102 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003103 case TARGET_SO_BINDTODEVICE:
3104 {
3105 char *dev_ifname, *addr_ifname;
3106
3107 if (optlen > IFNAMSIZ - 1) {
3108 optlen = IFNAMSIZ - 1;
3109 }
3110 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3111 if (!dev_ifname) {
3112 return -TARGET_EFAULT;
3113 }
3114 optname = SO_BINDTODEVICE;
3115 addr_ifname = alloca(IFNAMSIZ);
3116 memcpy(addr_ifname, dev_ifname, optlen);
3117 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08003118 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3119 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003120 unlock_user (dev_ifname, optval_addr, 0);
3121 return ret;
3122 }
bellard8853f862004-02-22 14:57:26 +00003123 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00003124 case TARGET_SO_DEBUG:
3125 optname = SO_DEBUG;
3126 break;
3127 case TARGET_SO_REUSEADDR:
3128 optname = SO_REUSEADDR;
3129 break;
3130 case TARGET_SO_TYPE:
3131 optname = SO_TYPE;
3132 break;
3133 case TARGET_SO_ERROR:
3134 optname = SO_ERROR;
3135 break;
3136 case TARGET_SO_DONTROUTE:
3137 optname = SO_DONTROUTE;
3138 break;
3139 case TARGET_SO_BROADCAST:
3140 optname = SO_BROADCAST;
3141 break;
3142 case TARGET_SO_SNDBUF:
3143 optname = SO_SNDBUF;
3144 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003145 case TARGET_SO_SNDBUFFORCE:
3146 optname = SO_SNDBUFFORCE;
3147 break;
bellard3532fa72006-06-24 15:06:03 +00003148 case TARGET_SO_RCVBUF:
3149 optname = SO_RCVBUF;
3150 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003151 case TARGET_SO_RCVBUFFORCE:
3152 optname = SO_RCVBUFFORCE;
3153 break;
bellard3532fa72006-06-24 15:06:03 +00003154 case TARGET_SO_KEEPALIVE:
3155 optname = SO_KEEPALIVE;
3156 break;
3157 case TARGET_SO_OOBINLINE:
3158 optname = SO_OOBINLINE;
3159 break;
3160 case TARGET_SO_NO_CHECK:
3161 optname = SO_NO_CHECK;
3162 break;
3163 case TARGET_SO_PRIORITY:
3164 optname = SO_PRIORITY;
3165 break;
bellard5e83e8e2005-03-01 22:32:06 +00003166#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00003167 case TARGET_SO_BSDCOMPAT:
3168 optname = SO_BSDCOMPAT;
3169 break;
bellard5e83e8e2005-03-01 22:32:06 +00003170#endif
bellard3532fa72006-06-24 15:06:03 +00003171 case TARGET_SO_PASSCRED:
3172 optname = SO_PASSCRED;
3173 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01003174 case TARGET_SO_PASSSEC:
3175 optname = SO_PASSSEC;
3176 break;
bellard3532fa72006-06-24 15:06:03 +00003177 case TARGET_SO_TIMESTAMP:
3178 optname = SO_TIMESTAMP;
3179 break;
3180 case TARGET_SO_RCVLOWAT:
3181 optname = SO_RCVLOWAT;
3182 break;
bellard8853f862004-02-22 14:57:26 +00003183 default:
3184 goto unimplemented;
3185 }
bellard3532fa72006-06-24 15:06:03 +00003186 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003187 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003188
bellard2f619692007-11-16 10:46:05 +00003189 if (get_user_u32(val, optval_addr))
3190 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003191 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003192 break;
bellard7854b052003-03-29 17:22:23 +00003193 default:
bellard8853f862004-02-22 14:57:26 +00003194 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003195 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003196 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003197 }
bellard8853f862004-02-22 14:57:26 +00003198 return ret;
bellard7854b052003-03-29 17:22:23 +00003199}
3200
ths0da46a62007-10-20 20:23:07 +00003201/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003202static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003203 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003204{
blueswir1992f48a2007-10-14 16:27:31 +00003205 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003206 int len, val;
3207 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003208
3209 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003210 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003211 level = SOL_SOCKET;
3212 switch (optname) {
3213 /* These don't just return a single integer */
3214 case TARGET_SO_LINGER:
3215 case TARGET_SO_RCVTIMEO:
3216 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003217 case TARGET_SO_PEERNAME:
3218 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003219 case TARGET_SO_PEERCRED: {
3220 struct ucred cr;
3221 socklen_t crlen;
3222 struct target_ucred *tcr;
3223
3224 if (get_user_u32(len, optlen)) {
3225 return -TARGET_EFAULT;
3226 }
3227 if (len < 0) {
3228 return -TARGET_EINVAL;
3229 }
3230
3231 crlen = sizeof(cr);
3232 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3233 &cr, &crlen));
3234 if (ret < 0) {
3235 return ret;
3236 }
3237 if (len > crlen) {
3238 len = crlen;
3239 }
3240 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3241 return -TARGET_EFAULT;
3242 }
3243 __put_user(cr.pid, &tcr->pid);
3244 __put_user(cr.uid, &tcr->uid);
3245 __put_user(cr.gid, &tcr->gid);
3246 unlock_user_struct(tcr, optval_addr, 1);
3247 if (put_user_u32(len, optlen)) {
3248 return -TARGET_EFAULT;
3249 }
3250 break;
3251 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003252 /* Options with 'int' argument. */
3253 case TARGET_SO_DEBUG:
3254 optname = SO_DEBUG;
3255 goto int_case;
3256 case TARGET_SO_REUSEADDR:
3257 optname = SO_REUSEADDR;
3258 goto int_case;
3259 case TARGET_SO_TYPE:
3260 optname = SO_TYPE;
3261 goto int_case;
3262 case TARGET_SO_ERROR:
3263 optname = SO_ERROR;
3264 goto int_case;
3265 case TARGET_SO_DONTROUTE:
3266 optname = SO_DONTROUTE;
3267 goto int_case;
3268 case TARGET_SO_BROADCAST:
3269 optname = SO_BROADCAST;
3270 goto int_case;
3271 case TARGET_SO_SNDBUF:
3272 optname = SO_SNDBUF;
3273 goto int_case;
3274 case TARGET_SO_RCVBUF:
3275 optname = SO_RCVBUF;
3276 goto int_case;
3277 case TARGET_SO_KEEPALIVE:
3278 optname = SO_KEEPALIVE;
3279 goto int_case;
3280 case TARGET_SO_OOBINLINE:
3281 optname = SO_OOBINLINE;
3282 goto int_case;
3283 case TARGET_SO_NO_CHECK:
3284 optname = SO_NO_CHECK;
3285 goto int_case;
3286 case TARGET_SO_PRIORITY:
3287 optname = SO_PRIORITY;
3288 goto int_case;
3289#ifdef SO_BSDCOMPAT
3290 case TARGET_SO_BSDCOMPAT:
3291 optname = SO_BSDCOMPAT;
3292 goto int_case;
3293#endif
3294 case TARGET_SO_PASSCRED:
3295 optname = SO_PASSCRED;
3296 goto int_case;
3297 case TARGET_SO_TIMESTAMP:
3298 optname = SO_TIMESTAMP;
3299 goto int_case;
3300 case TARGET_SO_RCVLOWAT:
3301 optname = SO_RCVLOWAT;
3302 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003303 case TARGET_SO_ACCEPTCONN:
3304 optname = SO_ACCEPTCONN;
3305 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003306 default:
bellard2efbe912005-07-23 15:10:20 +00003307 goto int_case;
3308 }
3309 break;
3310 case SOL_TCP:
3311 /* TCP options all take an 'int' value. */
3312 int_case:
bellard2f619692007-11-16 10:46:05 +00003313 if (get_user_u32(len, optlen))
3314 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003315 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003316 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003317 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003318 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3319 if (ret < 0)
3320 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003321 if (optname == SO_TYPE) {
3322 val = host_to_target_sock_type(val);
3323 }
bellard2efbe912005-07-23 15:10:20 +00003324 if (len > lv)
3325 len = lv;
bellard2f619692007-11-16 10:46:05 +00003326 if (len == 4) {
3327 if (put_user_u32(val, optval_addr))
3328 return -TARGET_EFAULT;
3329 } else {
3330 if (put_user_u8(val, optval_addr))
3331 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003332 }
bellard2f619692007-11-16 10:46:05 +00003333 if (put_user_u32(len, optlen))
3334 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003335 break;
3336 case SOL_IP:
3337 switch(optname) {
3338 case IP_TOS:
3339 case IP_TTL:
3340 case IP_HDRINCL:
3341 case IP_ROUTER_ALERT:
3342 case IP_RECVOPTS:
3343 case IP_RETOPTS:
3344 case IP_PKTINFO:
3345 case IP_MTU_DISCOVER:
3346 case IP_RECVERR:
3347 case IP_RECVTOS:
3348#ifdef IP_FREEBIND
3349 case IP_FREEBIND:
3350#endif
3351 case IP_MULTICAST_TTL:
3352 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003353 if (get_user_u32(len, optlen))
3354 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003355 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003356 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003357 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003358 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3359 if (ret < 0)
3360 return ret;
bellard2efbe912005-07-23 15:10:20 +00003361 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003362 len = 1;
bellard2f619692007-11-16 10:46:05 +00003363 if (put_user_u32(len, optlen)
3364 || put_user_u8(val, optval_addr))
3365 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003366 } else {
bellard2efbe912005-07-23 15:10:20 +00003367 if (len > sizeof(int))
3368 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003369 if (put_user_u32(len, optlen)
3370 || put_user_u32(val, optval_addr))
3371 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003372 }
bellard8853f862004-02-22 14:57:26 +00003373 break;
bellard2efbe912005-07-23 15:10:20 +00003374 default:
thsc02f4992007-12-18 02:39:59 +00003375 ret = -TARGET_ENOPROTOOPT;
3376 break;
bellard8853f862004-02-22 14:57:26 +00003377 }
3378 break;
3379 default:
3380 unimplemented:
3381 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3382 level, optname);
thsc02f4992007-12-18 02:39:59 +00003383 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003384 break;
3385 }
3386 return ret;
bellard7854b052003-03-29 17:22:23 +00003387}
3388
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003389static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003390 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003391{
3392 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003393 struct iovec *vec;
3394 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003395 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003396 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003397 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003398
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003399 if (count == 0) {
3400 errno = 0;
3401 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003402 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003403 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003404 errno = EINVAL;
3405 return NULL;
3406 }
3407
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303408 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003409 if (vec == NULL) {
3410 errno = ENOMEM;
3411 return NULL;
3412 }
3413
3414 target_vec = lock_user(VERIFY_READ, target_addr,
3415 count * sizeof(struct target_iovec), 1);
3416 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003417 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003418 goto fail2;
3419 }
3420
3421 /* ??? If host page size > target page size, this will result in a
3422 value larger than what we can actually support. */
3423 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3424 total_len = 0;
3425
3426 for (i = 0; i < count; i++) {
3427 abi_ulong base = tswapal(target_vec[i].iov_base);
3428 abi_long len = tswapal(target_vec[i].iov_len);
3429
3430 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003431 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003432 goto fail;
3433 } else if (len == 0) {
3434 /* Zero length pointer is ignored. */
3435 vec[i].iov_base = 0;
3436 } else {
3437 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003438 /* If the first buffer pointer is bad, this is a fault. But
3439 * subsequent bad buffers will result in a partial write; this
3440 * is realized by filling the vector with null pointers and
3441 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003442 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003443 if (i == 0) {
3444 err = EFAULT;
3445 goto fail;
3446 } else {
3447 bad_address = true;
3448 }
3449 }
3450 if (bad_address) {
3451 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003452 }
3453 if (len > max_len - total_len) {
3454 len = max_len - total_len;
3455 }
3456 }
3457 vec[i].iov_len = len;
3458 total_len += len;
3459 }
3460
3461 unlock_user(target_vec, target_addr, 0);
3462 return vec;
3463
3464 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003465 while (--i >= 0) {
3466 if (tswapal(target_vec[i].iov_len) > 0) {
3467 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3468 }
3469 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003470 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003471 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303472 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003473 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003474 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003475}
3476
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003477static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003478 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003479{
3480 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003481 int i;
3482
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003483 target_vec = lock_user(VERIFY_READ, target_addr,
3484 count * sizeof(struct target_iovec), 1);
3485 if (target_vec) {
3486 for (i = 0; i < count; i++) {
3487 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003488 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003489 if (len < 0) {
3490 break;
3491 }
balrogd732dcb2008-10-28 10:21:03 +00003492 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3493 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003494 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003495 }
bellard579a97f2007-11-11 14:26:47 +00003496
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303497 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003498}
3499
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003500static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003501{
3502 int host_type = 0;
3503 int target_type = *type;
3504
3505 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3506 case TARGET_SOCK_DGRAM:
3507 host_type = SOCK_DGRAM;
3508 break;
3509 case TARGET_SOCK_STREAM:
3510 host_type = SOCK_STREAM;
3511 break;
3512 default:
3513 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3514 break;
3515 }
3516 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003517#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003518 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003519#else
3520 return -TARGET_EINVAL;
3521#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003522 }
3523 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003524#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003525 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003526#elif !defined(O_NONBLOCK)
3527 return -TARGET_EINVAL;
3528#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003529 }
3530 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003531 return 0;
3532}
3533
3534/* Try to emulate socket type flags after socket creation. */
3535static int sock_flags_fixup(int fd, int target_type)
3536{
3537#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3538 if (target_type & TARGET_SOCK_NONBLOCK) {
3539 int flags = fcntl(fd, F_GETFL);
3540 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3541 close(fd);
3542 return -TARGET_EINVAL;
3543 }
3544 }
3545#endif
3546 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003547}
3548
Laurent Vivier0cf22722015-10-28 21:40:45 +01003549static abi_long packet_target_to_host_sockaddr(void *host_addr,
3550 abi_ulong target_addr,
3551 socklen_t len)
3552{
3553 struct sockaddr *addr = host_addr;
3554 struct target_sockaddr *target_saddr;
3555
3556 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3557 if (!target_saddr) {
3558 return -TARGET_EFAULT;
3559 }
3560
3561 memcpy(addr, target_saddr, len);
3562 addr->sa_family = tswap16(target_saddr->sa_family);
3563 /* spkt_protocol is big-endian */
3564
3565 unlock_user(target_saddr, target_addr, 0);
3566 return 0;
3567}
3568
3569static TargetFdTrans target_packet_trans = {
3570 .target_to_host_addr = packet_target_to_host_sockaddr,
3571};
3572
Laurent Vivier575b22b2016-06-02 22:14:15 +02003573#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003574static abi_long netlink_route_target_to_host(void *buf, size_t len)
3575{
Laurent Vivieref759f62016-06-21 19:51:13 +02003576 abi_long ret;
3577
3578 ret = target_to_host_nlmsg_route(buf, len);
3579 if (ret < 0) {
3580 return ret;
3581 }
3582
3583 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003584}
3585
3586static abi_long netlink_route_host_to_target(void *buf, size_t len)
3587{
Laurent Vivieref759f62016-06-21 19:51:13 +02003588 abi_long ret;
3589
3590 ret = host_to_target_nlmsg_route(buf, len);
3591 if (ret < 0) {
3592 return ret;
3593 }
3594
3595 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003596}
3597
3598static TargetFdTrans target_netlink_route_trans = {
3599 .target_to_host_data = netlink_route_target_to_host,
3600 .host_to_target_data = netlink_route_host_to_target,
3601};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003602#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003603
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003604static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3605{
Laurent Vivieref759f62016-06-21 19:51:13 +02003606 abi_long ret;
3607
3608 ret = target_to_host_nlmsg_audit(buf, len);
3609 if (ret < 0) {
3610 return ret;
3611 }
3612
3613 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003614}
3615
3616static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3617{
Laurent Vivieref759f62016-06-21 19:51:13 +02003618 abi_long ret;
3619
3620 ret = host_to_target_nlmsg_audit(buf, len);
3621 if (ret < 0) {
3622 return ret;
3623 }
3624
3625 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003626}
3627
3628static TargetFdTrans target_netlink_audit_trans = {
3629 .target_to_host_data = netlink_audit_target_to_host,
3630 .host_to_target_data = netlink_audit_host_to_target,
3631};
3632
ths0da46a62007-10-20 20:23:07 +00003633/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003634static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003635{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003636 int target_type = type;
3637 int ret;
3638
3639 ret = target_to_host_sock_type(&type);
3640 if (ret) {
3641 return ret;
3642 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003643
Laurent Vivier575b22b2016-06-02 22:14:15 +02003644 if (domain == PF_NETLINK && !(
3645#ifdef CONFIG_RTNETLINK
3646 protocol == NETLINK_ROUTE ||
3647#endif
3648 protocol == NETLINK_KOBJECT_UEVENT ||
3649 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003650 return -EPFNOSUPPORT;
3651 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003652
3653 if (domain == AF_PACKET ||
3654 (domain == AF_INET && type == SOCK_PACKET)) {
3655 protocol = tswap16(protocol);
3656 }
3657
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003658 ret = get_errno(socket(domain, type, protocol));
3659 if (ret >= 0) {
3660 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003661 if (type == SOCK_PACKET) {
3662 /* Manage an obsolete case :
3663 * if socket type is SOCK_PACKET, bind by name
3664 */
3665 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003666 } else if (domain == PF_NETLINK) {
3667 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003668#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003669 case NETLINK_ROUTE:
3670 fd_trans_register(ret, &target_netlink_route_trans);
3671 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003672#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003673 case NETLINK_KOBJECT_UEVENT:
3674 /* nothing to do: messages are strings */
3675 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003676 case NETLINK_AUDIT:
3677 fd_trans_register(ret, &target_netlink_audit_trans);
3678 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003679 default:
3680 g_assert_not_reached();
3681 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003682 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003683 }
3684 return ret;
bellard3532fa72006-06-24 15:06:03 +00003685}
3686
ths0da46a62007-10-20 20:23:07 +00003687/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003688static abi_long do_bind(int sockfd, abi_ulong target_addr,
3689 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003690{
aurel328f7aeaf2009-01-30 19:47:57 +00003691 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003692 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003693
Blue Swirl38724252010-09-18 05:53:14 +00003694 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003695 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003696 }
aurel328f7aeaf2009-01-30 19:47:57 +00003697
aurel32607175e2009-04-15 16:11:59 +00003698 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003699
Laurent Vivier7b36f782015-10-28 21:40:44 +01003700 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003701 if (ret)
3702 return ret;
3703
bellard3532fa72006-06-24 15:06:03 +00003704 return get_errno(bind(sockfd, addr, addrlen));
3705}
3706
ths0da46a62007-10-20 20:23:07 +00003707/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003708static abi_long do_connect(int sockfd, abi_ulong target_addr,
3709 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003710{
aurel328f7aeaf2009-01-30 19:47:57 +00003711 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003712 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003713
Blue Swirl38724252010-09-18 05:53:14 +00003714 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003715 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003716 }
aurel328f7aeaf2009-01-30 19:47:57 +00003717
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003718 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003719
Laurent Vivier7b36f782015-10-28 21:40:44 +01003720 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003721 if (ret)
3722 return ret;
3723
Peter Maydell2a3c7612016-06-06 19:58:03 +01003724 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003725}
3726
Alexander Graff19e00d2014-03-02 19:36:42 +00003727/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3728static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3729 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003730{
balrog6de645c2008-10-28 10:26:29 +00003731 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003732 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003733 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003734 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003735 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003736
bellard3532fa72006-06-24 15:06:03 +00003737 if (msgp->msg_name) {
3738 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003739 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003740 ret = target_to_host_sockaddr(fd, msg.msg_name,
3741 tswapal(msgp->msg_name),
3742 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003743 if (ret == -TARGET_EFAULT) {
3744 /* For connected sockets msg_name and msg_namelen must
3745 * be ignored, so returning EFAULT immediately is wrong.
3746 * Instead, pass a bad msg_name to the host kernel, and
3747 * let it decide whether to return EFAULT or not.
3748 */
3749 msg.msg_name = (void *)-1;
3750 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003751 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003752 }
bellard3532fa72006-06-24 15:06:03 +00003753 } else {
3754 msg.msg_name = NULL;
3755 msg.msg_namelen = 0;
3756 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003757 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003758 msg.msg_control = alloca(msg.msg_controllen);
3759 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003760
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003761 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003762 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003763
3764 if (count > IOV_MAX) {
3765 /* sendrcvmsg returns a different errno for this condition than
3766 * readv/writev, so we must catch it here before lock_iovec() does.
3767 */
3768 ret = -TARGET_EMSGSIZE;
3769 goto out2;
3770 }
3771
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003772 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3773 target_vec, count, send);
3774 if (vec == NULL) {
3775 ret = -host_to_target_errno(errno);
3776 goto out2;
3777 }
bellard3532fa72006-06-24 15:06:03 +00003778 msg.msg_iovlen = count;
3779 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003780
bellard3532fa72006-06-24 15:06:03 +00003781 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003782 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003783 void *host_msg;
3784
3785 host_msg = g_malloc(msg.msg_iov->iov_len);
3786 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3787 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003788 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003789 if (ret >= 0) {
3790 msg.msg_iov->iov_base = host_msg;
3791 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3792 }
3793 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003794 } else {
3795 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003796 if (ret == 0) {
3797 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3798 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003799 }
bellard3532fa72006-06-24 15:06:03 +00003800 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003801 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003802 if (!is_error(ret)) {
3803 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003804 if (fd_trans_host_to_target_data(fd)) {
3805 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003806 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003807 } else {
3808 ret = host_to_target_cmsg(msgp, &msg);
3809 }
Jing Huangca619062012-07-24 13:58:02 +00003810 if (!is_error(ret)) {
3811 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003812 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003813 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3814 msg.msg_name, msg.msg_namelen);
3815 if (ret) {
3816 goto out;
3817 }
3818 }
3819
balrog6de645c2008-10-28 10:26:29 +00003820 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003821 }
balrog6de645c2008-10-28 10:26:29 +00003822 }
bellard3532fa72006-06-24 15:06:03 +00003823 }
Jing Huangca619062012-07-24 13:58:02 +00003824
3825out:
bellard3532fa72006-06-24 15:06:03 +00003826 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003827out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003828 return ret;
3829}
3830
3831static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3832 int flags, int send)
3833{
3834 abi_long ret;
3835 struct target_msghdr *msgp;
3836
3837 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3838 msgp,
3839 target_msg,
3840 send ? 1 : 0)) {
3841 return -TARGET_EFAULT;
3842 }
3843 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003844 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003845 return ret;
3846}
3847
Alexander Graff19e00d2014-03-02 19:36:42 +00003848/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3849 * so it might not have this *mmsg-specific flag either.
3850 */
3851#ifndef MSG_WAITFORONE
3852#define MSG_WAITFORONE 0x10000
3853#endif
3854
3855static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3856 unsigned int vlen, unsigned int flags,
3857 int send)
3858{
3859 struct target_mmsghdr *mmsgp;
3860 abi_long ret = 0;
3861 int i;
3862
3863 if (vlen > UIO_MAXIOV) {
3864 vlen = UIO_MAXIOV;
3865 }
3866
3867 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3868 if (!mmsgp) {
3869 return -TARGET_EFAULT;
3870 }
3871
3872 for (i = 0; i < vlen; i++) {
3873 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3874 if (is_error(ret)) {
3875 break;
3876 }
3877 mmsgp[i].msg_len = tswap32(ret);
3878 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3879 if (flags & MSG_WAITFORONE) {
3880 flags |= MSG_DONTWAIT;
3881 }
3882 }
3883
3884 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3885
3886 /* Return number of datagrams sent if we sent any at all;
3887 * otherwise return the error.
3888 */
3889 if (i) {
3890 return i;
3891 }
3892 return ret;
3893}
Alexander Graff19e00d2014-03-02 19:36:42 +00003894
Peter Maydella94b4982013-02-08 04:35:04 +00003895/* do_accept4() Must return target values and target errnos. */
3896static abi_long do_accept4(int fd, abi_ulong target_addr,
3897 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003898{
bellard2f619692007-11-16 10:46:05 +00003899 socklen_t addrlen;
3900 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003901 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003902 int host_flags;
3903
3904 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003905
Peter Maydella94b4982013-02-08 04:35:04 +00003906 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003907 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003908 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003909
3910 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003911 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003912 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003913
Blue Swirl38724252010-09-18 05:53:14 +00003914 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003915 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003916 }
aurel328f7aeaf2009-01-30 19:47:57 +00003917
Arnaud Patard917507b2009-06-19 10:44:45 +03003918 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3919 return -TARGET_EINVAL;
3920
bellard2f619692007-11-16 10:46:05 +00003921 addr = alloca(addrlen);
3922
Peter Maydellff6dc132016-06-06 19:58:13 +01003923 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003924 if (!is_error(ret)) {
3925 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003926 if (put_user_u32(addrlen, target_addrlen_addr))
3927 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003928 }
3929 return ret;
3930}
3931
ths0da46a62007-10-20 20:23:07 +00003932/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003933static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003934 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003935{
bellard2f619692007-11-16 10:46:05 +00003936 socklen_t addrlen;
3937 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003938 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003939
bellard2f619692007-11-16 10:46:05 +00003940 if (get_user_u32(addrlen, target_addrlen_addr))
3941 return -TARGET_EFAULT;
3942
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_EFAULT;
3949
bellard2f619692007-11-16 10:46:05 +00003950 addr = alloca(addrlen);
3951
pbrook1be9e1d2006-11-19 15:26:04 +00003952 ret = get_errno(getpeername(fd, addr, &addrlen));
3953 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_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003962static abi_long do_getsockname(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(getsockname(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_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003991static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003992 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003993{
3994 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003995 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003996
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003997 target_to_host_sock_type(&type);
3998
pbrook1be9e1d2006-11-19 15:26:04 +00003999 ret = get_errno(socketpair(domain, type, protocol, tab));
4000 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00004001 if (put_user_s32(tab[0], target_tab_addr)
4002 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
4003 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004004 }
4005 return ret;
4006}
4007
ths0da46a62007-10-20 20:23:07 +00004008/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004009static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
4010 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004011{
4012 void *addr;
4013 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02004014 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00004015 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004016
Blue Swirl38724252010-09-18 05:53:14 +00004017 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004018 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00004019 }
aurel328f7aeaf2009-01-30 19:47:57 +00004020
bellard579a97f2007-11-11 14:26:47 +00004021 host_msg = lock_user(VERIFY_READ, msg, len, 1);
4022 if (!host_msg)
4023 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004024 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004025 copy_msg = host_msg;
4026 host_msg = g_malloc(len);
4027 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004028 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
4029 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004030 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02004031 }
4032 }
pbrook1be9e1d2006-11-19 15:26:04 +00004033 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02004034 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01004035 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03004036 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02004037 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03004038 }
Peter Maydell66687532016-06-06 19:58:04 +01004039 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004040 } else {
Peter Maydell66687532016-06-06 19:58:04 +01004041 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004042 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02004043fail:
4044 if (copy_msg) {
4045 g_free(host_msg);
4046 host_msg = copy_msg;
4047 }
pbrook1be9e1d2006-11-19 15:26:04 +00004048 unlock_user(host_msg, msg, 0);
4049 return ret;
4050}
4051
ths0da46a62007-10-20 20:23:07 +00004052/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004053static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4054 abi_ulong target_addr,
4055 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004056{
4057 socklen_t addrlen;
4058 void *addr;
4059 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004060 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004061
bellard579a97f2007-11-11 14:26:47 +00004062 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4063 if (!host_msg)
4064 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004065 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004066 if (get_user_u32(addrlen, target_addrlen)) {
4067 ret = -TARGET_EFAULT;
4068 goto fail;
4069 }
Blue Swirl38724252010-09-18 05:53:14 +00004070 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004071 ret = -TARGET_EINVAL;
4072 goto fail;
4073 }
pbrook1be9e1d2006-11-19 15:26:04 +00004074 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004075 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4076 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004077 } else {
4078 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004079 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004080 }
4081 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004082 if (fd_trans_host_to_target_data(fd)) {
4083 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4084 }
pbrook1be9e1d2006-11-19 15:26:04 +00004085 if (target_addr) {
4086 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004087 if (put_user_u32(addrlen, target_addrlen)) {
4088 ret = -TARGET_EFAULT;
4089 goto fail;
4090 }
pbrook1be9e1d2006-11-19 15:26:04 +00004091 }
4092 unlock_user(host_msg, msg, len);
4093 } else {
bellard2f619692007-11-16 10:46:05 +00004094fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004095 unlock_user(host_msg, msg, 0);
4096 }
4097 return ret;
4098}
4099
j_mayer32407102007-09-26 23:01:49 +00004100#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004101/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004102static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004103{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004104 static const unsigned nargs[] = { /* number of arguments per operation */
4105 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4106 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4107 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4108 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4109 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4110 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4111 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4112 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4113 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4114 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4115 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4116 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4117 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4118 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4119 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4120 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4121 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4122 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4123 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4124 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004125 };
4126 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004127 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004128
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004129 /* check the range of the first argument num */
4130 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4131 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4132 return -TARGET_EINVAL;
4133 }
4134 /* ensure we have space for args */
4135 if (nargs[num] > ARRAY_SIZE(a)) {
4136 return -TARGET_EINVAL;
4137 }
4138 /* collect the arguments in a[] according to nargs[] */
4139 for (i = 0; i < nargs[num]; ++i) {
4140 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4141 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004142 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004143 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004144 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004145 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004146 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004147 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004148 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004149 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004150 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004151 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004152 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004153 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004154 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004155 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004156 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004157 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004158 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004159 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004160 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004161 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004162 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004163 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004164 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004165 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004166 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004167 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004168 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004169 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004170 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004171 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004172 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004173 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004174 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004175 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004176 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4177 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4178 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4179 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4180 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4181 return do_accept4(a[0], a[1], a[2], a[3]);
4182 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4183 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4184 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4185 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004186 default:
4187 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004188 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004189 }
bellard31e31b82003-02-18 22:55:36 +00004190}
j_mayer32407102007-09-26 23:01:49 +00004191#endif
bellard31e31b82003-02-18 22:55:36 +00004192
bellard8853f862004-02-22 14:57:26 +00004193#define N_SHM_REGIONS 32
4194
4195static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004196 abi_ulong start;
4197 abi_ulong size;
4198 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004199} shm_regions[N_SHM_REGIONS];
4200
Peter Maydell005eb2a2016-07-15 16:50:47 +01004201#ifndef TARGET_SEMID64_DS
4202/* asm-generic version of this struct */
4203struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004204{
4205 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004206 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004207#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004208 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004209#endif
blueswir1992f48a2007-10-14 16:27:31 +00004210 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004211#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004212 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004213#endif
blueswir1992f48a2007-10-14 16:27:31 +00004214 abi_ulong sem_nsems;
4215 abi_ulong __unused3;
4216 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004217};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004218#endif
ths3eb6b042007-06-03 14:26:27 +00004219
bellard579a97f2007-11-11 14:26:47 +00004220static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4221 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004222{
4223 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004224 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004225
bellard579a97f2007-11-11 14:26:47 +00004226 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4227 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004228 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004229 host_ip->__key = tswap32(target_ip->__key);
4230 host_ip->uid = tswap32(target_ip->uid);
4231 host_ip->gid = tswap32(target_ip->gid);
4232 host_ip->cuid = tswap32(target_ip->cuid);
4233 host_ip->cgid = tswap32(target_ip->cgid);
4234#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4235 host_ip->mode = tswap32(target_ip->mode);
4236#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004237 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004238#endif
4239#if defined(TARGET_PPC)
4240 host_ip->__seq = tswap32(target_ip->__seq);
4241#else
4242 host_ip->__seq = tswap16(target_ip->__seq);
4243#endif
ths3eb6b042007-06-03 14:26:27 +00004244 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004245 return 0;
ths3eb6b042007-06-03 14:26:27 +00004246}
4247
bellard579a97f2007-11-11 14:26:47 +00004248static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4249 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004250{
4251 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004252 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004253
bellard579a97f2007-11-11 14:26:47 +00004254 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4255 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004256 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004257 target_ip->__key = tswap32(host_ip->__key);
4258 target_ip->uid = tswap32(host_ip->uid);
4259 target_ip->gid = tswap32(host_ip->gid);
4260 target_ip->cuid = tswap32(host_ip->cuid);
4261 target_ip->cgid = tswap32(host_ip->cgid);
4262#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4263 target_ip->mode = tswap32(host_ip->mode);
4264#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004265 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004266#endif
4267#if defined(TARGET_PPC)
4268 target_ip->__seq = tswap32(host_ip->__seq);
4269#else
4270 target_ip->__seq = tswap16(host_ip->__seq);
4271#endif
ths3eb6b042007-06-03 14:26:27 +00004272 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004273 return 0;
ths3eb6b042007-06-03 14:26:27 +00004274}
4275
bellard579a97f2007-11-11 14:26:47 +00004276static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4277 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004278{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004279 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004280
bellard579a97f2007-11-11 14:26:47 +00004281 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4282 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004283 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4284 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004285 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4286 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4287 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004288 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004289 return 0;
ths3eb6b042007-06-03 14:26:27 +00004290}
4291
bellard579a97f2007-11-11 14:26:47 +00004292static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4293 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004294{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004295 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004296
bellard579a97f2007-11-11 14:26:47 +00004297 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4298 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004299 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004300 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004301 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4302 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4303 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004304 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004305 return 0;
ths3eb6b042007-06-03 14:26:27 +00004306}
4307
aurel32e5289082009-04-18 16:16:12 +00004308struct target_seminfo {
4309 int semmap;
4310 int semmni;
4311 int semmns;
4312 int semmnu;
4313 int semmsl;
4314 int semopm;
4315 int semume;
4316 int semusz;
4317 int semvmx;
4318 int semaem;
4319};
4320
4321static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4322 struct seminfo *host_seminfo)
4323{
4324 struct target_seminfo *target_seminfo;
4325 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4326 return -TARGET_EFAULT;
4327 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4328 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4329 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4330 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4331 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4332 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4333 __put_user(host_seminfo->semume, &target_seminfo->semume);
4334 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4335 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4336 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4337 unlock_user_struct(target_seminfo, target_addr, 1);
4338 return 0;
4339}
4340
thsfa294812007-02-02 22:05:00 +00004341union semun {
4342 int val;
ths3eb6b042007-06-03 14:26:27 +00004343 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004344 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004345 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004346};
4347
ths3eb6b042007-06-03 14:26:27 +00004348union target_semun {
4349 int val;
aurel32e5289082009-04-18 16:16:12 +00004350 abi_ulong buf;
4351 abi_ulong array;
4352 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004353};
4354
aurel32e5289082009-04-18 16:16:12 +00004355static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4356 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004357{
aurel32e5289082009-04-18 16:16:12 +00004358 int nsems;
4359 unsigned short *array;
4360 union semun semun;
4361 struct semid_ds semid_ds;
4362 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004363
aurel32e5289082009-04-18 16:16:12 +00004364 semun.buf = &semid_ds;
4365
4366 ret = semctl(semid, 0, IPC_STAT, semun);
4367 if (ret == -1)
4368 return get_errno(ret);
4369
4370 nsems = semid_ds.sem_nsems;
4371
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304372 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004373 if (!*host_array) {
4374 return -TARGET_ENOMEM;
4375 }
aurel32e5289082009-04-18 16:16:12 +00004376 array = lock_user(VERIFY_READ, target_addr,
4377 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004378 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304379 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004380 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004381 }
aurel32e5289082009-04-18 16:16:12 +00004382
4383 for(i=0; i<nsems; i++) {
4384 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004385 }
aurel32e5289082009-04-18 16:16:12 +00004386 unlock_user(array, target_addr, 0);
4387
bellard579a97f2007-11-11 14:26:47 +00004388 return 0;
ths3eb6b042007-06-03 14:26:27 +00004389}
4390
aurel32e5289082009-04-18 16:16:12 +00004391static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4392 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004393{
aurel32e5289082009-04-18 16:16:12 +00004394 int nsems;
4395 unsigned short *array;
4396 union semun semun;
4397 struct semid_ds semid_ds;
4398 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004399
aurel32e5289082009-04-18 16:16:12 +00004400 semun.buf = &semid_ds;
4401
4402 ret = semctl(semid, 0, IPC_STAT, semun);
4403 if (ret == -1)
4404 return get_errno(ret);
4405
4406 nsems = semid_ds.sem_nsems;
4407
4408 array = lock_user(VERIFY_WRITE, target_addr,
4409 nsems*sizeof(unsigned short), 0);
4410 if (!array)
4411 return -TARGET_EFAULT;
4412
4413 for(i=0; i<nsems; i++) {
4414 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004415 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304416 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004417 unlock_user(array, target_addr, 1);
4418
bellard579a97f2007-11-11 14:26:47 +00004419 return 0;
ths3eb6b042007-06-03 14:26:27 +00004420}
4421
aurel32e5289082009-04-18 16:16:12 +00004422static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004423 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004424{
Stefan Weild1c002b2015-02-08 15:40:58 +01004425 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004426 union semun arg;
4427 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304428 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004429 struct seminfo seminfo;
4430 abi_long ret = -TARGET_EINVAL;
4431 abi_long err;
4432 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004433
4434 switch( cmd ) {
4435 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004436 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004437 /* In 64 bit cross-endian situations, we will erroneously pick up
4438 * the wrong half of the union for the "val" element. To rectify
4439 * this, the entire 8-byte structure is byteswapped, followed by
4440 * a swap of the 4 byte val field. In other cases, the data is
4441 * already in proper host byte order. */
4442 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4443 target_su.buf = tswapal(target_su.buf);
4444 arg.val = tswap32(target_su.val);
4445 } else {
4446 arg.val = target_su.val;
4447 }
aurel32e5289082009-04-18 16:16:12 +00004448 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004449 break;
4450 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004451 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004452 err = target_to_host_semarray(semid, &array, target_su.array);
4453 if (err)
4454 return err;
4455 arg.array = array;
4456 ret = get_errno(semctl(semid, semnum, cmd, arg));
4457 err = host_to_target_semarray(semid, target_su.array, &array);
4458 if (err)
4459 return err;
ths3eb6b042007-06-03 14:26:27 +00004460 break;
4461 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004462 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004463 case SEM_STAT:
4464 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4465 if (err)
4466 return err;
4467 arg.buf = &dsarg;
4468 ret = get_errno(semctl(semid, semnum, cmd, arg));
4469 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4470 if (err)
4471 return err;
ths3eb6b042007-06-03 14:26:27 +00004472 break;
aurel32e5289082009-04-18 16:16:12 +00004473 case IPC_INFO:
4474 case SEM_INFO:
4475 arg.__buf = &seminfo;
4476 ret = get_errno(semctl(semid, semnum, cmd, arg));
4477 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4478 if (err)
4479 return err;
4480 break;
4481 case IPC_RMID:
4482 case GETPID:
4483 case GETNCNT:
4484 case GETZCNT:
4485 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4486 break;
ths3eb6b042007-06-03 14:26:27 +00004487 }
4488
4489 return ret;
4490}
4491
aurel32e5289082009-04-18 16:16:12 +00004492struct target_sembuf {
4493 unsigned short sem_num;
4494 short sem_op;
4495 short sem_flg;
4496};
4497
4498static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4499 abi_ulong target_addr,
4500 unsigned nsops)
4501{
4502 struct target_sembuf *target_sembuf;
4503 int i;
4504
4505 target_sembuf = lock_user(VERIFY_READ, target_addr,
4506 nsops*sizeof(struct target_sembuf), 1);
4507 if (!target_sembuf)
4508 return -TARGET_EFAULT;
4509
4510 for(i=0; i<nsops; i++) {
4511 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4512 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4513 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4514 }
4515
4516 unlock_user(target_sembuf, target_addr, 0);
4517
4518 return 0;
4519}
4520
4521static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4522{
4523 struct sembuf sops[nsops];
4524
4525 if (target_to_host_sembuf(sops, ptr, nsops))
4526 return -TARGET_EFAULT;
4527
Peter Maydellffb7ee72016-06-06 19:58:12 +01004528 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004529}
4530
ths1bc012f2007-06-03 14:27:49 +00004531struct target_msqid_ds
4532{
aurel321c54ff92008-10-13 21:08:44 +00004533 struct target_ipc_perm msg_perm;
4534 abi_ulong msg_stime;
4535#if TARGET_ABI_BITS == 32
4536 abi_ulong __unused1;
4537#endif
4538 abi_ulong msg_rtime;
4539#if TARGET_ABI_BITS == 32
4540 abi_ulong __unused2;
4541#endif
4542 abi_ulong msg_ctime;
4543#if TARGET_ABI_BITS == 32
4544 abi_ulong __unused3;
4545#endif
4546 abi_ulong __msg_cbytes;
4547 abi_ulong msg_qnum;
4548 abi_ulong msg_qbytes;
4549 abi_ulong msg_lspid;
4550 abi_ulong msg_lrpid;
4551 abi_ulong __unused4;
4552 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004553};
4554
bellard579a97f2007-11-11 14:26:47 +00004555static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4556 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004557{
4558 struct target_msqid_ds *target_md;
4559
bellard579a97f2007-11-11 14:26:47 +00004560 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4561 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004562 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4563 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004564 host_md->msg_stime = tswapal(target_md->msg_stime);
4565 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4566 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4567 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4568 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4569 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4570 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4571 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004572 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004573 return 0;
ths1bc012f2007-06-03 14:27:49 +00004574}
4575
bellard579a97f2007-11-11 14:26:47 +00004576static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4577 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004578{
4579 struct target_msqid_ds *target_md;
4580
bellard579a97f2007-11-11 14:26:47 +00004581 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4582 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004583 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4584 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004585 target_md->msg_stime = tswapal(host_md->msg_stime);
4586 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4587 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4588 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4589 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4590 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4591 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4592 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004593 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004594 return 0;
ths1bc012f2007-06-03 14:27:49 +00004595}
4596
aurel321c54ff92008-10-13 21:08:44 +00004597struct target_msginfo {
4598 int msgpool;
4599 int msgmap;
4600 int msgmax;
4601 int msgmnb;
4602 int msgmni;
4603 int msgssz;
4604 int msgtql;
4605 unsigned short int msgseg;
4606};
4607
4608static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4609 struct msginfo *host_msginfo)
4610{
4611 struct target_msginfo *target_msginfo;
4612 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4613 return -TARGET_EFAULT;
4614 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4615 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4616 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4617 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4618 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4619 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4620 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4621 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4622 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004623 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004624}
4625
4626static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004627{
4628 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004629 struct msginfo msginfo;
4630 abi_long ret = -TARGET_EINVAL;
4631
4632 cmd &= 0xff;
4633
4634 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004635 case IPC_STAT:
4636 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004637 case MSG_STAT:
4638 if (target_to_host_msqid_ds(&dsarg,ptr))
4639 return -TARGET_EFAULT;
4640 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4641 if (host_to_target_msqid_ds(ptr,&dsarg))
4642 return -TARGET_EFAULT;
4643 break;
4644 case IPC_RMID:
4645 ret = get_errno(msgctl(msgid, cmd, NULL));
4646 break;
4647 case IPC_INFO:
4648 case MSG_INFO:
4649 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4650 if (host_to_target_msginfo(ptr, &msginfo))
4651 return -TARGET_EFAULT;
4652 break;
ths1bc012f2007-06-03 14:27:49 +00004653 }
aurel321c54ff92008-10-13 21:08:44 +00004654
ths1bc012f2007-06-03 14:27:49 +00004655 return ret;
4656}
4657
4658struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004659 abi_long mtype;
4660 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004661};
4662
blueswir1992f48a2007-10-14 16:27:31 +00004663static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004664 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004665{
4666 struct target_msgbuf *target_mb;
4667 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004668 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004669
Tom Mustaedcc5f92014-08-12 13:53:37 -05004670 if (msgsz < 0) {
4671 return -TARGET_EINVAL;
4672 }
4673
bellard579a97f2007-11-11 14:26:47 +00004674 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4675 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304676 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004677 if (!host_mb) {
4678 unlock_user_struct(target_mb, msgp, 0);
4679 return -TARGET_ENOMEM;
4680 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004681 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004682 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004683 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304684 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004685 unlock_user_struct(target_mb, msgp, 0);
4686
4687 return ret;
4688}
4689
blueswir1992f48a2007-10-14 16:27:31 +00004690static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004691 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004692 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004693{
4694 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004695 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004696 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004697 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004698
Peter Maydell99874f62016-05-20 19:00:56 +01004699 if (msgsz < 0) {
4700 return -TARGET_EINVAL;
4701 }
4702
bellard579a97f2007-11-11 14:26:47 +00004703 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4704 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004705
Peter Maydell415d8472016-05-20 19:00:57 +01004706 host_mb = g_try_malloc(msgsz + sizeof(long));
4707 if (!host_mb) {
4708 ret = -TARGET_ENOMEM;
4709 goto end;
4710 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004711 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004712
bellard579a97f2007-11-11 14:26:47 +00004713 if (ret > 0) {
4714 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4715 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4716 if (!target_mtext) {
4717 ret = -TARGET_EFAULT;
4718 goto end;
4719 }
aurel321c54ff92008-10-13 21:08:44 +00004720 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004721 unlock_user(target_mtext, target_mtext_addr, ret);
4722 }
aurel321c54ff92008-10-13 21:08:44 +00004723
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004724 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004725
bellard579a97f2007-11-11 14:26:47 +00004726end:
4727 if (target_mb)
4728 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004729 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004730 return ret;
4731}
4732
Riku Voipio88a8c982009-04-03 10:42:00 +03004733static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4734 abi_ulong target_addr)
4735{
4736 struct target_shmid_ds *target_sd;
4737
4738 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4739 return -TARGET_EFAULT;
4740 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4741 return -TARGET_EFAULT;
4742 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4743 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4744 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4745 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4746 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4747 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4748 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4749 unlock_user_struct(target_sd, target_addr, 0);
4750 return 0;
4751}
4752
4753static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4754 struct shmid_ds *host_sd)
4755{
4756 struct target_shmid_ds *target_sd;
4757
4758 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4759 return -TARGET_EFAULT;
4760 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4761 return -TARGET_EFAULT;
4762 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4763 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4764 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4765 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4766 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4767 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4768 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4769 unlock_user_struct(target_sd, target_addr, 1);
4770 return 0;
4771}
4772
4773struct target_shminfo {
4774 abi_ulong shmmax;
4775 abi_ulong shmmin;
4776 abi_ulong shmmni;
4777 abi_ulong shmseg;
4778 abi_ulong shmall;
4779};
4780
4781static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4782 struct shminfo *host_shminfo)
4783{
4784 struct target_shminfo *target_shminfo;
4785 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4786 return -TARGET_EFAULT;
4787 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4788 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4789 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4790 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4791 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4792 unlock_user_struct(target_shminfo, target_addr, 1);
4793 return 0;
4794}
4795
4796struct target_shm_info {
4797 int used_ids;
4798 abi_ulong shm_tot;
4799 abi_ulong shm_rss;
4800 abi_ulong shm_swp;
4801 abi_ulong swap_attempts;
4802 abi_ulong swap_successes;
4803};
4804
4805static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4806 struct shm_info *host_shm_info)
4807{
4808 struct target_shm_info *target_shm_info;
4809 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4810 return -TARGET_EFAULT;
4811 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4812 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4813 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4814 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4815 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4816 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4817 unlock_user_struct(target_shm_info, target_addr, 1);
4818 return 0;
4819}
4820
4821static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4822{
4823 struct shmid_ds dsarg;
4824 struct shminfo shminfo;
4825 struct shm_info shm_info;
4826 abi_long ret = -TARGET_EINVAL;
4827
4828 cmd &= 0xff;
4829
4830 switch(cmd) {
4831 case IPC_STAT:
4832 case IPC_SET:
4833 case SHM_STAT:
4834 if (target_to_host_shmid_ds(&dsarg, buf))
4835 return -TARGET_EFAULT;
4836 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4837 if (host_to_target_shmid_ds(buf, &dsarg))
4838 return -TARGET_EFAULT;
4839 break;
4840 case IPC_INFO:
4841 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4842 if (host_to_target_shminfo(buf, &shminfo))
4843 return -TARGET_EFAULT;
4844 break;
4845 case SHM_INFO:
4846 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4847 if (host_to_target_shm_info(buf, &shm_info))
4848 return -TARGET_EFAULT;
4849 break;
4850 case IPC_RMID:
4851 case SHM_LOCK:
4852 case SHM_UNLOCK:
4853 ret = get_errno(shmctl(shmid, cmd, NULL));
4854 break;
4855 }
4856
4857 return ret;
4858}
4859
Peter Maydellee8e7612016-07-11 16:48:11 +01004860#ifndef TARGET_FORCE_SHMLBA
4861/* For most architectures, SHMLBA is the same as the page size;
4862 * some architectures have larger values, in which case they should
4863 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4864 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4865 * and defining its own value for SHMLBA.
4866 *
4867 * The kernel also permits SHMLBA to be set by the architecture to a
4868 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4869 * this means that addresses are rounded to the large size if
4870 * SHM_RND is set but addresses not aligned to that size are not rejected
4871 * as long as they are at least page-aligned. Since the only architecture
4872 * which uses this is ia64 this code doesn't provide for that oddity.
4873 */
4874static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4875{
4876 return TARGET_PAGE_SIZE;
4877}
4878#endif
4879
4880static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4881 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004882{
4883 abi_long raddr;
4884 void *host_raddr;
4885 struct shmid_ds shm_info;
4886 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004887 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004888
4889 /* find out the length of the shared memory segment */
4890 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4891 if (is_error(ret)) {
4892 /* can't get length, bail out */
4893 return ret;
4894 }
4895
Peter Maydellee8e7612016-07-11 16:48:11 +01004896 shmlba = target_shmlba(cpu_env);
4897
4898 if (shmaddr & (shmlba - 1)) {
4899 if (shmflg & SHM_RND) {
4900 shmaddr &= ~(shmlba - 1);
4901 } else {
4902 return -TARGET_EINVAL;
4903 }
4904 }
Max Filippovebf9a362018-03-07 13:50:10 -08004905 if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
4906 return -TARGET_EINVAL;
4907 }
Peter Maydellee8e7612016-07-11 16:48:11 +01004908
Riku Voipio88a8c982009-04-03 10:42:00 +03004909 mmap_lock();
4910
4911 if (shmaddr)
4912 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4913 else {
4914 abi_ulong mmap_start;
4915
4916 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4917
4918 if (mmap_start == -1) {
4919 errno = ENOMEM;
4920 host_raddr = (void *)-1;
4921 } else
4922 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4923 }
4924
4925 if (host_raddr == (void *)-1) {
4926 mmap_unlock();
4927 return get_errno((long)host_raddr);
4928 }
4929 raddr=h2g((unsigned long)host_raddr);
4930
4931 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4932 PAGE_VALID | PAGE_READ |
4933 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4934
4935 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004936 if (!shm_regions[i].in_use) {
4937 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004938 shm_regions[i].start = raddr;
4939 shm_regions[i].size = shm_info.shm_segsz;
4940 break;
4941 }
4942 }
4943
4944 mmap_unlock();
4945 return raddr;
4946
4947}
4948
4949static inline abi_long do_shmdt(abi_ulong shmaddr)
4950{
4951 int i;
Max Filippov3c5f6a52018-02-28 14:16:04 -08004952 abi_long rv;
4953
4954 mmap_lock();
Riku Voipio88a8c982009-04-03 10:42:00 +03004955
4956 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004957 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4958 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004959 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004960 break;
4961 }
4962 }
Max Filippov3c5f6a52018-02-28 14:16:04 -08004963 rv = get_errno(shmdt(g2h(shmaddr)));
Riku Voipio88a8c982009-04-03 10:42:00 +03004964
Max Filippov3c5f6a52018-02-28 14:16:04 -08004965 mmap_unlock();
4966
4967 return rv;
Riku Voipio88a8c982009-04-03 10:42:00 +03004968}
4969
aurel321c54ff92008-10-13 21:08:44 +00004970#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004971/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004972/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004973static abi_long do_ipc(CPUArchState *cpu_env,
4974 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004975 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004976 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004977{
4978 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004979 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004980
4981 version = call >> 16;
4982 call &= 0xffff;
4983
4984 switch (call) {
thsfa294812007-02-02 22:05:00 +00004985 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004986 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004987 break;
4988
4989 case IPCOP_semget:
4990 ret = get_errno(semget(first, second, third));
4991 break;
4992
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004993 case IPCOP_semctl: {
4994 /* The semun argument to semctl is passed by value, so dereference the
4995 * ptr argument. */
4996 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004997 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004998 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004999 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05005000 }
thsd96372e2007-02-02 22:05:44 +00005001
aurel321c54ff92008-10-13 21:08:44 +00005002 case IPCOP_msgget:
5003 ret = get_errno(msgget(first, second));
5004 break;
thsd96372e2007-02-02 22:05:44 +00005005
aurel321c54ff92008-10-13 21:08:44 +00005006 case IPCOP_msgsnd:
5007 ret = do_msgsnd(first, ptr, second, third);
5008 break;
thsd96372e2007-02-02 22:05:44 +00005009
aurel321c54ff92008-10-13 21:08:44 +00005010 case IPCOP_msgctl:
5011 ret = do_msgctl(first, second, ptr);
5012 break;
thsd96372e2007-02-02 22:05:44 +00005013
aurel321c54ff92008-10-13 21:08:44 +00005014 case IPCOP_msgrcv:
5015 switch (version) {
5016 case 0:
5017 {
5018 struct target_ipc_kludge {
5019 abi_long msgp;
5020 abi_long msgtyp;
5021 } *tmp;
thsd96372e2007-02-02 22:05:44 +00005022
aurel321c54ff92008-10-13 21:08:44 +00005023 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
5024 ret = -TARGET_EFAULT;
5025 break;
ths1bc012f2007-06-03 14:27:49 +00005026 }
aurel321c54ff92008-10-13 21:08:44 +00005027
Laurent Vivier79dd77d2012-12-20 11:00:11 +00005028 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00005029
5030 unlock_user_struct(tmp, ptr, 0);
5031 break;
5032 }
5033 default:
5034 ret = do_msgrcv(first, ptr, second, fifth, third);
5035 }
5036 break;
thsd96372e2007-02-02 22:05:44 +00005037
bellard8853f862004-02-22 14:57:26 +00005038 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03005039 switch (version) {
5040 default:
bellard5a4a8982007-11-11 17:39:18 +00005041 {
5042 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01005043 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03005044 if (is_error(raddr))
5045 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00005046 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00005047 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03005048 break;
5049 }
5050 case 1:
5051 ret = -TARGET_EINVAL;
5052 break;
bellard5a4a8982007-11-11 17:39:18 +00005053 }
bellard8853f862004-02-22 14:57:26 +00005054 break;
5055 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03005056 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00005057 break;
5058
5059 case IPCOP_shmget:
5060 /* IPC_* flag values are the same on all linux platforms */
5061 ret = get_errno(shmget(first, second, third));
5062 break;
5063
5064 /* IPC_* and SHM_* command values are the same on all linux platforms */
5065 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005066 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005067 break;
5068 default:
j_mayer32407102007-09-26 23:01:49 +00005069 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005070 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005071 break;
5072 }
5073 return ret;
5074}
j_mayer32407102007-09-26 23:01:49 +00005075#endif
bellard8853f862004-02-22 14:57:26 +00005076
bellard31e31b82003-02-18 22:55:36 +00005077/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005078
Blue Swirl001faf32009-05-13 17:53:17 +00005079#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005080#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5081enum {
5082#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005083STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005084};
5085#undef STRUCT
5086#undef STRUCT_SPECIAL
5087
Blue Swirl001faf32009-05-13 17:53:17 +00005088#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005089#define STRUCT_SPECIAL(name)
5090#include "syscall_types.h"
5091#undef STRUCT
5092#undef STRUCT_SPECIAL
5093
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005094typedef struct IOCTLEntry IOCTLEntry;
5095
5096typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005097 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005098
5099struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005100 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005101 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005102 const char *name;
5103 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005104 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005105 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005106};
bellard31e31b82003-02-18 22:55:36 +00005107
5108#define IOC_R 0x0001
5109#define IOC_W 0x0002
5110#define IOC_RW (IOC_R | IOC_W)
5111
5112#define MAX_STRUCT_SIZE 4096
5113
Peter Maydelldace20d2011-01-10 13:11:24 +00005114#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005115/* So fiemap access checks don't overflow on 32 bit systems.
5116 * This is very slightly smaller than the limit imposed by
5117 * the underlying kernel.
5118 */
5119#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5120 / sizeof(struct fiemap_extent))
5121
5122static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005123 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005124{
5125 /* The parameter for this ioctl is a struct fiemap followed
5126 * by an array of struct fiemap_extent whose size is set
5127 * in fiemap->fm_extent_count. The array is filled in by the
5128 * ioctl.
5129 */
5130 int target_size_in, target_size_out;
5131 struct fiemap *fm;
5132 const argtype *arg_type = ie->arg_type;
5133 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5134 void *argptr, *p;
5135 abi_long ret;
5136 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5137 uint32_t outbufsz;
5138 int free_fm = 0;
5139
5140 assert(arg_type[0] == TYPE_PTR);
5141 assert(ie->access == IOC_RW);
5142 arg_type++;
5143 target_size_in = thunk_type_size(arg_type, 0);
5144 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5145 if (!argptr) {
5146 return -TARGET_EFAULT;
5147 }
5148 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5149 unlock_user(argptr, arg, 0);
5150 fm = (struct fiemap *)buf_temp;
5151 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5152 return -TARGET_EINVAL;
5153 }
5154
5155 outbufsz = sizeof (*fm) +
5156 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5157
5158 if (outbufsz > MAX_STRUCT_SIZE) {
5159 /* We can't fit all the extents into the fixed size buffer.
5160 * Allocate one that is large enough and use it instead.
5161 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305162 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005163 if (!fm) {
5164 return -TARGET_ENOMEM;
5165 }
5166 memcpy(fm, buf_temp, sizeof(struct fiemap));
5167 free_fm = 1;
5168 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005169 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005170 if (!is_error(ret)) {
5171 target_size_out = target_size_in;
5172 /* An extent_count of 0 means we were only counting the extents
5173 * so there are no structs to copy
5174 */
5175 if (fm->fm_extent_count != 0) {
5176 target_size_out += fm->fm_mapped_extents * extent_size;
5177 }
5178 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5179 if (!argptr) {
5180 ret = -TARGET_EFAULT;
5181 } else {
5182 /* Convert the struct fiemap */
5183 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5184 if (fm->fm_extent_count != 0) {
5185 p = argptr + target_size_in;
5186 /* ...and then all the struct fiemap_extents */
5187 for (i = 0; i < fm->fm_mapped_extents; i++) {
5188 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5189 THUNK_TARGET);
5190 p += extent_size;
5191 }
5192 }
5193 unlock_user(argptr, arg, target_size_out);
5194 }
5195 }
5196 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305197 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005198 }
5199 return ret;
5200}
Peter Maydelldace20d2011-01-10 13:11:24 +00005201#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005202
Laurent Vivier059c2f22011-03-30 00:12:12 +02005203static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005204 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005205{
5206 const argtype *arg_type = ie->arg_type;
5207 int target_size;
5208 void *argptr;
5209 int ret;
5210 struct ifconf *host_ifconf;
5211 uint32_t outbufsz;
5212 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5213 int target_ifreq_size;
5214 int nb_ifreq;
5215 int free_buf = 0;
5216 int i;
5217 int target_ifc_len;
5218 abi_long target_ifc_buf;
5219 int host_ifc_len;
5220 char *host_ifc_buf;
5221
5222 assert(arg_type[0] == TYPE_PTR);
5223 assert(ie->access == IOC_RW);
5224
5225 arg_type++;
5226 target_size = thunk_type_size(arg_type, 0);
5227
5228 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5229 if (!argptr)
5230 return -TARGET_EFAULT;
5231 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5232 unlock_user(argptr, arg, 0);
5233
5234 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5235 target_ifc_len = host_ifconf->ifc_len;
5236 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5237
5238 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5239 nb_ifreq = target_ifc_len / target_ifreq_size;
5240 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5241
5242 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5243 if (outbufsz > MAX_STRUCT_SIZE) {
5244 /* We can't fit all the extents into the fixed size buffer.
5245 * Allocate one that is large enough and use it instead.
5246 */
5247 host_ifconf = malloc(outbufsz);
5248 if (!host_ifconf) {
5249 return -TARGET_ENOMEM;
5250 }
5251 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5252 free_buf = 1;
5253 }
5254 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5255
5256 host_ifconf->ifc_len = host_ifc_len;
5257 host_ifconf->ifc_buf = host_ifc_buf;
5258
Peter Maydell49ca6f32016-06-06 19:58:14 +01005259 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005260 if (!is_error(ret)) {
5261 /* convert host ifc_len to target ifc_len */
5262
5263 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5264 target_ifc_len = nb_ifreq * target_ifreq_size;
5265 host_ifconf->ifc_len = target_ifc_len;
5266
5267 /* restore target ifc_buf */
5268
5269 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5270
5271 /* copy struct ifconf to target user */
5272
5273 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5274 if (!argptr)
5275 return -TARGET_EFAULT;
5276 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5277 unlock_user(argptr, arg, target_size);
5278
5279 /* copy ifreq[] to target user */
5280
5281 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5282 for (i = 0; i < nb_ifreq ; i++) {
5283 thunk_convert(argptr + i * target_ifreq_size,
5284 host_ifc_buf + i * sizeof(struct ifreq),
5285 ifreq_arg_type, THUNK_TARGET);
5286 }
5287 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5288 }
5289
5290 if (free_buf) {
5291 free(host_ifconf);
5292 }
5293
5294 return ret;
5295}
5296
Alexander Graf56e904e2012-01-31 18:42:06 +01005297static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005298 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005299{
5300 void *argptr;
5301 struct dm_ioctl *host_dm;
5302 abi_long guest_data;
5303 uint32_t guest_data_size;
5304 int target_size;
5305 const argtype *arg_type = ie->arg_type;
5306 abi_long ret;
5307 void *big_buf = NULL;
5308 char *host_data;
5309
5310 arg_type++;
5311 target_size = thunk_type_size(arg_type, 0);
5312 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5313 if (!argptr) {
5314 ret = -TARGET_EFAULT;
5315 goto out;
5316 }
5317 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5318 unlock_user(argptr, arg, 0);
5319
5320 /* buf_temp is too small, so fetch things into a bigger buffer */
5321 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5322 memcpy(big_buf, buf_temp, target_size);
5323 buf_temp = big_buf;
5324 host_dm = big_buf;
5325
5326 guest_data = arg + host_dm->data_start;
5327 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005328 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005329 goto out;
5330 }
5331 guest_data_size = host_dm->data_size - host_dm->data_start;
5332 host_data = (char*)host_dm + host_dm->data_start;
5333
5334 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005335 if (!argptr) {
5336 ret = -TARGET_EFAULT;
5337 goto out;
5338 }
5339
Alexander Graf56e904e2012-01-31 18:42:06 +01005340 switch (ie->host_cmd) {
5341 case DM_REMOVE_ALL:
5342 case DM_LIST_DEVICES:
5343 case DM_DEV_CREATE:
5344 case DM_DEV_REMOVE:
5345 case DM_DEV_SUSPEND:
5346 case DM_DEV_STATUS:
5347 case DM_DEV_WAIT:
5348 case DM_TABLE_STATUS:
5349 case DM_TABLE_CLEAR:
5350 case DM_TABLE_DEPS:
5351 case DM_LIST_VERSIONS:
5352 /* no input data */
5353 break;
5354 case DM_DEV_RENAME:
5355 case DM_DEV_SET_GEOMETRY:
5356 /* data contains only strings */
5357 memcpy(host_data, argptr, guest_data_size);
5358 break;
5359 case DM_TARGET_MSG:
5360 memcpy(host_data, argptr, guest_data_size);
5361 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5362 break;
5363 case DM_TABLE_LOAD:
5364 {
5365 void *gspec = argptr;
5366 void *cur_data = host_data;
5367 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5368 int spec_size = thunk_type_size(arg_type, 0);
5369 int i;
5370
5371 for (i = 0; i < host_dm->target_count; i++) {
5372 struct dm_target_spec *spec = cur_data;
5373 uint32_t next;
5374 int slen;
5375
5376 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5377 slen = strlen((char*)gspec + spec_size) + 1;
5378 next = spec->next;
5379 spec->next = sizeof(*spec) + slen;
5380 strcpy((char*)&spec[1], gspec + spec_size);
5381 gspec += next;
5382 cur_data += spec->next;
5383 }
5384 break;
5385 }
5386 default:
5387 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005388 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005389 goto out;
5390 }
5391 unlock_user(argptr, guest_data, 0);
5392
Peter Maydell49ca6f32016-06-06 19:58:14 +01005393 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005394 if (!is_error(ret)) {
5395 guest_data = arg + host_dm->data_start;
5396 guest_data_size = host_dm->data_size - host_dm->data_start;
5397 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5398 switch (ie->host_cmd) {
5399 case DM_REMOVE_ALL:
5400 case DM_DEV_CREATE:
5401 case DM_DEV_REMOVE:
5402 case DM_DEV_RENAME:
5403 case DM_DEV_SUSPEND:
5404 case DM_DEV_STATUS:
5405 case DM_TABLE_LOAD:
5406 case DM_TABLE_CLEAR:
5407 case DM_TARGET_MSG:
5408 case DM_DEV_SET_GEOMETRY:
5409 /* no return data */
5410 break;
5411 case DM_LIST_DEVICES:
5412 {
5413 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5414 uint32_t remaining_data = guest_data_size;
5415 void *cur_data = argptr;
5416 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5417 int nl_size = 12; /* can't use thunk_size due to alignment */
5418
5419 while (1) {
5420 uint32_t next = nl->next;
5421 if (next) {
5422 nl->next = nl_size + (strlen(nl->name) + 1);
5423 }
5424 if (remaining_data < nl->next) {
5425 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5426 break;
5427 }
5428 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5429 strcpy(cur_data + nl_size, nl->name);
5430 cur_data += nl->next;
5431 remaining_data -= nl->next;
5432 if (!next) {
5433 break;
5434 }
5435 nl = (void*)nl + next;
5436 }
5437 break;
5438 }
5439 case DM_DEV_WAIT:
5440 case DM_TABLE_STATUS:
5441 {
5442 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5443 void *cur_data = argptr;
5444 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5445 int spec_size = thunk_type_size(arg_type, 0);
5446 int i;
5447
5448 for (i = 0; i < host_dm->target_count; i++) {
5449 uint32_t next = spec->next;
5450 int slen = strlen((char*)&spec[1]) + 1;
5451 spec->next = (cur_data - argptr) + spec_size + slen;
5452 if (guest_data_size < spec->next) {
5453 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5454 break;
5455 }
5456 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5457 strcpy(cur_data + spec_size, (char*)&spec[1]);
5458 cur_data = argptr + spec->next;
5459 spec = (void*)host_dm + host_dm->data_start + next;
5460 }
5461 break;
5462 }
5463 case DM_TABLE_DEPS:
5464 {
5465 void *hdata = (void*)host_dm + host_dm->data_start;
5466 int count = *(uint32_t*)hdata;
5467 uint64_t *hdev = hdata + 8;
5468 uint64_t *gdev = argptr + 8;
5469 int i;
5470
5471 *(uint32_t*)argptr = tswap32(count);
5472 for (i = 0; i < count; i++) {
5473 *gdev = tswap64(*hdev);
5474 gdev++;
5475 hdev++;
5476 }
5477 break;
5478 }
5479 case DM_LIST_VERSIONS:
5480 {
5481 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5482 uint32_t remaining_data = guest_data_size;
5483 void *cur_data = argptr;
5484 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5485 int vers_size = thunk_type_size(arg_type, 0);
5486
5487 while (1) {
5488 uint32_t next = vers->next;
5489 if (next) {
5490 vers->next = vers_size + (strlen(vers->name) + 1);
5491 }
5492 if (remaining_data < vers->next) {
5493 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5494 break;
5495 }
5496 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5497 strcpy(cur_data + vers_size, vers->name);
5498 cur_data += vers->next;
5499 remaining_data -= vers->next;
5500 if (!next) {
5501 break;
5502 }
5503 vers = (void*)vers + next;
5504 }
5505 break;
5506 }
5507 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005508 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005509 ret = -TARGET_EINVAL;
5510 goto out;
5511 }
5512 unlock_user(argptr, guest_data, guest_data_size);
5513
5514 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5515 if (!argptr) {
5516 ret = -TARGET_EFAULT;
5517 goto out;
5518 }
5519 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5520 unlock_user(argptr, arg, target_size);
5521 }
5522out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005523 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005524 return ret;
5525}
5526
Alexander Grafa59b5e32014-08-22 13:15:50 +02005527static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005528 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005529{
5530 void *argptr;
5531 int target_size;
5532 const argtype *arg_type = ie->arg_type;
5533 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5534 abi_long ret;
5535
5536 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5537 struct blkpg_partition host_part;
5538
5539 /* Read and convert blkpg */
5540 arg_type++;
5541 target_size = thunk_type_size(arg_type, 0);
5542 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5543 if (!argptr) {
5544 ret = -TARGET_EFAULT;
5545 goto out;
5546 }
5547 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5548 unlock_user(argptr, arg, 0);
5549
5550 switch (host_blkpg->op) {
5551 case BLKPG_ADD_PARTITION:
5552 case BLKPG_DEL_PARTITION:
5553 /* payload is struct blkpg_partition */
5554 break;
5555 default:
5556 /* Unknown opcode */
5557 ret = -TARGET_EINVAL;
5558 goto out;
5559 }
5560
5561 /* Read and convert blkpg->data */
5562 arg = (abi_long)(uintptr_t)host_blkpg->data;
5563 target_size = thunk_type_size(part_arg_type, 0);
5564 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5565 if (!argptr) {
5566 ret = -TARGET_EFAULT;
5567 goto out;
5568 }
5569 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5570 unlock_user(argptr, arg, 0);
5571
5572 /* Swizzle the data pointer to our local copy and call! */
5573 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005574 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005575
5576out:
5577 return ret;
5578}
5579
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005580static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005581 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005582{
5583 const argtype *arg_type = ie->arg_type;
5584 const StructEntry *se;
5585 const argtype *field_types;
5586 const int *dst_offsets, *src_offsets;
5587 int target_size;
5588 void *argptr;
5589 abi_ulong *target_rt_dev_ptr;
5590 unsigned long *host_rt_dev_ptr;
5591 abi_long ret;
5592 int i;
5593
5594 assert(ie->access == IOC_W);
5595 assert(*arg_type == TYPE_PTR);
5596 arg_type++;
5597 assert(*arg_type == TYPE_STRUCT);
5598 target_size = thunk_type_size(arg_type, 0);
5599 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5600 if (!argptr) {
5601 return -TARGET_EFAULT;
5602 }
5603 arg_type++;
5604 assert(*arg_type == (int)STRUCT_rtentry);
5605 se = struct_entries + *arg_type++;
5606 assert(se->convert[0] == NULL);
5607 /* convert struct here to be able to catch rt_dev string */
5608 field_types = se->field_types;
5609 dst_offsets = se->field_offsets[THUNK_HOST];
5610 src_offsets = se->field_offsets[THUNK_TARGET];
5611 for (i = 0; i < se->nb_fields; i++) {
5612 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5613 assert(*field_types == TYPE_PTRVOID);
5614 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5615 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5616 if (*target_rt_dev_ptr != 0) {
5617 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5618 tswapal(*target_rt_dev_ptr));
5619 if (!*host_rt_dev_ptr) {
5620 unlock_user(argptr, arg, 0);
5621 return -TARGET_EFAULT;
5622 }
5623 } else {
5624 *host_rt_dev_ptr = 0;
5625 }
5626 field_types++;
5627 continue;
5628 }
5629 field_types = thunk_convert(buf_temp + dst_offsets[i],
5630 argptr + src_offsets[i],
5631 field_types, THUNK_HOST);
5632 }
5633 unlock_user(argptr, arg, 0);
5634
Peter Maydell49ca6f32016-06-06 19:58:14 +01005635 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005636 if (*host_rt_dev_ptr != 0) {
5637 unlock_user((void *)*host_rt_dev_ptr,
5638 *target_rt_dev_ptr, 0);
5639 }
5640 return ret;
5641}
5642
Paul Burtonca56f5b2014-06-22 11:25:47 +01005643static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005644 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005645{
5646 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005647 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005648}
5649
Andreas Schwab2b74f622018-01-29 11:47:06 +01005650#ifdef TIOCGPTPEER
5651static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
5652 int fd, int cmd, abi_long arg)
5653{
5654 int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
5655 return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
5656}
5657#endif
5658
blueswir19f106a72008-10-05 10:52:52 +00005659static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005660#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005661 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5662#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5663 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005664#define IOCTL_IGNORE(cmd) \
5665 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005666#include "ioctls.h"
5667 { 0, 0, },
5668};
5669
pbrook53a59602006-03-25 19:31:22 +00005670/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005671/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005672static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005673{
5674 const IOCTLEntry *ie;
5675 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005676 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005677 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005678 int target_size;
5679 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005680
5681 ie = ioctl_entries;
5682 for(;;) {
5683 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005684 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005685 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005686 }
5687 if (ie->target_cmd == cmd)
5688 break;
5689 ie++;
5690 }
5691 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005692#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005693 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005694#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005695 if (ie->do_ioctl) {
5696 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005697 } else if (!ie->host_cmd) {
5698 /* Some architectures define BSD ioctls in their headers
5699 that are not implemented in Linux. */
5700 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005701 }
5702
bellard31e31b82003-02-18 22:55:36 +00005703 switch(arg_type[0]) {
5704 case TYPE_NULL:
5705 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005706 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005707 break;
5708 case TYPE_PTRVOID:
5709 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005710 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005711 break;
5712 case TYPE_PTR:
5713 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005714 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005715 switch(ie->access) {
5716 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005717 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005718 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005719 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5720 if (!argptr)
5721 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005722 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5723 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005724 }
5725 break;
5726 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005727 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5728 if (!argptr)
5729 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005730 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5731 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005732 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005733 break;
5734 default:
5735 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005736 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5737 if (!argptr)
5738 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005739 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5740 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005741 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005742 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005743 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5744 if (!argptr)
5745 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005746 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5747 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005748 }
5749 break;
5750 }
5751 break;
5752 default:
j_mayer32407102007-09-26 23:01:49 +00005753 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5754 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005755 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005756 break;
5757 }
5758 return ret;
5759}
5760
blueswir1b39bc502008-10-05 10:51:10 +00005761static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005762 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5763 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5764 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5765 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5766 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5767 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5768 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5769 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5770 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5771 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5772 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5773 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5774 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5775 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5776 { 0, 0, 0, 0 }
5777};
5778
blueswir1b39bc502008-10-05 10:51:10 +00005779static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005780 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5781 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5782 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5783 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5784 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5785 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5786 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5787 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5788 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5789 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5790 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5791 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5792 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5793 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5794 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5795 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5796 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5797 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5798 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5799 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5800 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5801 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5802 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5803 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5804 { 0, 0, 0, 0 }
5805};
5806
blueswir1b39bc502008-10-05 10:51:10 +00005807static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005808 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5809 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5810 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5811 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5812 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5813 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5814 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5815 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5816 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5817 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5818 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5819 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5820 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5821 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5822 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5823 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5824 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5825 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5826 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5827 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5828 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5829 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5830 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5831 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5832 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5833 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5834 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5835 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5836 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5837 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5838 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5839 { 0, 0, 0, 0 }
5840};
5841
blueswir1b39bc502008-10-05 10:51:10 +00005842static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005843 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5844 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5845 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5846 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5847 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5848 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5849 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5850 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5851 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5852 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5853 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5854 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5855 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5856 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5857 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5858 { 0, 0, 0, 0 }
5859};
5860
5861static void target_to_host_termios (void *dst, const void *src)
5862{
5863 struct host_termios *host = dst;
5864 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005865
ths5fafdf22007-09-16 21:08:06 +00005866 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005867 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005868 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005869 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005870 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005871 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005872 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005873 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5874 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005875
Arnaud Patard44607122009-04-21 17:39:08 +03005876 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005877 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5878 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005879 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005880 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005881 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005882 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005883 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005884 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005885 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005886 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5887 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005888 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5889 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5890 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5891 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5892 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005893 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005894}
ths3b46e622007-09-17 08:09:54 +00005895
bellard31e31b82003-02-18 22:55:36 +00005896static void host_to_target_termios (void *dst, const void *src)
5897{
5898 struct target_termios *target = dst;
5899 const struct host_termios *host = src;
5900
ths5fafdf22007-09-16 21:08:06 +00005901 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005902 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005903 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005904 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005905 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005906 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005907 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005908 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5909 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005910
Arnaud Patard44607122009-04-21 17:39:08 +03005911 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005912 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5913 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5914 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5915 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5916 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5917 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5918 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5919 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5920 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5921 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5922 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5923 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5924 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5925 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5926 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5927 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5928 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5929}
5930
blueswir18e853dc2008-10-05 10:49:32 +00005931static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005932 .convert = { host_to_target_termios, target_to_host_termios },
5933 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5934 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5935};
5936
bellard5286db72003-06-05 00:57:30 +00005937static bitmask_transtbl mmap_flags_tbl[] = {
Helge Deller541e1692017-10-31 13:53:58 +01005938 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5939 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5940 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5941 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
5942 MAP_ANONYMOUS, MAP_ANONYMOUS },
5943 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
5944 MAP_GROWSDOWN, MAP_GROWSDOWN },
5945 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
5946 MAP_DENYWRITE, MAP_DENYWRITE },
5947 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
5948 MAP_EXECUTABLE, MAP_EXECUTABLE },
5949 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
5950 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
5951 MAP_NORESERVE, MAP_NORESERVE },
5952 { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
5953 /* MAP_STACK had been ignored by the kernel for quite some time.
5954 Recognize it for the target insofar as we do not want to pass
5955 it through to the host. */
5956 { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
5957 { 0, 0, 0, 0 }
bellard5286db72003-06-05 00:57:30 +00005958};
5959
bellard2ab83ea2003-06-15 19:56:46 +00005960#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005961
5962/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005963static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005964
bellard03acab62007-11-11 14:57:14 +00005965static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005966{
5967 int size;
pbrook53a59602006-03-25 19:31:22 +00005968 void *p;
bellard6dbad632003-03-16 18:05:05 +00005969
5970 if (!ldt_table)
5971 return 0;
5972 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5973 if (size > bytecount)
5974 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005975 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5976 if (!p)
bellard03acab62007-11-11 14:57:14 +00005977 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005978 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005979 memcpy(p, ldt_table, size);
5980 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005981 return size;
5982}
5983
5984/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005985static abi_long write_ldt(CPUX86State *env,
5986 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005987{
5988 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005989 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005990 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005991 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005992 uint32_t *lp, entry_1, entry_2;
5993
5994 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005995 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005996 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005997 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005998 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005999 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00006000 ldt_info.limit = tswap32(target_ldt_info->limit);
6001 ldt_info.flags = tswap32(target_ldt_info->flags);
6002 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00006003
bellard6dbad632003-03-16 18:05:05 +00006004 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00006005 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006006 seg_32bit = ldt_info.flags & 1;
6007 contents = (ldt_info.flags >> 1) & 3;
6008 read_exec_only = (ldt_info.flags >> 3) & 1;
6009 limit_in_pages = (ldt_info.flags >> 4) & 1;
6010 seg_not_present = (ldt_info.flags >> 5) & 1;
6011 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00006012#ifdef TARGET_ABI32
6013 lm = 0;
6014#else
6015 lm = (ldt_info.flags >> 7) & 1;
6016#endif
bellard6dbad632003-03-16 18:05:05 +00006017 if (contents == 3) {
6018 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00006019 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006020 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00006021 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00006022 }
6023 /* allocate the LDT */
6024 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00006025 env->ldt.base = target_mmap(0,
6026 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
6027 PROT_READ|PROT_WRITE,
6028 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
6029 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00006030 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00006031 memset(g2h(env->ldt.base), 0,
6032 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00006033 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00006034 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00006035 }
6036
6037 /* NOTE: same code as Linux kernel */
6038 /* Allow LDTs to be cleared by the user. */
6039 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6040 if (oldmode ||
6041 (contents == 0 &&
6042 read_exec_only == 1 &&
6043 seg_32bit == 0 &&
6044 limit_in_pages == 0 &&
6045 seg_not_present == 1 &&
6046 useable == 0 )) {
6047 entry_1 = 0;
6048 entry_2 = 0;
6049 goto install;
6050 }
6051 }
ths3b46e622007-09-17 08:09:54 +00006052
bellard6dbad632003-03-16 18:05:05 +00006053 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6054 (ldt_info.limit & 0x0ffff);
6055 entry_2 = (ldt_info.base_addr & 0xff000000) |
6056 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6057 (ldt_info.limit & 0xf0000) |
6058 ((read_exec_only ^ 1) << 9) |
6059 (contents << 10) |
6060 ((seg_not_present ^ 1) << 15) |
6061 (seg_32bit << 22) |
6062 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00006063 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00006064 0x7000;
6065 if (!oldmode)
6066 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00006067
bellard6dbad632003-03-16 18:05:05 +00006068 /* Install the new entry ... */
6069install:
6070 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
6071 lp[0] = tswap32(entry_1);
6072 lp[1] = tswap32(entry_2);
6073 return 0;
6074}
6075
6076/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00006077static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
6078 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006079{
bellard03acab62007-11-11 14:57:14 +00006080 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006081
bellard6dbad632003-03-16 18:05:05 +00006082 switch (func) {
6083 case 0:
6084 ret = read_ldt(ptr, bytecount);
6085 break;
6086 case 1:
6087 ret = write_ldt(env, ptr, bytecount, 1);
6088 break;
6089 case 0x11:
6090 ret = write_ldt(env, ptr, bytecount, 0);
6091 break;
bellard03acab62007-11-11 14:57:14 +00006092 default:
6093 ret = -TARGET_ENOSYS;
6094 break;
bellard6dbad632003-03-16 18:05:05 +00006095 }
6096 return ret;
6097}
bellard1b6b0292003-03-22 17:31:38 +00006098
blueswir14583f582008-08-24 10:35:55 +00006099#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006100abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006101{
6102 uint64_t *gdt_table = g2h(env->gdt.base);
6103 struct target_modify_ldt_ldt_s ldt_info;
6104 struct target_modify_ldt_ldt_s *target_ldt_info;
6105 int seg_32bit, contents, read_exec_only, limit_in_pages;
6106 int seg_not_present, useable, lm;
6107 uint32_t *lp, entry_1, entry_2;
6108 int i;
6109
6110 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6111 if (!target_ldt_info)
6112 return -TARGET_EFAULT;
6113 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006114 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006115 ldt_info.limit = tswap32(target_ldt_info->limit);
6116 ldt_info.flags = tswap32(target_ldt_info->flags);
6117 if (ldt_info.entry_number == -1) {
6118 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6119 if (gdt_table[i] == 0) {
6120 ldt_info.entry_number = i;
6121 target_ldt_info->entry_number = tswap32(i);
6122 break;
6123 }
6124 }
6125 }
6126 unlock_user_struct(target_ldt_info, ptr, 1);
6127
6128 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6129 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6130 return -TARGET_EINVAL;
6131 seg_32bit = ldt_info.flags & 1;
6132 contents = (ldt_info.flags >> 1) & 3;
6133 read_exec_only = (ldt_info.flags >> 3) & 1;
6134 limit_in_pages = (ldt_info.flags >> 4) & 1;
6135 seg_not_present = (ldt_info.flags >> 5) & 1;
6136 useable = (ldt_info.flags >> 6) & 1;
6137#ifdef TARGET_ABI32
6138 lm = 0;
6139#else
6140 lm = (ldt_info.flags >> 7) & 1;
6141#endif
6142
6143 if (contents == 3) {
6144 if (seg_not_present == 0)
6145 return -TARGET_EINVAL;
6146 }
6147
6148 /* NOTE: same code as Linux kernel */
6149 /* Allow LDTs to be cleared by the user. */
6150 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6151 if ((contents == 0 &&
6152 read_exec_only == 1 &&
6153 seg_32bit == 0 &&
6154 limit_in_pages == 0 &&
6155 seg_not_present == 1 &&
6156 useable == 0 )) {
6157 entry_1 = 0;
6158 entry_2 = 0;
6159 goto install;
6160 }
6161 }
6162
6163 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6164 (ldt_info.limit & 0x0ffff);
6165 entry_2 = (ldt_info.base_addr & 0xff000000) |
6166 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6167 (ldt_info.limit & 0xf0000) |
6168 ((read_exec_only ^ 1) << 9) |
6169 (contents << 10) |
6170 ((seg_not_present ^ 1) << 15) |
6171 (seg_32bit << 22) |
6172 (limit_in_pages << 23) |
6173 (useable << 20) |
6174 (lm << 21) |
6175 0x7000;
6176
6177 /* Install the new entry ... */
6178install:
6179 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6180 lp[0] = tswap32(entry_1);
6181 lp[1] = tswap32(entry_2);
6182 return 0;
6183}
6184
blueswir18fcd3692008-08-17 20:26:25 +00006185static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006186{
6187 struct target_modify_ldt_ldt_s *target_ldt_info;
6188 uint64_t *gdt_table = g2h(env->gdt.base);
6189 uint32_t base_addr, limit, flags;
6190 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6191 int seg_not_present, useable, lm;
6192 uint32_t *lp, entry_1, entry_2;
6193
6194 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6195 if (!target_ldt_info)
6196 return -TARGET_EFAULT;
6197 idx = tswap32(target_ldt_info->entry_number);
6198 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6199 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6200 unlock_user_struct(target_ldt_info, ptr, 1);
6201 return -TARGET_EINVAL;
6202 }
6203 lp = (uint32_t *)(gdt_table + idx);
6204 entry_1 = tswap32(lp[0]);
6205 entry_2 = tswap32(lp[1]);
6206
6207 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6208 contents = (entry_2 >> 10) & 3;
6209 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6210 seg_32bit = (entry_2 >> 22) & 1;
6211 limit_in_pages = (entry_2 >> 23) & 1;
6212 useable = (entry_2 >> 20) & 1;
6213#ifdef TARGET_ABI32
6214 lm = 0;
6215#else
6216 lm = (entry_2 >> 21) & 1;
6217#endif
6218 flags = (seg_32bit << 0) | (contents << 1) |
6219 (read_exec_only << 3) | (limit_in_pages << 4) |
6220 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6221 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6222 base_addr = (entry_1 >> 16) |
6223 (entry_2 & 0xff000000) |
6224 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006225 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006226 target_ldt_info->limit = tswap32(limit);
6227 target_ldt_info->flags = tswap32(flags);
6228 unlock_user_struct(target_ldt_info, ptr, 1);
6229 return 0;
6230}
blueswir14583f582008-08-24 10:35:55 +00006231#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006232
bellardd2fd1af2007-11-14 18:08:56 +00006233#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006234abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006235{
Juan Quintela1add8692011-06-16 17:37:09 +01006236 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006237 abi_ulong val;
6238 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006239
bellardd2fd1af2007-11-14 18:08:56 +00006240 switch(code) {
6241 case TARGET_ARCH_SET_GS:
6242 case TARGET_ARCH_SET_FS:
6243 if (code == TARGET_ARCH_SET_GS)
6244 idx = R_GS;
6245 else
6246 idx = R_FS;
6247 cpu_x86_load_seg(env, idx, 0);
6248 env->segs[idx].base = addr;
6249 break;
6250 case TARGET_ARCH_GET_GS:
6251 case TARGET_ARCH_GET_FS:
6252 if (code == TARGET_ARCH_GET_GS)
6253 idx = R_GS;
6254 else
6255 idx = R_FS;
6256 val = env->segs[idx].base;
6257 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006258 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006259 break;
6260 default:
6261 ret = -TARGET_EINVAL;
6262 break;
6263 }
Juan Quintela1add8692011-06-16 17:37:09 +01006264 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006265}
6266#endif
6267
bellard2ab83ea2003-06-15 19:56:46 +00006268#endif /* defined(TARGET_I386) */
6269
Riku Voipio05098a92011-03-04 15:27:29 +02006270#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006271
pbrookd865bab2008-06-07 22:12:17 +00006272
6273static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6274typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006275 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006276 pthread_mutex_t mutex;
6277 pthread_cond_t cond;
6278 pthread_t thread;
6279 uint32_t tid;
6280 abi_ulong child_tidptr;
6281 abi_ulong parent_tidptr;
6282 sigset_t sigmask;
6283} new_thread_info;
6284
6285static void *clone_func(void *arg)
6286{
6287 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006288 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006289 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006290 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006291
Emilio G. Cota70903762015-08-23 20:23:41 -04006292 rcu_register_thread();
Emilio G. Cota3468b592017-07-19 18:57:58 -04006293 tcg_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006294 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006295 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006296 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006297 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006298 info->tid = gettid();
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006299 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006300 if (info->child_tidptr)
6301 put_user_u32(info->tid, info->child_tidptr);
6302 if (info->parent_tidptr)
6303 put_user_u32(info->tid, info->parent_tidptr);
6304 /* Enable signals. */
6305 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6306 /* Signal to the parent that we're ready. */
6307 pthread_mutex_lock(&info->mutex);
6308 pthread_cond_broadcast(&info->cond);
6309 pthread_mutex_unlock(&info->mutex);
Emilio G. Cotaa4dd3d52017-10-18 18:01:41 -04006310 /* Wait until the parent has finished initializing the tls state. */
pbrookd865bab2008-06-07 22:12:17 +00006311 pthread_mutex_lock(&clone_lock);
6312 pthread_mutex_unlock(&clone_lock);
6313 cpu_loop(env);
6314 /* never exits */
6315 return NULL;
6316}
bellard1b6b0292003-03-22 17:31:38 +00006317
ths0da46a62007-10-20 20:23:07 +00006318/* do_fork() Must return host values and target errnos (unlike most
6319 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006320static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006321 abi_ulong parent_tidptr, target_ulong newtls,
6322 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006323{
Andreas Färber0429a972013-08-26 18:14:44 +02006324 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006325 int ret;
bellard5cd43932003-03-29 16:54:36 +00006326 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006327 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006328 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006329 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006330
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006331 flags &= ~CLONE_IGNORED_FLAGS;
6332
balrog436d1242008-09-21 02:39:45 +00006333 /* Emulate vfork() with fork() */
6334 if (flags & CLONE_VFORK)
6335 flags &= ~(CLONE_VFORK | CLONE_VM);
6336
bellard1b6b0292003-03-22 17:31:38 +00006337 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006338 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006339 new_thread_info info;
6340 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006341
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006342 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6343 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6344 return -TARGET_EINVAL;
6345 }
6346
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006347 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006348 init_task_state(ts);
Max Filippov73a988d2018-03-30 06:19:58 -07006349
6350 /* Grab a mutex so that thread setup appears atomic. */
6351 pthread_mutex_lock(&clone_lock);
6352
bellard1b6b0292003-03-22 17:31:38 +00006353 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006354 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006355 /* Init regs that differ from the parent. */
6356 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006357 new_cpu = ENV_GET_CPU(new_env);
6358 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006359 ts->bprm = parent_ts->bprm;
6360 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006361 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006362
Peter Maydell7cfbd382016-08-02 18:41:26 +01006363 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006364 ts->child_tidptr = child_tidptr;
6365 }
6366
Peter Maydell7cfbd382016-08-02 18:41:26 +01006367 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006368 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006369 }
pbrookd865bab2008-06-07 22:12:17 +00006370
pbrookd865bab2008-06-07 22:12:17 +00006371 memset(&info, 0, sizeof(info));
6372 pthread_mutex_init(&info.mutex, NULL);
6373 pthread_mutex_lock(&info.mutex);
6374 pthread_cond_init(&info.cond, NULL);
6375 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006376 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006377 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006378 }
6379 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006380 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006381 }
pbrookd865bab2008-06-07 22:12:17 +00006382
6383 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006384 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6385 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006386 /* It is not safe to deliver signals until the child has finished
6387 initializing, so temporarily block all signals. */
6388 sigfillset(&sigmask);
6389 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6390
Alex Bennéeb67cb682016-10-05 11:13:04 -07006391 /* If this is our first additional thread, we need to ensure we
6392 * generate code for parallel execution and flush old translations.
6393 */
6394 if (!parallel_cpus) {
6395 parallel_cpus = true;
6396 tb_flush(cpu);
6397 }
6398
pbrookd865bab2008-06-07 22:12:17 +00006399 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006400 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006401
6402 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6403 pthread_attr_destroy(&attr);
6404 if (ret == 0) {
6405 /* Wait for the child to initialize. */
6406 pthread_cond_wait(&info.cond, &info.mutex);
6407 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006408 } else {
6409 ret = -1;
6410 }
6411 pthread_mutex_unlock(&info.mutex);
6412 pthread_cond_destroy(&info.cond);
6413 pthread_mutex_destroy(&info.mutex);
6414 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006415 } else {
6416 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006417 if (flags & CLONE_INVALID_FORK_FLAGS) {
6418 return -TARGET_EINVAL;
6419 }
6420
6421 /* We can't support custom termination signals */
6422 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006423 return -TARGET_EINVAL;
6424 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006425
6426 if (block_signals()) {
6427 return -TARGET_ERESTARTSYS;
6428 }
6429
pbrookd865bab2008-06-07 22:12:17 +00006430 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006431 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006432 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006433 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00006434 cpu_clone_regs(env, newsp);
6435 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006436 /* There is a race condition here. The parent process could
6437 theoretically read the TID in the child process before the child
6438 tid is set. This would require using either ptrace
6439 (not implemented) or having *_tidptr to point at a shared memory
6440 mapping. We can't repeat the spinlock hack used above because
6441 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006442 if (flags & CLONE_CHILD_SETTID)
6443 put_user_u32(gettid(), child_tidptr);
6444 if (flags & CLONE_PARENT_SETTID)
6445 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006446 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006447 if (flags & CLONE_SETTLS)
6448 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006449 if (flags & CLONE_CHILD_CLEARTID)
6450 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006451 } else {
6452 fork_end(0);
6453 }
bellard1b6b0292003-03-22 17:31:38 +00006454 }
6455 return ret;
6456}
6457
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006458/* warning : doesn't handle linux specific flags... */
6459static int target_to_host_fcntl_cmd(int cmd)
6460{
6461 switch(cmd) {
6462 case TARGET_F_DUPFD:
6463 case TARGET_F_GETFD:
6464 case TARGET_F_SETFD:
6465 case TARGET_F_GETFL:
6466 case TARGET_F_SETFL:
6467 return cmd;
6468 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006469 return F_GETLK64;
6470 case TARGET_F_SETLK:
6471 return F_SETLK64;
6472 case TARGET_F_SETLKW:
6473 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006474 case TARGET_F_GETOWN:
6475 return F_GETOWN;
6476 case TARGET_F_SETOWN:
6477 return F_SETOWN;
6478 case TARGET_F_GETSIG:
6479 return F_GETSIG;
6480 case TARGET_F_SETSIG:
6481 return F_SETSIG;
6482#if TARGET_ABI_BITS == 32
6483 case TARGET_F_GETLK64:
6484 return F_GETLK64;
6485 case TARGET_F_SETLK64:
6486 return F_SETLK64;
6487 case TARGET_F_SETLKW64:
6488 return F_SETLKW64;
6489#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006490 case TARGET_F_SETLEASE:
6491 return F_SETLEASE;
6492 case TARGET_F_GETLEASE:
6493 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006494#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006495 case TARGET_F_DUPFD_CLOEXEC:
6496 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006497#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006498 case TARGET_F_NOTIFY:
6499 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006500#ifdef F_GETOWN_EX
6501 case TARGET_F_GETOWN_EX:
6502 return F_GETOWN_EX;
6503#endif
6504#ifdef F_SETOWN_EX
6505 case TARGET_F_SETOWN_EX:
6506 return F_SETOWN_EX;
6507#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006508#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006509 case TARGET_F_SETPIPE_SZ:
6510 return F_SETPIPE_SZ;
6511 case TARGET_F_GETPIPE_SZ:
6512 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006513#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006514 default:
6515 return -TARGET_EINVAL;
6516 }
6517 return -TARGET_EINVAL;
6518}
6519
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006520#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6521static const bitmask_transtbl flock_tbl[] = {
6522 TRANSTBL_CONVERT(F_RDLCK),
6523 TRANSTBL_CONVERT(F_WRLCK),
6524 TRANSTBL_CONVERT(F_UNLCK),
6525 TRANSTBL_CONVERT(F_EXLCK),
6526 TRANSTBL_CONVERT(F_SHLCK),
6527 { 0, 0, 0, 0 }
6528};
6529
Peter Maydell213d3e92016-06-13 11:22:05 +01006530static inline abi_long copy_from_user_flock(struct flock64 *fl,
6531 abi_ulong target_flock_addr)
6532{
6533 struct target_flock *target_fl;
6534 short l_type;
6535
6536 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6537 return -TARGET_EFAULT;
6538 }
6539
6540 __get_user(l_type, &target_fl->l_type);
6541 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6542 __get_user(fl->l_whence, &target_fl->l_whence);
6543 __get_user(fl->l_start, &target_fl->l_start);
6544 __get_user(fl->l_len, &target_fl->l_len);
6545 __get_user(fl->l_pid, &target_fl->l_pid);
6546 unlock_user_struct(target_fl, target_flock_addr, 0);
6547 return 0;
6548}
6549
6550static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6551 const struct flock64 *fl)
6552{
6553 struct target_flock *target_fl;
6554 short l_type;
6555
6556 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6557 return -TARGET_EFAULT;
6558 }
6559
6560 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6561 __put_user(l_type, &target_fl->l_type);
6562 __put_user(fl->l_whence, &target_fl->l_whence);
6563 __put_user(fl->l_start, &target_fl->l_start);
6564 __put_user(fl->l_len, &target_fl->l_len);
6565 __put_user(fl->l_pid, &target_fl->l_pid);
6566 unlock_user_struct(target_fl, target_flock_addr, 1);
6567 return 0;
6568}
6569
6570typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6571typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6572
6573#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6574static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6575 abi_ulong target_flock_addr)
6576{
6577 struct target_eabi_flock64 *target_fl;
6578 short l_type;
6579
6580 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6581 return -TARGET_EFAULT;
6582 }
6583
6584 __get_user(l_type, &target_fl->l_type);
6585 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6586 __get_user(fl->l_whence, &target_fl->l_whence);
6587 __get_user(fl->l_start, &target_fl->l_start);
6588 __get_user(fl->l_len, &target_fl->l_len);
6589 __get_user(fl->l_pid, &target_fl->l_pid);
6590 unlock_user_struct(target_fl, target_flock_addr, 0);
6591 return 0;
6592}
6593
6594static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6595 const struct flock64 *fl)
6596{
6597 struct target_eabi_flock64 *target_fl;
6598 short l_type;
6599
6600 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6601 return -TARGET_EFAULT;
6602 }
6603
6604 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6605 __put_user(l_type, &target_fl->l_type);
6606 __put_user(fl->l_whence, &target_fl->l_whence);
6607 __put_user(fl->l_start, &target_fl->l_start);
6608 __put_user(fl->l_len, &target_fl->l_len);
6609 __put_user(fl->l_pid, &target_fl->l_pid);
6610 unlock_user_struct(target_fl, target_flock_addr, 1);
6611 return 0;
6612}
6613#endif
6614
6615static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6616 abi_ulong target_flock_addr)
6617{
6618 struct target_flock64 *target_fl;
6619 short l_type;
6620
6621 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6622 return -TARGET_EFAULT;
6623 }
6624
6625 __get_user(l_type, &target_fl->l_type);
6626 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6627 __get_user(fl->l_whence, &target_fl->l_whence);
6628 __get_user(fl->l_start, &target_fl->l_start);
6629 __get_user(fl->l_len, &target_fl->l_len);
6630 __get_user(fl->l_pid, &target_fl->l_pid);
6631 unlock_user_struct(target_fl, target_flock_addr, 0);
6632 return 0;
6633}
6634
6635static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6636 const struct flock64 *fl)
6637{
6638 struct target_flock64 *target_fl;
6639 short l_type;
6640
6641 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6642 return -TARGET_EFAULT;
6643 }
6644
6645 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6646 __put_user(l_type, &target_fl->l_type);
6647 __put_user(fl->l_whence, &target_fl->l_whence);
6648 __put_user(fl->l_start, &target_fl->l_start);
6649 __put_user(fl->l_len, &target_fl->l_len);
6650 __put_user(fl->l_pid, &target_fl->l_pid);
6651 unlock_user_struct(target_fl, target_flock_addr, 1);
6652 return 0;
6653}
6654
blueswir1992f48a2007-10-14 16:27:31 +00006655static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006656{
ths43f238d2007-01-05 20:55:49 +00006657 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006658#ifdef F_GETOWN_EX
6659 struct f_owner_ex fox;
6660 struct target_f_owner_ex *target_fox;
6661#endif
blueswir1992f48a2007-10-14 16:27:31 +00006662 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006663 int host_cmd = target_to_host_fcntl_cmd(cmd);
6664
6665 if (host_cmd == -TARGET_EINVAL)
6666 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006667
bellard7775e9e2003-05-14 22:46:48 +00006668 switch(cmd) {
6669 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006670 ret = copy_from_user_flock(&fl64, arg);
6671 if (ret) {
6672 return ret;
6673 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006674 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006675 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006676 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006677 }
6678 break;
ths3b46e622007-09-17 08:09:54 +00006679
bellard7775e9e2003-05-14 22:46:48 +00006680 case TARGET_F_SETLK:
6681 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006682 ret = copy_from_user_flock(&fl64, arg);
6683 if (ret) {
6684 return ret;
6685 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006686 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006687 break;
ths3b46e622007-09-17 08:09:54 +00006688
bellard7775e9e2003-05-14 22:46:48 +00006689 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006690 ret = copy_from_user_flock64(&fl64, arg);
6691 if (ret) {
6692 return ret;
6693 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006694 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006695 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006696 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006697 }
bellard9ee1fa22007-11-11 15:11:19 +00006698 break;
bellard7775e9e2003-05-14 22:46:48 +00006699 case TARGET_F_SETLK64:
6700 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006701 ret = copy_from_user_flock64(&fl64, arg);
6702 if (ret) {
6703 return ret;
6704 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006705 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006706 break;
6707
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006708 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006709 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006710 if (ret >= 0) {
6711 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6712 }
bellardffa65c32004-01-04 23:57:22 +00006713 break;
6714
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006715 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006716 ret = get_errno(safe_fcntl(fd, host_cmd,
6717 target_to_host_bitmask(arg,
6718 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006719 break;
6720
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006721#ifdef F_GETOWN_EX
6722 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006723 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006724 if (ret >= 0) {
6725 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6726 return -TARGET_EFAULT;
6727 target_fox->type = tswap32(fox.type);
6728 target_fox->pid = tswap32(fox.pid);
6729 unlock_user_struct(target_fox, arg, 1);
6730 }
6731 break;
6732#endif
6733
6734#ifdef F_SETOWN_EX
6735 case TARGET_F_SETOWN_EX:
6736 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6737 return -TARGET_EFAULT;
6738 fox.type = tswap32(target_fox->type);
6739 fox.pid = tswap32(target_fox->pid);
6740 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006741 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006742 break;
6743#endif
6744
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006745 case TARGET_F_SETOWN:
6746 case TARGET_F_GETOWN:
6747 case TARGET_F_SETSIG:
6748 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006749 case TARGET_F_SETLEASE:
6750 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006751 case TARGET_F_SETPIPE_SZ:
6752 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006753 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006754 break;
6755
bellard7775e9e2003-05-14 22:46:48 +00006756 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006757 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006758 break;
6759 }
6760 return ret;
6761}
6762
bellard67867302003-11-23 17:05:30 +00006763#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006764
bellard67867302003-11-23 17:05:30 +00006765static inline int high2lowuid(int uid)
6766{
6767 if (uid > 65535)
6768 return 65534;
6769 else
6770 return uid;
6771}
6772
6773static inline int high2lowgid(int gid)
6774{
6775 if (gid > 65535)
6776 return 65534;
6777 else
6778 return gid;
6779}
6780
6781static inline int low2highuid(int uid)
6782{
6783 if ((int16_t)uid == -1)
6784 return -1;
6785 else
6786 return uid;
6787}
6788
6789static inline int low2highgid(int gid)
6790{
6791 if ((int16_t)gid == -1)
6792 return -1;
6793 else
6794 return gid;
6795}
Riku Voipio0c866a72011-04-18 15:23:06 +03006796static inline int tswapid(int id)
6797{
6798 return tswap16(id);
6799}
Peter Maydell76ca3102014-03-02 19:36:41 +00006800
6801#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6802
Riku Voipio0c866a72011-04-18 15:23:06 +03006803#else /* !USE_UID16 */
6804static inline int high2lowuid(int uid)
6805{
6806 return uid;
6807}
6808static inline int high2lowgid(int gid)
6809{
6810 return gid;
6811}
6812static inline int low2highuid(int uid)
6813{
6814 return uid;
6815}
6816static inline int low2highgid(int gid)
6817{
6818 return gid;
6819}
6820static inline int tswapid(int id)
6821{
6822 return tswap32(id);
6823}
Peter Maydell76ca3102014-03-02 19:36:41 +00006824
6825#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6826
bellard67867302003-11-23 17:05:30 +00006827#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006828
Peter Maydellfd6f7792016-03-01 16:33:02 +00006829/* We must do direct syscalls for setting UID/GID, because we want to
6830 * implement the Linux system call semantics of "change only for this thread",
6831 * not the libc/POSIX semantics of "change for all threads in process".
6832 * (See http://ewontfix.com/17/ for more details.)
6833 * We use the 32-bit version of the syscalls if present; if it is not
6834 * then either the host architecture supports 32-bit UIDs natively with
6835 * the standard syscall, or the 16-bit UID is the best we can do.
6836 */
6837#ifdef __NR_setuid32
6838#define __NR_sys_setuid __NR_setuid32
6839#else
6840#define __NR_sys_setuid __NR_setuid
6841#endif
6842#ifdef __NR_setgid32
6843#define __NR_sys_setgid __NR_setgid32
6844#else
6845#define __NR_sys_setgid __NR_setgid
6846#endif
6847#ifdef __NR_setresuid32
6848#define __NR_sys_setresuid __NR_setresuid32
6849#else
6850#define __NR_sys_setresuid __NR_setresuid
6851#endif
6852#ifdef __NR_setresgid32
6853#define __NR_sys_setresgid __NR_setresgid32
6854#else
6855#define __NR_sys_setresgid __NR_setresgid
6856#endif
6857
6858_syscall1(int, sys_setuid, uid_t, uid)
6859_syscall1(int, sys_setgid, gid_t, gid)
6860_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6861_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6862
bellard31e31b82003-02-18 22:55:36 +00006863void syscall_init(void)
6864{
bellard2ab83ea2003-06-15 19:56:46 +00006865 IOCTLEntry *ie;
6866 const argtype *arg_type;
6867 int size;
thsb92c47c2007-11-01 00:07:38 +00006868 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006869
Alexander Graf8be656b2015-05-06 23:47:32 +02006870 thunk_init(STRUCT_MAX);
6871
Blue Swirl001faf32009-05-13 17:53:17 +00006872#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006873#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006874#include "syscall_types.h"
6875#undef STRUCT
6876#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006877
Peter Maydelldd6e9572012-07-23 08:07:22 +00006878 /* Build target_to_host_errno_table[] table from
6879 * host_to_target_errno_table[]. */
6880 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6881 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6882 }
6883
bellard2ab83ea2003-06-15 19:56:46 +00006884 /* we patch the ioctl size if necessary. We rely on the fact that
6885 no ioctl has all the bits at '1' in the size field */
6886 ie = ioctl_entries;
6887 while (ie->target_cmd != 0) {
6888 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6889 TARGET_IOC_SIZEMASK) {
6890 arg_type = ie->arg_type;
6891 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006892 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006893 ie->target_cmd);
6894 exit(1);
6895 }
6896 arg_type++;
6897 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006898 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006899 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6900 (size << TARGET_IOC_SIZESHIFT);
6901 }
thsb92c47c2007-11-01 00:07:38 +00006902
bellard2ab83ea2003-06-15 19:56:46 +00006903 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006904#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6905 (defined(__x86_64__) && defined(TARGET_X86_64))
6906 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6907 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6908 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006909 }
6910#endif
6911 ie++;
6912 }
bellard31e31b82003-02-18 22:55:36 +00006913}
bellardc573ff62004-01-04 15:51:36 +00006914
blueswir1992f48a2007-10-14 16:27:31 +00006915#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006916static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6917{
thsaf325d32008-06-10 15:29:15 +00006918#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006919 return ((uint64_t)word0 << 32) | word1;
6920#else
6921 return ((uint64_t)word1 << 32) | word0;
6922#endif
6923}
blueswir1992f48a2007-10-14 16:27:31 +00006924#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006925static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6926{
6927 return word0;
6928}
blueswir1992f48a2007-10-14 16:27:31 +00006929#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006930
6931#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006932static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6933 abi_long arg2,
6934 abi_long arg3,
6935 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006936{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006937 if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006938 arg2 = arg3;
6939 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006940 }
pbrookce4defa2006-02-09 16:49:55 +00006941 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6942}
6943#endif
6944
6945#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006946static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6947 abi_long arg2,
6948 abi_long arg3,
6949 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006950{
James Clarke8bf8e9d2017-09-15 20:33:13 +01006951 if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
pbrookce4defa2006-02-09 16:49:55 +00006952 arg2 = arg3;
6953 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006954 }
pbrookce4defa2006-02-09 16:49:55 +00006955 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6956}
6957#endif
6958
bellard579a97f2007-11-11 14:26:47 +00006959static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6960 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006961{
6962 struct target_timespec *target_ts;
6963
bellard579a97f2007-11-11 14:26:47 +00006964 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6965 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006966 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6967 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006968 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006969 return 0;
pbrook53a59602006-03-25 19:31:22 +00006970}
6971
bellard579a97f2007-11-11 14:26:47 +00006972static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6973 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006974{
6975 struct target_timespec *target_ts;
6976
bellard579a97f2007-11-11 14:26:47 +00006977 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6978 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006979 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6980 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006981 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006982 return 0;
pbrook53a59602006-03-25 19:31:22 +00006983}
6984
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006985static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6986 abi_ulong target_addr)
6987{
6988 struct target_itimerspec *target_itspec;
6989
6990 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6991 return -TARGET_EFAULT;
6992 }
6993
6994 host_itspec->it_interval.tv_sec =
6995 tswapal(target_itspec->it_interval.tv_sec);
6996 host_itspec->it_interval.tv_nsec =
6997 tswapal(target_itspec->it_interval.tv_nsec);
6998 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6999 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
7000
7001 unlock_user_struct(target_itspec, target_addr, 1);
7002 return 0;
7003}
7004
7005static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
7006 struct itimerspec *host_its)
7007{
7008 struct target_itimerspec *target_itspec;
7009
7010 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
7011 return -TARGET_EFAULT;
7012 }
7013
7014 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
7015 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
7016
7017 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
7018 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
7019
7020 unlock_user_struct(target_itspec, target_addr, 0);
7021 return 0;
7022}
7023
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02007024static inline abi_long target_to_host_timex(struct timex *host_tx,
7025 abi_long target_addr)
7026{
7027 struct target_timex *target_tx;
7028
7029 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
7030 return -TARGET_EFAULT;
7031 }
7032
7033 __get_user(host_tx->modes, &target_tx->modes);
7034 __get_user(host_tx->offset, &target_tx->offset);
7035 __get_user(host_tx->freq, &target_tx->freq);
7036 __get_user(host_tx->maxerror, &target_tx->maxerror);
7037 __get_user(host_tx->esterror, &target_tx->esterror);
7038 __get_user(host_tx->status, &target_tx->status);
7039 __get_user(host_tx->constant, &target_tx->constant);
7040 __get_user(host_tx->precision, &target_tx->precision);
7041 __get_user(host_tx->tolerance, &target_tx->tolerance);
7042 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7043 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7044 __get_user(host_tx->tick, &target_tx->tick);
7045 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7046 __get_user(host_tx->jitter, &target_tx->jitter);
7047 __get_user(host_tx->shift, &target_tx->shift);
7048 __get_user(host_tx->stabil, &target_tx->stabil);
7049 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
7050 __get_user(host_tx->calcnt, &target_tx->calcnt);
7051 __get_user(host_tx->errcnt, &target_tx->errcnt);
7052 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
7053 __get_user(host_tx->tai, &target_tx->tai);
7054
7055 unlock_user_struct(target_tx, target_addr, 0);
7056 return 0;
7057}
7058
7059static inline abi_long host_to_target_timex(abi_long target_addr,
7060 struct timex *host_tx)
7061{
7062 struct target_timex *target_tx;
7063
7064 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
7065 return -TARGET_EFAULT;
7066 }
7067
7068 __put_user(host_tx->modes, &target_tx->modes);
7069 __put_user(host_tx->offset, &target_tx->offset);
7070 __put_user(host_tx->freq, &target_tx->freq);
7071 __put_user(host_tx->maxerror, &target_tx->maxerror);
7072 __put_user(host_tx->esterror, &target_tx->esterror);
7073 __put_user(host_tx->status, &target_tx->status);
7074 __put_user(host_tx->constant, &target_tx->constant);
7075 __put_user(host_tx->precision, &target_tx->precision);
7076 __put_user(host_tx->tolerance, &target_tx->tolerance);
7077 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
7078 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7079 __put_user(host_tx->tick, &target_tx->tick);
7080 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7081 __put_user(host_tx->jitter, &target_tx->jitter);
7082 __put_user(host_tx->shift, &target_tx->shift);
7083 __put_user(host_tx->stabil, &target_tx->stabil);
7084 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7085 __put_user(host_tx->calcnt, &target_tx->calcnt);
7086 __put_user(host_tx->errcnt, &target_tx->errcnt);
7087 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7088 __put_user(host_tx->tai, &target_tx->tai);
7089
7090 unlock_user_struct(target_tx, target_addr, 1);
7091 return 0;
7092}
7093
7094
Peter Maydellc0659762014-08-09 15:42:32 +01007095static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7096 abi_ulong target_addr)
7097{
7098 struct target_sigevent *target_sevp;
7099
7100 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7101 return -TARGET_EFAULT;
7102 }
7103
7104 /* This union is awkward on 64 bit systems because it has a 32 bit
7105 * integer and a pointer in it; we follow the conversion approach
7106 * used for handling sigval types in signal.c so the guest should get
7107 * the correct value back even if we did a 64 bit byteswap and it's
7108 * using the 32 bit integer.
7109 */
7110 host_sevp->sigev_value.sival_ptr =
7111 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7112 host_sevp->sigev_signo =
7113 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7114 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7115 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7116
7117 unlock_user_struct(target_sevp, target_addr, 1);
7118 return 0;
7119}
7120
Tom Musta6f6a4032014-08-12 13:53:42 -05007121#if defined(TARGET_NR_mlockall)
7122static inline int target_to_host_mlockall_arg(int arg)
7123{
7124 int result = 0;
7125
7126 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7127 result |= MCL_CURRENT;
7128 }
7129 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7130 result |= MCL_FUTURE;
7131 }
7132 return result;
7133}
7134#endif
7135
balrog6a24a772008-09-20 02:23:36 +00007136static inline abi_long host_to_target_stat64(void *cpu_env,
7137 abi_ulong target_addr,
7138 struct stat *host_st)
7139{
Alexander Graf09701192013-09-03 20:12:15 +01007140#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007141 if (((CPUARMState *)cpu_env)->eabi) {
7142 struct target_eabi_stat64 *target_st;
7143
7144 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7145 return -TARGET_EFAULT;
7146 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7147 __put_user(host_st->st_dev, &target_st->st_dev);
7148 __put_user(host_st->st_ino, &target_st->st_ino);
7149#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7150 __put_user(host_st->st_ino, &target_st->__st_ino);
7151#endif
7152 __put_user(host_st->st_mode, &target_st->st_mode);
7153 __put_user(host_st->st_nlink, &target_st->st_nlink);
7154 __put_user(host_st->st_uid, &target_st->st_uid);
7155 __put_user(host_st->st_gid, &target_st->st_gid);
7156 __put_user(host_st->st_rdev, &target_st->st_rdev);
7157 __put_user(host_st->st_size, &target_st->st_size);
7158 __put_user(host_st->st_blksize, &target_st->st_blksize);
7159 __put_user(host_st->st_blocks, &target_st->st_blocks);
7160 __put_user(host_st->st_atime, &target_st->target_st_atime);
7161 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7162 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7163 unlock_user_struct(target_st, target_addr, 1);
7164 } else
7165#endif
7166 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007167#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007168 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007169#else
7170 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007171#endif
balrog6a24a772008-09-20 02:23:36 +00007172
7173 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7174 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007175 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007176 __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 /* XXX: better use of kernel struct */
7187 __put_user(host_st->st_size, &target_st->st_size);
7188 __put_user(host_st->st_blksize, &target_st->st_blksize);
7189 __put_user(host_st->st_blocks, &target_st->st_blocks);
7190 __put_user(host_st->st_atime, &target_st->target_st_atime);
7191 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7192 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7193 unlock_user_struct(target_st, target_addr, 1);
7194 }
7195
7196 return 0;
7197}
balrog6a24a772008-09-20 02:23:36 +00007198
pbrookbd0c5662008-05-29 14:34:11 +00007199/* ??? Using host futex calls even when target atomic operations
7200 are not really atomic probably breaks things. However implementing
7201 futexes locally would make futexes shared between multiple processes
7202 tricky. However they're probably useless because guest atomic
7203 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007204static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7205 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007206{
7207 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007208 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007209
7210 /* ??? We assume FUTEX_* constants are the same on both host
7211 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007212#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007213 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007214#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007215 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007216#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007217 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007218 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007219 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007220 if (timeout) {
7221 pts = &ts;
7222 target_to_host_timespec(pts, timeout);
7223 } else {
7224 pts = NULL;
7225 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007226 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007227 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007228 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007229 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007230 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007231 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007232 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007233 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007234 case FUTEX_WAKE_OP:
7235 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7236 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7237 But the prototype takes a `struct timespec *'; insert casts
7238 to satisfy the compiler. We do not need to tswap TIMEOUT
7239 since it's not compared to guest memory. */
7240 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007241 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7242 g2h(uaddr2),
7243 (base_op == FUTEX_CMP_REQUEUE
7244 ? tswap32(val3)
7245 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007246 default:
7247 return -TARGET_ENOSYS;
7248 }
7249}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007250#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7251static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7252 abi_long handle, abi_long mount_id,
7253 abi_long flags)
7254{
7255 struct file_handle *target_fh;
7256 struct file_handle *fh;
7257 int mid = 0;
7258 abi_long ret;
7259 char *name;
7260 unsigned int size, total_size;
7261
7262 if (get_user_s32(size, handle)) {
7263 return -TARGET_EFAULT;
7264 }
7265
7266 name = lock_user_string(pathname);
7267 if (!name) {
7268 return -TARGET_EFAULT;
7269 }
7270
7271 total_size = sizeof(struct file_handle) + size;
7272 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7273 if (!target_fh) {
7274 unlock_user(name, pathname, 0);
7275 return -TARGET_EFAULT;
7276 }
7277
7278 fh = g_malloc0(total_size);
7279 fh->handle_bytes = size;
7280
7281 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7282 unlock_user(name, pathname, 0);
7283
7284 /* man name_to_handle_at(2):
7285 * Other than the use of the handle_bytes field, the caller should treat
7286 * the file_handle structure as an opaque data type
7287 */
7288
7289 memcpy(target_fh, fh, total_size);
7290 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7291 target_fh->handle_type = tswap32(fh->handle_type);
7292 g_free(fh);
7293 unlock_user(target_fh, handle, total_size);
7294
7295 if (put_user_s32(mid, mount_id)) {
7296 return -TARGET_EFAULT;
7297 }
7298
7299 return ret;
7300
7301}
7302#endif
7303
7304#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7305static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7306 abi_long flags)
7307{
7308 struct file_handle *target_fh;
7309 struct file_handle *fh;
7310 unsigned int size, total_size;
7311 abi_long ret;
7312
7313 if (get_user_s32(size, handle)) {
7314 return -TARGET_EFAULT;
7315 }
7316
7317 total_size = sizeof(struct file_handle) + size;
7318 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7319 if (!target_fh) {
7320 return -TARGET_EFAULT;
7321 }
7322
Thomas Huthe9d49d52015-10-09 17:56:38 +02007323 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007324 fh->handle_bytes = size;
7325 fh->handle_type = tswap32(target_fh->handle_type);
7326
7327 ret = get_errno(open_by_handle_at(mount_fd, fh,
7328 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7329
7330 g_free(fh);
7331
7332 unlock_user(target_fh, handle, total_size);
7333
7334 return ret;
7335}
7336#endif
pbrookbd0c5662008-05-29 14:34:11 +00007337
Laurent Viviere36800c2015-10-02 14:48:09 +02007338#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7339
7340/* signalfd siginfo conversion */
7341
7342static void
7343host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7344 const struct signalfd_siginfo *info)
7345{
7346 int sig = host_to_target_signal(info->ssi_signo);
7347
7348 /* linux/signalfd.h defines a ssi_addr_lsb
7349 * not defined in sys/signalfd.h but used by some kernels
7350 */
7351
7352#ifdef BUS_MCEERR_AO
7353 if (tinfo->ssi_signo == SIGBUS &&
7354 (tinfo->ssi_code == BUS_MCEERR_AR ||
7355 tinfo->ssi_code == BUS_MCEERR_AO)) {
7356 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7357 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7358 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7359 }
7360#endif
7361
7362 tinfo->ssi_signo = tswap32(sig);
7363 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7364 tinfo->ssi_code = tswap32(info->ssi_code);
7365 tinfo->ssi_pid = tswap32(info->ssi_pid);
7366 tinfo->ssi_uid = tswap32(info->ssi_uid);
7367 tinfo->ssi_fd = tswap32(info->ssi_fd);
7368 tinfo->ssi_tid = tswap32(info->ssi_tid);
7369 tinfo->ssi_band = tswap32(info->ssi_band);
7370 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7371 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7372 tinfo->ssi_status = tswap32(info->ssi_status);
7373 tinfo->ssi_int = tswap32(info->ssi_int);
7374 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7375 tinfo->ssi_utime = tswap64(info->ssi_utime);
7376 tinfo->ssi_stime = tswap64(info->ssi_stime);
7377 tinfo->ssi_addr = tswap64(info->ssi_addr);
7378}
7379
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007380static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007381{
7382 int i;
7383
7384 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7385 host_to_target_signalfd_siginfo(buf + i, buf + i);
7386 }
7387
7388 return len;
7389}
7390
7391static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007392 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007393};
7394
7395static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7396{
7397 int host_flags;
7398 target_sigset_t *target_mask;
7399 sigset_t host_mask;
7400 abi_long ret;
7401
7402 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7403 return -TARGET_EINVAL;
7404 }
7405 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7406 return -TARGET_EFAULT;
7407 }
7408
7409 target_to_host_sigset(&host_mask, target_mask);
7410
7411 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7412
7413 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7414 if (ret >= 0) {
7415 fd_trans_register(ret, &target_signalfd_trans);
7416 }
7417
7418 unlock_user_struct(target_mask, mask, 0);
7419
7420 return ret;
7421}
7422#endif
7423
pbrook1d9d8b52009-04-16 15:17:02 +00007424/* Map host to target signal numbers for the wait family of syscalls.
7425 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007426int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007427{
7428 if (WIFSIGNALED(status)) {
7429 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7430 }
7431 if (WIFSTOPPED(status)) {
7432 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7433 | (status & 0xff);
7434 }
7435 return status;
7436}
7437
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007438static int open_self_cmdline(void *cpu_env, int fd)
7439{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007440 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7441 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7442 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007443
Andreas Schwab58de8b92017-03-20 12:31:55 +01007444 for (i = 0; i < bprm->argc; i++) {
7445 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007446
Andreas Schwab58de8b92017-03-20 12:31:55 +01007447 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007448 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007449 }
7450 }
7451
Andreas Schwab58de8b92017-03-20 12:31:55 +01007452 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007453}
7454
Alexander Graf36c08d42011-11-02 20:23:24 +01007455static int open_self_maps(void *cpu_env, int fd)
7456{
Andreas Färber0429a972013-08-26 18:14:44 +02007457 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7458 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007459 FILE *fp;
7460 char *line = NULL;
7461 size_t len = 0;
7462 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007463
Alexander Graf1a49ef22012-05-01 16:30:28 +01007464 fp = fopen("/proc/self/maps", "r");
7465 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007466 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007467 }
7468
7469 while ((read = getline(&line, &len, fp)) != -1) {
7470 int fields, dev_maj, dev_min, inode;
7471 uint64_t min, max, offset;
7472 char flag_r, flag_w, flag_x, flag_p;
7473 char path[512] = "";
7474 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7475 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7476 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7477
7478 if ((fields < 10) || (fields > 11)) {
7479 continue;
7480 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007481 if (h2g_valid(min)) {
7482 int flags = page_get_flags(h2g(min));
Max Filippovebf9a362018-03-07 13:50:10 -08007483 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007484 if (page_check_range(h2g(min), max - min, flags) == -1) {
7485 continue;
7486 }
7487 if (h2g(min) == ts->info->stack_limit) {
7488 pstrcpy(path, sizeof(path), " [stack]");
7489 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007490 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007491 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007492 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007493 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007494 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007495 }
7496 }
7497
7498 free(line);
7499 fclose(fp);
7500
Alexander Graf36c08d42011-11-02 20:23:24 +01007501 return 0;
7502}
7503
Alexander Graf480b8e72011-11-02 20:23:25 +01007504static int open_self_stat(void *cpu_env, int fd)
7505{
Andreas Färber0429a972013-08-26 18:14:44 +02007506 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7507 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007508 abi_ulong start_stack = ts->info->start_stack;
7509 int i;
7510
7511 for (i = 0; i < 44; i++) {
7512 char buf[128];
7513 int len;
7514 uint64_t val = 0;
7515
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007516 if (i == 0) {
7517 /* pid */
7518 val = getpid();
7519 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7520 } else if (i == 1) {
7521 /* app name */
7522 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7523 } else if (i == 27) {
7524 /* stack bottom */
7525 val = start_stack;
7526 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7527 } else {
7528 /* for the rest, there is MasterCard */
7529 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007530 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007531
Alexander Graf480b8e72011-11-02 20:23:25 +01007532 len = strlen(buf);
7533 if (write(fd, buf, len) != len) {
7534 return -1;
7535 }
7536 }
7537
7538 return 0;
7539}
7540
Alexander Graf257450e2011-11-02 20:23:26 +01007541static int open_self_auxv(void *cpu_env, int fd)
7542{
Andreas Färber0429a972013-08-26 18:14:44 +02007543 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7544 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007545 abi_ulong auxv = ts->info->saved_auxv;
7546 abi_ulong len = ts->info->auxv_len;
7547 char *ptr;
7548
7549 /*
7550 * Auxiliary vector is stored in target process stack.
7551 * read in whole auxv vector and copy it to file
7552 */
7553 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7554 if (ptr != NULL) {
7555 while (len > 0) {
7556 ssize_t r;
7557 r = write(fd, ptr, len);
7558 if (r <= 0) {
7559 break;
7560 }
7561 len -= r;
7562 ptr += r;
7563 }
7564 lseek(fd, 0, SEEK_SET);
7565 unlock_user(ptr, auxv, len);
7566 }
7567
7568 return 0;
7569}
7570
Andreas Schwab463d8e72013-07-02 14:04:12 +01007571static int is_proc_myself(const char *filename, const char *entry)
7572{
7573 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7574 filename += strlen("/proc/");
7575 if (!strncmp(filename, "self/", strlen("self/"))) {
7576 filename += strlen("self/");
7577 } else if (*filename >= '1' && *filename <= '9') {
7578 char myself[80];
7579 snprintf(myself, sizeof(myself), "%d/", getpid());
7580 if (!strncmp(filename, myself, strlen(myself))) {
7581 filename += strlen(myself);
7582 } else {
7583 return 0;
7584 }
7585 } else {
7586 return 0;
7587 }
7588 if (!strcmp(filename, entry)) {
7589 return 1;
7590 }
7591 }
7592 return 0;
7593}
7594
Laurent Vivierde6b9932013-08-30 01:46:40 +02007595#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7596static int is_proc(const char *filename, const char *entry)
7597{
7598 return strcmp(filename, entry) == 0;
7599}
7600
7601static int open_net_route(void *cpu_env, int fd)
7602{
7603 FILE *fp;
7604 char *line = NULL;
7605 size_t len = 0;
7606 ssize_t read;
7607
7608 fp = fopen("/proc/net/route", "r");
7609 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007610 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007611 }
7612
7613 /* read header */
7614
7615 read = getline(&line, &len, fp);
7616 dprintf(fd, "%s", line);
7617
7618 /* read routes */
7619
7620 while ((read = getline(&line, &len, fp)) != -1) {
7621 char iface[16];
7622 uint32_t dest, gw, mask;
7623 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7624 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7625 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7626 &mask, &mtu, &window, &irtt);
7627 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7628 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7629 metric, tswap32(mask), mtu, window, irtt);
7630 }
7631
7632 free(line);
7633 fclose(fp);
7634
7635 return 0;
7636}
7637#endif
7638
Riku Voipio0b2effd2014-08-06 10:36:37 +03007639static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007640{
7641 struct fake_open {
7642 const char *filename;
7643 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007644 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007645 };
7646 const struct fake_open *fake_open;
7647 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007648 { "maps", open_self_maps, is_proc_myself },
7649 { "stat", open_self_stat, is_proc_myself },
7650 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007651 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007652#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7653 { "/proc/net/route", open_net_route, is_proc },
7654#endif
7655 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007656 };
7657
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007658 if (is_proc_myself(pathname, "exe")) {
7659 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007660 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007661 }
7662
Alexander Graf3be14d02011-11-02 20:23:23 +01007663 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007664 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007665 break;
7666 }
7667 }
7668
7669 if (fake_open->filename) {
7670 const char *tmpdir;
7671 char filename[PATH_MAX];
7672 int fd, r;
7673
7674 /* create temporary file to map stat to */
7675 tmpdir = getenv("TMPDIR");
7676 if (!tmpdir)
7677 tmpdir = "/tmp";
7678 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7679 fd = mkstemp(filename);
7680 if (fd < 0) {
7681 return fd;
7682 }
7683 unlink(filename);
7684
7685 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007686 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007687 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007688 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007689 return r;
7690 }
7691 lseek(fd, 0, SEEK_SET);
7692
7693 return fd;
7694 }
7695
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007696 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007697}
7698
Alexander Grafaecc8862014-11-10 21:33:03 +01007699#define TIMER_MAGIC 0x0caf0000
7700#define TIMER_MAGIC_MASK 0xffff0000
7701
7702/* Convert QEMU provided timer ID back to internal 16bit index format */
7703static target_timer_t get_timer_id(abi_long arg)
7704{
7705 target_timer_t timerid = arg;
7706
7707 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7708 return -TARGET_EINVAL;
7709 }
7710
7711 timerid &= 0xffff;
7712
7713 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7714 return -TARGET_EINVAL;
7715 }
7716
7717 return timerid;
7718}
7719
Laurent Vivier562a20b2017-03-01 10:37:48 +01007720static abi_long swap_data_eventfd(void *buf, size_t len)
7721{
7722 uint64_t *counter = buf;
7723 int i;
7724
7725 if (len < sizeof(uint64_t)) {
7726 return -EINVAL;
7727 }
7728
7729 for (i = 0; i < len; i += sizeof(uint64_t)) {
7730 *counter = tswap64(*counter);
7731 counter++;
7732 }
7733
7734 return len;
7735}
7736
7737static TargetFdTrans target_eventfd_trans = {
7738 .host_to_target_data = swap_data_eventfd,
7739 .target_to_host_data = swap_data_eventfd,
7740};
7741
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007742#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7743 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7744 defined(__NR_inotify_init1))
7745static abi_long host_to_target_data_inotify(void *buf, size_t len)
7746{
7747 struct inotify_event *ev;
7748 int i;
7749 uint32_t name_len;
7750
7751 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7752 ev = (struct inotify_event *)((char *)buf + i);
7753 name_len = ev->len;
7754
7755 ev->wd = tswap32(ev->wd);
7756 ev->mask = tswap32(ev->mask);
7757 ev->cookie = tswap32(ev->cookie);
7758 ev->len = tswap32(name_len);
7759 }
7760
7761 return len;
7762}
7763
7764static TargetFdTrans target_inotify_trans = {
7765 .host_to_target_data = host_to_target_data_inotify,
7766};
7767#endif
7768
Samuel Thibault2e0a8712018-01-09 21:16:43 +01007769static int target_to_host_cpu_mask(unsigned long *host_mask,
7770 size_t host_size,
7771 abi_ulong target_addr,
7772 size_t target_size)
7773{
7774 unsigned target_bits = sizeof(abi_ulong) * 8;
7775 unsigned host_bits = sizeof(*host_mask) * 8;
7776 abi_ulong *target_mask;
7777 unsigned i, j;
7778
7779 assert(host_size >= target_size);
7780
7781 target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
7782 if (!target_mask) {
7783 return -TARGET_EFAULT;
7784 }
7785 memset(host_mask, 0, host_size);
7786
7787 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7788 unsigned bit = i * target_bits;
7789 abi_ulong val;
7790
7791 __get_user(val, &target_mask[i]);
7792 for (j = 0; j < target_bits; j++, bit++) {
7793 if (val & (1UL << j)) {
7794 host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
7795 }
7796 }
7797 }
7798
7799 unlock_user(target_mask, target_addr, 0);
7800 return 0;
7801}
7802
7803static int host_to_target_cpu_mask(const unsigned long *host_mask,
7804 size_t host_size,
7805 abi_ulong target_addr,
7806 size_t target_size)
7807{
7808 unsigned target_bits = sizeof(abi_ulong) * 8;
7809 unsigned host_bits = sizeof(*host_mask) * 8;
7810 abi_ulong *target_mask;
7811 unsigned i, j;
7812
7813 assert(host_size >= target_size);
7814
7815 target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
7816 if (!target_mask) {
7817 return -TARGET_EFAULT;
7818 }
7819
7820 for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
7821 unsigned bit = i * target_bits;
7822 abi_ulong val = 0;
7823
7824 for (j = 0; j < target_bits; j++, bit++) {
7825 if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
7826 val |= 1UL << j;
7827 }
7828 }
7829 __put_user(val, &target_mask[i]);
7830 }
7831
7832 unlock_user(target_mask, target_addr, target_size);
7833 return 0;
7834}
7835
ths0da46a62007-10-20 20:23:07 +00007836/* do_syscall() should always have a single exit point at the end so
7837 that actions, such as logging of syscall results, can be performed.
7838 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007839abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7840 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007841 abi_long arg5, abi_long arg6, abi_long arg7,
7842 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007843{
Andreas Färber182735e2013-05-29 22:29:20 +02007844 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007845 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007846 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007847 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007848 void *p;
ths3b46e622007-09-17 08:09:54 +00007849
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007850#if defined(DEBUG_ERESTARTSYS)
7851 /* Debug-only code for exercising the syscall-restart code paths
7852 * in the per-architecture cpu main loops: restart every syscall
7853 * the guest makes once before letting it through.
7854 */
7855 {
7856 static int flag;
7857
7858 flag = !flag;
7859 if (flag) {
7860 return -TARGET_ERESTARTSYS;
7861 }
7862 }
7863#endif
7864
bellard72f03902003-02-18 23:33:18 +00007865#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007866 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007867#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007868 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007869 if(do_strace)
7870 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7871
bellard31e31b82003-02-18 22:55:36 +00007872 switch(num) {
7873 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007874 /* In old applications this may be used to implement _exit(2).
7875 However in threaded applictions it is used for thread termination,
7876 and _exit_group is used for application termination.
7877 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007878
7879 if (block_signals()) {
7880 ret = -TARGET_ERESTARTSYS;
7881 break;
7882 }
7883
Alex Bennéedd1f6342016-09-30 22:31:01 +01007884 cpu_list_lock();
7885
Andreas Färberbdc44642013-06-24 23:50:24 +02007886 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007887 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007888
Andreas Färber9b056fc2013-06-24 23:53:10 +02007889 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007890 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007891
Andreas Färber9b056fc2013-06-24 23:53:10 +02007892 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007893
Andreas Färber0429a972013-08-26 18:14:44 +02007894 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007895 if (ts->child_tidptr) {
7896 put_user_u32(0, ts->child_tidptr);
7897 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7898 NULL, NULL, 0);
7899 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007900 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007901 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007902 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007903 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007904 pthread_exit(NULL);
7905 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007906
7907 cpu_list_unlock();
Juan Quintela9788c9c2009-07-27 16:13:02 +02007908#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007909 _mcleanup();
7910#endif
bellarde9009672005-04-26 20:42:36 +00007911 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007912 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007913 ret = 0; /* avoid warning */
7914 break;
7915 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007916 if (arg3 == 0)
7917 ret = 0;
7918 else {
7919 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7920 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007921 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007922 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007923 fd_trans_host_to_target_data(arg1)) {
7924 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007925 }
aurel3238d840e2009-01-30 19:48:17 +00007926 unlock_user(p, arg2, ret);
7927 }
bellard31e31b82003-02-18 22:55:36 +00007928 break;
7929 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007930 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7931 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01007932 if (fd_trans_target_to_host_data(arg1)) {
7933 void *copy = g_malloc(arg3);
7934 memcpy(copy, p, arg3);
7935 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
7936 if (ret >= 0) {
7937 ret = get_errno(safe_write(arg1, copy, ret));
7938 }
7939 g_free(copy);
7940 } else {
7941 ret = get_errno(safe_write(arg1, p, arg3));
7942 }
pbrook53a59602006-03-25 19:31:22 +00007943 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007944 break;
Chen Gang704eff62015-08-21 05:37:33 +08007945#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007946 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007947 if (!(p = lock_user_string(arg1)))
7948 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007949 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7950 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7951 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007952 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007953 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007954 break;
Chen Gang704eff62015-08-21 05:37:33 +08007955#endif
ths82424832007-09-24 09:21:55 +00007956 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007957 if (!(p = lock_user_string(arg2)))
7958 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007959 ret = get_errno(do_openat(cpu_env, arg1, p,
7960 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7961 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007962 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007963 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007964 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007965#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7966 case TARGET_NR_name_to_handle_at:
7967 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7968 break;
7969#endif
7970#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7971 case TARGET_NR_open_by_handle_at:
7972 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007973 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007974 break;
7975#endif
bellard31e31b82003-02-18 22:55:36 +00007976 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007977 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007978 ret = get_errno(close(arg1));
7979 break;
7980 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007981 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007982 break;
Chen Gang704eff62015-08-21 05:37:33 +08007983#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007984 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01007985 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007986 break;
Chen Gang704eff62015-08-21 05:37:33 +08007987#endif
thse5febef2007-04-01 18:31:35 +00007988#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007989 case TARGET_NR_waitpid:
7990 {
pbrook53a59602006-03-25 19:31:22 +00007991 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007992 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007993 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007994 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007995 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007996 }
7997 break;
thse5febef2007-04-01 18:31:35 +00007998#endif
pbrookf0cbb612008-05-30 18:20:05 +00007999#ifdef TARGET_NR_waitid
8000 case TARGET_NR_waitid:
8001 {
8002 siginfo_t info;
8003 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008004 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00008005 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008006 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00008007 goto efault;
8008 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05008009 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00008010 }
8011 }
8012 break;
8013#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008014#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008015 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00008016 if (!(p = lock_user_string(arg1)))
8017 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008018 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008019 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00008020 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008021 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008022#endif
Chen Gang704eff62015-08-21 05:37:33 +08008023#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00008024 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00008025 {
8026 void * p2;
8027 p = lock_user_string(arg1);
8028 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008029 if (!p || !p2)
8030 ret = -TARGET_EFAULT;
8031 else
8032 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008033 unlock_user(p2, arg2, 0);
8034 unlock_user(p, arg1, 0);
8035 }
bellard31e31b82003-02-18 22:55:36 +00008036 break;
Chen Gang704eff62015-08-21 05:37:33 +08008037#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008038#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00008039 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00008040 {
8041 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00008042 if (!arg2 || !arg4)
8043 goto efault;
ths64f0ce42007-09-24 09:25:06 +00008044 p = lock_user_string(arg2);
8045 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008046 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008047 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00008048 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008049 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00008050 unlock_user(p, arg2, 0);
8051 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00008052 }
8053 break;
8054#endif
Chen Gang704eff62015-08-21 05:37:33 +08008055#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00008056 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00008057 if (!(p = lock_user_string(arg1)))
8058 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008059 ret = get_errno(unlink(p));
8060 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008061 break;
Chen Gang704eff62015-08-21 05:37:33 +08008062#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008063#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00008064 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00008065 if (!(p = lock_user_string(arg2)))
8066 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008067 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008068 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00008069 break;
balrogb7d35e62007-12-12 00:40:24 +00008070#endif
bellard31e31b82003-02-18 22:55:36 +00008071 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00008072 {
8073 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00008074 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00008075 abi_ulong gp;
8076 abi_ulong guest_argp;
8077 abi_ulong guest_envp;
8078 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00008079 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008080 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00008081
bellardf7341ff2003-03-30 21:00:25 +00008082 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00008083 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00008084 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008085 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008086 goto efault;
ths03aa1972007-12-02 06:28:08 +00008087 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008088 break;
bellard7854b052003-03-29 17:22:23 +00008089 argc++;
bellard2f619692007-11-16 10:46:05 +00008090 }
bellardf7341ff2003-03-30 21:00:25 +00008091 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00008092 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00008093 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00008094 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00008095 goto efault;
ths03aa1972007-12-02 06:28:08 +00008096 if (!addr)
bellard2f619692007-11-16 10:46:05 +00008097 break;
bellard7854b052003-03-29 17:22:23 +00008098 envc++;
bellard2f619692007-11-16 10:46:05 +00008099 }
bellard7854b052003-03-29 17:22:23 +00008100
Prasad J Panditb936cb52017-03-07 12:51:47 +05308101 argp = g_new0(char *, argc + 1);
8102 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00008103
pbrookda94d262008-05-30 18:24:00 +00008104 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008105 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008106 if (get_user_ual(addr, gp))
8107 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008108 if (!addr)
8109 break;
bellard2f619692007-11-16 10:46:05 +00008110 if (!(*q = lock_user_string(addr)))
8111 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008112 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008113 }
bellardf7341ff2003-03-30 21:00:25 +00008114 *q = NULL;
8115
pbrookda94d262008-05-30 18:24:00 +00008116 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00008117 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008118 if (get_user_ual(addr, gp))
8119 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00008120 if (!addr)
8121 break;
bellard2f619692007-11-16 10:46:05 +00008122 if (!(*q = lock_user_string(addr)))
8123 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01008124 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00008125 }
bellardf7341ff2003-03-30 21:00:25 +00008126 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00008127
bellard2f619692007-11-16 10:46:05 +00008128 if (!(p = lock_user_string(arg1)))
8129 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01008130 /* Although execve() is not an interruptible syscall it is
8131 * a special case where we must use the safe_syscall wrapper:
8132 * if we allow a signal to happen before we make the host
8133 * syscall then we will 'lose' it, because at the point of
8134 * execve the process leaves QEMU's control. So we use the
8135 * safe syscall wrapper to ensure that we either take the
8136 * signal as a guest signal, or else it does not happen
8137 * before the execve completes and makes it the other
8138 * program's problem.
8139 */
8140 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00008141 unlock_user(p, arg1, 0);
8142
bellard2f619692007-11-16 10:46:05 +00008143 goto execve_end;
8144
8145 execve_efault:
8146 ret = -TARGET_EFAULT;
8147
8148 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008149 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008150 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008151 if (get_user_ual(addr, gp)
8152 || !addr)
8153 break;
pbrook53a59602006-03-25 19:31:22 +00008154 unlock_user(*q, addr, 0);
8155 }
8156 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008157 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008158 if (get_user_ual(addr, gp)
8159 || !addr)
8160 break;
pbrook53a59602006-03-25 19:31:22 +00008161 unlock_user(*q, addr, 0);
8162 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308163
8164 g_free(argp);
8165 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008166 }
bellard31e31b82003-02-18 22:55:36 +00008167 break;
8168 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008169 if (!(p = lock_user_string(arg1)))
8170 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008171 ret = get_errno(chdir(p));
8172 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008173 break;
bellarda315a142005-01-30 22:59:18 +00008174#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008175 case TARGET_NR_time:
8176 {
pbrook53a59602006-03-25 19:31:22 +00008177 time_t host_time;
8178 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008179 if (!is_error(ret)
8180 && arg1
8181 && put_user_sal(host_time, arg1))
8182 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008183 }
8184 break;
bellarda315a142005-01-30 22:59:18 +00008185#endif
Chen Gang704eff62015-08-21 05:37:33 +08008186#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008187 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008188 if (!(p = lock_user_string(arg1)))
8189 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008190 ret = get_errno(mknod(p, arg2, arg3));
8191 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008192 break;
Chen Gang704eff62015-08-21 05:37:33 +08008193#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008194#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008195 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008196 if (!(p = lock_user_string(arg2)))
8197 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008198 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008199 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008200 break;
8201#endif
Chen Gang704eff62015-08-21 05:37:33 +08008202#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008203 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008204 if (!(p = lock_user_string(arg1)))
8205 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008206 ret = get_errno(chmod(p, arg2));
8207 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008208 break;
Chen Gang704eff62015-08-21 05:37:33 +08008209#endif
bellardebc05482003-09-30 21:08:41 +00008210#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008211 case TARGET_NR_break:
8212 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008213#endif
8214#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008215 case TARGET_NR_oldstat:
8216 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008217#endif
bellard31e31b82003-02-18 22:55:36 +00008218 case TARGET_NR_lseek:
8219 ret = get_errno(lseek(arg1, arg2, arg3));
8220 break;
Richard Henderson92317332010-05-03 10:07:53 -07008221#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8222 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008223 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008224 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008225 ret = get_errno(getpid());
8226 break;
Richard Henderson92317332010-05-03 10:07:53 -07008227#endif
8228#ifdef TARGET_NR_getpid
8229 case TARGET_NR_getpid:
8230 ret = get_errno(getpid());
8231 break;
8232#endif
bellard31e31b82003-02-18 22:55:36 +00008233 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008234 {
8235 /* need to look at the data field */
8236 void *p2, *p3;
8237
8238 if (arg1) {
8239 p = lock_user_string(arg1);
8240 if (!p) {
8241 goto efault;
8242 }
8243 } else {
8244 p = NULL;
8245 }
8246
8247 p2 = lock_user_string(arg2);
8248 if (!p2) {
8249 if (arg1) {
8250 unlock_user(p, arg1, 0);
8251 }
8252 goto efault;
8253 }
8254
8255 if (arg3) {
8256 p3 = lock_user_string(arg3);
8257 if (!p3) {
8258 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008259 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008260 }
8261 unlock_user(p2, arg2, 0);
8262 goto efault;
8263 }
8264 } else {
8265 p3 = NULL;
8266 }
8267
8268 /* FIXME - arg5 should be locked, but it isn't clear how to
8269 * do that since it's not guaranteed to be a NULL-terminated
8270 * string.
8271 */
8272 if (!arg5) {
8273 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8274 } else {
8275 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8276 }
8277 ret = get_errno(ret);
8278
8279 if (arg1) {
8280 unlock_user(p, arg1, 0);
8281 }
8282 unlock_user(p2, arg2, 0);
8283 if (arg3) {
8284 unlock_user(p3, arg3, 0);
8285 }
8286 }
8287 break;
thse5febef2007-04-01 18:31:35 +00008288#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008289 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008290 if (!(p = lock_user_string(arg1)))
8291 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008292 ret = get_errno(umount(p));
8293 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008294 break;
thse5febef2007-04-01 18:31:35 +00008295#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008296#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008297 case TARGET_NR_stime:
8298 {
pbrook53a59602006-03-25 19:31:22 +00008299 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008300 if (get_user_sal(host_time, arg1))
8301 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008302 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008303 }
8304 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008305#endif
bellard31e31b82003-02-18 22:55:36 +00008306 case TARGET_NR_ptrace:
8307 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008308#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008309 case TARGET_NR_alarm:
8310 ret = alarm(arg1);
8311 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008312#endif
bellardebc05482003-09-30 21:08:41 +00008313#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008314 case TARGET_NR_oldfstat:
8315 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008316#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008317#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008318 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008319 if (!block_signals()) {
8320 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8321 }
8322 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008323 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008324#endif
thse5febef2007-04-01 18:31:35 +00008325#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008326 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008327 {
pbrook53a59602006-03-25 19:31:22 +00008328 struct utimbuf tbuf, *host_tbuf;
8329 struct target_utimbuf *target_tbuf;
8330 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008331 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8332 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008333 tbuf.actime = tswapal(target_tbuf->actime);
8334 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008335 unlock_user_struct(target_tbuf, arg2, 0);
8336 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008337 } else {
pbrook53a59602006-03-25 19:31:22 +00008338 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008339 }
bellard579a97f2007-11-11 14:26:47 +00008340 if (!(p = lock_user_string(arg1)))
8341 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008342 ret = get_errno(utime(p, host_tbuf));
8343 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008344 }
8345 break;
thse5febef2007-04-01 18:31:35 +00008346#endif
Chen Gang704eff62015-08-21 05:37:33 +08008347#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008348 case TARGET_NR_utimes:
8349 {
bellard978a66f2004-12-06 22:58:05 +00008350 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008351 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008352 if (copy_from_user_timeval(&tv[0], arg2)
8353 || copy_from_user_timeval(&tv[1],
8354 arg2 + sizeof(struct target_timeval)))
8355 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008356 tvp = tv;
8357 } else {
8358 tvp = NULL;
8359 }
bellard579a97f2007-11-11 14:26:47 +00008360 if (!(p = lock_user_string(arg1)))
8361 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008362 ret = get_errno(utimes(p, tvp));
8363 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008364 }
8365 break;
Chen Gang704eff62015-08-21 05:37:33 +08008366#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008367#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008368 case TARGET_NR_futimesat:
8369 {
8370 struct timeval *tvp, tv[2];
8371 if (arg3) {
8372 if (copy_from_user_timeval(&tv[0], arg3)
8373 || copy_from_user_timeval(&tv[1],
8374 arg3 + sizeof(struct target_timeval)))
8375 goto efault;
8376 tvp = tv;
8377 } else {
8378 tvp = NULL;
8379 }
8380 if (!(p = lock_user_string(arg2)))
8381 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008382 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008383 unlock_user(p, arg2, 0);
8384 }
8385 break;
8386#endif
bellardebc05482003-09-30 21:08:41 +00008387#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008388 case TARGET_NR_stty:
8389 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008390#endif
8391#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008392 case TARGET_NR_gtty:
8393 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008394#endif
Chen Gang704eff62015-08-21 05:37:33 +08008395#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008396 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008397 if (!(p = lock_user_string(arg1)))
8398 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008399 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008400 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008401 break;
Chen Gang704eff62015-08-21 05:37:33 +08008402#endif
ths92a34c12007-09-24 09:27:49 +00008403#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8404 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008405 if (!(p = lock_user_string(arg2)))
8406 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008407 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008408 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008409 break;
8410#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008411#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008412 case TARGET_NR_nice:
8413 ret = get_errno(nice(arg1));
8414 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008415#endif
bellardebc05482003-09-30 21:08:41 +00008416#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008417 case TARGET_NR_ftime:
8418 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008419#endif
bellard31e31b82003-02-18 22:55:36 +00008420 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008421 sync();
8422 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008423 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008424#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8425 case TARGET_NR_syncfs:
8426 ret = get_errno(syncfs(arg1));
8427 break;
8428#endif
bellard31e31b82003-02-18 22:55:36 +00008429 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008430 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008431 break;
Chen Gang704eff62015-08-21 05:37:33 +08008432#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008433 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008434 {
8435 void *p2;
8436 p = lock_user_string(arg1);
8437 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008438 if (!p || !p2)
8439 ret = -TARGET_EFAULT;
8440 else
8441 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008442 unlock_user(p2, arg2, 0);
8443 unlock_user(p, arg1, 0);
8444 }
bellard31e31b82003-02-18 22:55:36 +00008445 break;
Chen Gang704eff62015-08-21 05:37:33 +08008446#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008447#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008448 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008449 {
bellard579a97f2007-11-11 14:26:47 +00008450 void *p2;
ths722183f2007-09-24 09:24:37 +00008451 p = lock_user_string(arg2);
8452 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008453 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008454 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008455 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008456 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008457 unlock_user(p2, arg4, 0);
8458 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008459 }
8460 break;
8461#endif
Andreas Schwab95d03072018-01-23 11:53:31 +01008462#if defined(TARGET_NR_renameat2)
8463 case TARGET_NR_renameat2:
8464 {
8465 void *p2;
8466 p = lock_user_string(arg2);
8467 p2 = lock_user_string(arg4);
8468 if (!p || !p2) {
8469 ret = -TARGET_EFAULT;
8470 } else {
8471 ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
8472 }
8473 unlock_user(p2, arg4, 0);
8474 unlock_user(p, arg2, 0);
8475 }
8476 break;
8477#endif
Chen Gang704eff62015-08-21 05:37:33 +08008478#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008479 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008480 if (!(p = lock_user_string(arg1)))
8481 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008482 ret = get_errno(mkdir(p, arg2));
8483 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008484 break;
Chen Gang704eff62015-08-21 05:37:33 +08008485#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008486#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008487 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008488 if (!(p = lock_user_string(arg2)))
8489 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008490 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008491 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008492 break;
8493#endif
Chen Gang704eff62015-08-21 05:37:33 +08008494#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008495 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008496 if (!(p = lock_user_string(arg1)))
8497 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008498 ret = get_errno(rmdir(p));
8499 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008500 break;
Chen Gang704eff62015-08-21 05:37:33 +08008501#endif
bellard31e31b82003-02-18 22:55:36 +00008502 case TARGET_NR_dup:
8503 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008504 if (ret >= 0) {
8505 fd_trans_dup(arg1, ret);
8506 }
bellard31e31b82003-02-18 22:55:36 +00008507 break;
Chen Gang704eff62015-08-21 05:37:33 +08008508#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008509 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008510 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008511 break;
Chen Gang704eff62015-08-21 05:37:33 +08008512#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008513#ifdef TARGET_NR_pipe2
8514 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008515 ret = do_pipe(cpu_env, arg1,
8516 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008517 break;
8518#endif
bellard31e31b82003-02-18 22:55:36 +00008519 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008520 {
pbrook53a59602006-03-25 19:31:22 +00008521 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008522 struct tms tms;
8523 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008524 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008525 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8526 if (!tmsp)
8527 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008528 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8529 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8530 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8531 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008532 }
bellardc596ed12003-07-13 17:32:31 +00008533 if (!is_error(ret))
8534 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008535 }
8536 break;
bellardebc05482003-09-30 21:08:41 +00008537#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008538 case TARGET_NR_prof:
8539 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008540#endif
thse5febef2007-04-01 18:31:35 +00008541#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008542 case TARGET_NR_signal:
8543 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008544#endif
bellard31e31b82003-02-18 22:55:36 +00008545 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008546 if (arg1 == 0) {
8547 ret = get_errno(acct(NULL));
8548 } else {
8549 if (!(p = lock_user_string(arg1)))
8550 goto efault;
8551 ret = get_errno(acct(path(p)));
8552 unlock_user(p, arg1, 0);
8553 }
pbrook24836682006-04-16 14:14:53 +00008554 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008555#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008556 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008557 if (!(p = lock_user_string(arg1)))
8558 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008559 ret = get_errno(umount2(p, arg2));
8560 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008561 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008562#endif
bellardebc05482003-09-30 21:08:41 +00008563#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008564 case TARGET_NR_lock:
8565 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008566#endif
bellard31e31b82003-02-18 22:55:36 +00008567 case TARGET_NR_ioctl:
8568 ret = do_ioctl(arg1, arg2, arg3);
8569 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008570#ifdef TARGET_NR_fcntl
bellard31e31b82003-02-18 22:55:36 +00008571 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008572 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008573 break;
Michael Clark47ae93c2018-03-03 01:31:11 +13008574#endif
bellardebc05482003-09-30 21:08:41 +00008575#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008576 case TARGET_NR_mpx:
8577 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008578#endif
bellard31e31b82003-02-18 22:55:36 +00008579 case TARGET_NR_setpgid:
8580 ret = get_errno(setpgid(arg1, arg2));
8581 break;
bellardebc05482003-09-30 21:08:41 +00008582#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008583 case TARGET_NR_ulimit:
8584 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008585#endif
8586#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008587 case TARGET_NR_oldolduname:
8588 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008589#endif
bellard31e31b82003-02-18 22:55:36 +00008590 case TARGET_NR_umask:
8591 ret = get_errno(umask(arg1));
8592 break;
8593 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008594 if (!(p = lock_user_string(arg1)))
8595 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008596 ret = get_errno(chroot(p));
8597 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008598 break;
Chen Gang704eff62015-08-21 05:37:33 +08008599#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008600 case TARGET_NR_ustat:
8601 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008602#endif
8603#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008604 case TARGET_NR_dup2:
8605 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008606 if (ret >= 0) {
8607 fd_trans_dup(arg1, arg2);
8608 }
bellard31e31b82003-02-18 22:55:36 +00008609 break;
Chen Gang704eff62015-08-21 05:37:33 +08008610#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008611#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8612 case TARGET_NR_dup3:
Peter Maydell10fa9932017-12-15 15:18:00 +00008613 {
8614 int host_flags;
8615
8616 if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
8617 return -EINVAL;
8618 }
8619 host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
8620 ret = get_errno(dup3(arg1, arg2, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02008621 if (ret >= 0) {
8622 fd_trans_dup(arg1, arg2);
8623 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008624 break;
Peter Maydell10fa9932017-12-15 15:18:00 +00008625 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008626#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008627#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008628 case TARGET_NR_getppid:
8629 ret = get_errno(getppid());
8630 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008631#endif
Chen Gang704eff62015-08-21 05:37:33 +08008632#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008633 case TARGET_NR_getpgrp:
8634 ret = get_errno(getpgrp());
8635 break;
Chen Gang704eff62015-08-21 05:37:33 +08008636#endif
bellard31e31b82003-02-18 22:55:36 +00008637 case TARGET_NR_setsid:
8638 ret = get_errno(setsid());
8639 break;
thse5febef2007-04-01 18:31:35 +00008640#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008641 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008642 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008643#if defined(TARGET_ALPHA)
8644 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008645 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008646 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008647 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8648 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008649 act._sa_handler = old_act->_sa_handler;
8650 target_siginitset(&act.sa_mask, old_act->sa_mask);
8651 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008652 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008653 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008654 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008655 }
8656 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008657 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008658 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8659 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008660 old_act->_sa_handler = oact._sa_handler;
8661 old_act->sa_mask = oact.sa_mask.sig[0];
8662 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008663 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008664 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008665#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008666 struct target_sigaction act, oact, *pact, *old_act;
8667
8668 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008669 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8670 goto efault;
bellard106ec872006-06-27 21:08:10 +00008671 act._sa_handler = old_act->_sa_handler;
8672 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8673 act.sa_flags = old_act->sa_flags;
8674 unlock_user_struct(old_act, arg2, 0);
8675 pact = &act;
8676 } else {
8677 pact = NULL;
8678 }
8679
8680 ret = get_errno(do_sigaction(arg1, pact, &oact));
8681
8682 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008683 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8684 goto efault;
bellard106ec872006-06-27 21:08:10 +00008685 old_act->_sa_handler = oact._sa_handler;
8686 old_act->sa_flags = oact.sa_flags;
8687 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8688 old_act->sa_mask.sig[1] = 0;
8689 old_act->sa_mask.sig[2] = 0;
8690 old_act->sa_mask.sig[3] = 0;
8691 unlock_user_struct(old_act, arg3, 1);
8692 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008693#else
8694 struct target_old_sigaction *old_act;
8695 struct target_sigaction act, oact, *pact;
8696 if (arg2) {
8697 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8698 goto efault;
8699 act._sa_handler = old_act->_sa_handler;
8700 target_siginitset(&act.sa_mask, old_act->sa_mask);
8701 act.sa_flags = old_act->sa_flags;
8702 act.sa_restorer = old_act->sa_restorer;
8703 unlock_user_struct(old_act, arg2, 0);
8704 pact = &act;
8705 } else {
8706 pact = NULL;
8707 }
8708 ret = get_errno(do_sigaction(arg1, pact, &oact));
8709 if (!is_error(ret) && arg3) {
8710 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8711 goto efault;
8712 old_act->_sa_handler = oact._sa_handler;
8713 old_act->sa_mask = oact.sa_mask.sig[0];
8714 old_act->sa_flags = oact.sa_flags;
8715 old_act->sa_restorer = oact.sa_restorer;
8716 unlock_user_struct(old_act, arg3, 1);
8717 }
ths388bb212007-05-13 13:58:00 +00008718#endif
bellard31e31b82003-02-18 22:55:36 +00008719 }
8720 break;
thse5febef2007-04-01 18:31:35 +00008721#endif
bellard66fb9762003-03-23 01:06:05 +00008722 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008723 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008724#if defined(TARGET_ALPHA)
Peter Maydell78bfef72017-11-06 18:33:26 +00008725 /* For Alpha and SPARC this is a 5 argument syscall, with
8726 * a 'restorer' parameter which must be copied into the
8727 * sa_restorer field of the sigaction struct.
8728 * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
8729 * and arg5 is the sigsetsize.
8730 * Alpha also has a separate rt_sigaction struct that it uses
8731 * here; SPARC uses the usual sigaction struct.
8732 */
Richard Henderson6049f4f2009-12-27 18:30:03 -08008733 struct target_rt_sigaction *rt_act;
Peter Maydell78bfef72017-11-06 18:33:26 +00008734 struct target_sigaction act, oact, *pact = 0;
Peter Maydellc8157012016-06-30 14:23:24 +01008735
8736 if (arg4 != sizeof(target_sigset_t)) {
8737 ret = -TARGET_EINVAL;
8738 break;
8739 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008740 if (arg2) {
8741 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8742 goto efault;
8743 act._sa_handler = rt_act->_sa_handler;
8744 act.sa_mask = rt_act->sa_mask;
8745 act.sa_flags = rt_act->sa_flags;
8746 act.sa_restorer = arg5;
8747 unlock_user_struct(rt_act, arg2, 0);
8748 pact = &act;
8749 }
8750 ret = get_errno(do_sigaction(arg1, pact, &oact));
8751 if (!is_error(ret) && arg3) {
8752 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8753 goto efault;
8754 rt_act->_sa_handler = oact._sa_handler;
8755 rt_act->sa_mask = oact.sa_mask;
8756 rt_act->sa_flags = oact.sa_flags;
8757 unlock_user_struct(rt_act, arg3, 1);
8758 }
8759#else
Peter Maydell78bfef72017-11-06 18:33:26 +00008760#ifdef TARGET_SPARC
8761 target_ulong restorer = arg4;
8762 target_ulong sigsetsize = arg5;
8763#else
8764 target_ulong sigsetsize = arg4;
8765#endif
pbrook53a59602006-03-25 19:31:22 +00008766 struct target_sigaction *act;
8767 struct target_sigaction *oact;
8768
Peter Maydell78bfef72017-11-06 18:33:26 +00008769 if (sigsetsize != sizeof(target_sigset_t)) {
Peter Maydellc8157012016-06-30 14:23:24 +01008770 ret = -TARGET_EINVAL;
8771 break;
8772 }
bellard579a97f2007-11-11 14:26:47 +00008773 if (arg2) {
Peter Maydell78bfef72017-11-06 18:33:26 +00008774 if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
bellard579a97f2007-11-11 14:26:47 +00008775 goto efault;
Peter Maydell78bfef72017-11-06 18:33:26 +00008776 }
8777#ifdef TARGET_SPARC
8778 act->sa_restorer = restorer;
8779#endif
8780 } else {
pbrook53a59602006-03-25 19:31:22 +00008781 act = NULL;
Peter Maydell78bfef72017-11-06 18:33:26 +00008782 }
bellard579a97f2007-11-11 14:26:47 +00008783 if (arg3) {
8784 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8785 ret = -TARGET_EFAULT;
8786 goto rt_sigaction_fail;
8787 }
8788 } else
pbrook53a59602006-03-25 19:31:22 +00008789 oact = NULL;
8790 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008791 rt_sigaction_fail:
8792 if (act)
pbrook53a59602006-03-25 19:31:22 +00008793 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008794 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008795 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008796#endif
pbrook53a59602006-03-25 19:31:22 +00008797 }
bellard66fb9762003-03-23 01:06:05 +00008798 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008799#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008800 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008801 {
8802 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008803 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008804 ret = do_sigprocmask(0, NULL, &cur_set);
8805 if (!ret) {
8806 host_to_target_old_sigset(&target_set, &cur_set);
8807 ret = target_set;
8808 }
bellard66fb9762003-03-23 01:06:05 +00008809 }
8810 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008811#endif
8812#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008813 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008814 {
Miloš Stojanovića8617d82017-05-15 16:59:43 +02008815 sigset_t set, oset;
blueswir1992f48a2007-10-14 16:27:31 +00008816 abi_ulong target_set = arg1;
bellard66fb9762003-03-23 01:06:05 +00008817 target_to_host_old_sigset(&set, &target_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008818 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8819 if (!ret) {
8820 host_to_target_old_sigset(&target_set, &oset);
8821 ret = target_set;
8822 }
bellard66fb9762003-03-23 01:06:05 +00008823 }
8824 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008825#endif
thse5febef2007-04-01 18:31:35 +00008826#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008827 case TARGET_NR_sigprocmask:
8828 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008829#if defined(TARGET_ALPHA)
8830 sigset_t set, oldset;
8831 abi_ulong mask;
8832 int how;
8833
8834 switch (arg1) {
8835 case TARGET_SIG_BLOCK:
8836 how = SIG_BLOCK;
8837 break;
8838 case TARGET_SIG_UNBLOCK:
8839 how = SIG_UNBLOCK;
8840 break;
8841 case TARGET_SIG_SETMASK:
8842 how = SIG_SETMASK;
8843 break;
8844 default:
8845 ret = -TARGET_EINVAL;
8846 goto fail;
8847 }
8848 mask = arg2;
8849 target_to_host_old_sigset(&set, &mask);
8850
Peter Maydell3d3efba2016-05-27 15:51:49 +01008851 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008852 if (!is_error(ret)) {
8853 host_to_target_old_sigset(&mask, &oldset);
8854 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008855 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008856 }
8857#else
bellard66fb9762003-03-23 01:06:05 +00008858 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008859 int how;
ths3b46e622007-09-17 08:09:54 +00008860
pbrook53a59602006-03-25 19:31:22 +00008861 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008862 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008863 case TARGET_SIG_BLOCK:
8864 how = SIG_BLOCK;
8865 break;
8866 case TARGET_SIG_UNBLOCK:
8867 how = SIG_UNBLOCK;
8868 break;
8869 case TARGET_SIG_SETMASK:
8870 how = SIG_SETMASK;
8871 break;
8872 default:
ths0da46a62007-10-20 20:23:07 +00008873 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008874 goto fail;
8875 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008876 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008877 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008878 target_to_host_old_sigset(&set, p);
8879 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008880 set_ptr = &set;
8881 } else {
8882 how = 0;
8883 set_ptr = NULL;
8884 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008885 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008886 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008887 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008888 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008889 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008890 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008891 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008892#endif
bellard66fb9762003-03-23 01:06:05 +00008893 }
8894 break;
thse5febef2007-04-01 18:31:35 +00008895#endif
bellard66fb9762003-03-23 01:06:05 +00008896 case TARGET_NR_rt_sigprocmask:
8897 {
8898 int how = arg1;
8899 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008900
Peter Maydellc8157012016-06-30 14:23:24 +01008901 if (arg4 != sizeof(target_sigset_t)) {
8902 ret = -TARGET_EINVAL;
8903 break;
8904 }
8905
pbrook53a59602006-03-25 19:31:22 +00008906 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008907 switch(how) {
8908 case TARGET_SIG_BLOCK:
8909 how = SIG_BLOCK;
8910 break;
8911 case TARGET_SIG_UNBLOCK:
8912 how = SIG_UNBLOCK;
8913 break;
8914 case TARGET_SIG_SETMASK:
8915 how = SIG_SETMASK;
8916 break;
8917 default:
ths0da46a62007-10-20 20:23:07 +00008918 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008919 goto fail;
8920 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008921 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008922 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008923 target_to_host_sigset(&set, p);
8924 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008925 set_ptr = &set;
8926 } else {
8927 how = 0;
8928 set_ptr = NULL;
8929 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008930 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008931 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008932 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008933 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008934 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008935 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008936 }
8937 }
8938 break;
thse5febef2007-04-01 18:31:35 +00008939#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008940 case TARGET_NR_sigpending:
8941 {
8942 sigset_t set;
8943 ret = get_errno(sigpending(&set));
8944 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008945 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008946 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008947 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008948 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008949 }
8950 }
8951 break;
thse5febef2007-04-01 18:31:35 +00008952#endif
bellard66fb9762003-03-23 01:06:05 +00008953 case TARGET_NR_rt_sigpending:
8954 {
8955 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008956
8957 /* Yes, this check is >, not != like most. We follow the kernel's
8958 * logic and it does it like this because it implements
8959 * NR_sigpending through the same code path, and in that case
8960 * the old_sigset_t is smaller in size.
8961 */
8962 if (arg2 > sizeof(target_sigset_t)) {
8963 ret = -TARGET_EINVAL;
8964 break;
8965 }
8966
bellard66fb9762003-03-23 01:06:05 +00008967 ret = get_errno(sigpending(&set));
8968 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008969 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008970 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008971 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008972 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008973 }
8974 }
8975 break;
thse5febef2007-04-01 18:31:35 +00008976#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008977 case TARGET_NR_sigsuspend:
8978 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008979 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008980#if defined(TARGET_ALPHA)
8981 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008982 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008983#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008984 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008985 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008986 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008987 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008988#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008989 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8990 SIGSET_T_SIZE));
8991 if (ret != -TARGET_ERESTARTSYS) {
8992 ts->in_sigsuspend = 1;
8993 }
bellard66fb9762003-03-23 01:06:05 +00008994 }
8995 break;
thse5febef2007-04-01 18:31:35 +00008996#endif
bellard66fb9762003-03-23 01:06:05 +00008997 case TARGET_NR_rt_sigsuspend:
8998 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008999 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01009000
9001 if (arg2 != sizeof(target_sigset_t)) {
9002 ret = -TARGET_EINVAL;
9003 break;
9004 }
Anthony Liguoric227f092009-10-01 16:12:16 -05009005 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009006 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01009007 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00009008 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009009 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
9010 SIGSET_T_SIZE));
9011 if (ret != -TARGET_ERESTARTSYS) {
9012 ts->in_sigsuspend = 1;
9013 }
bellard66fb9762003-03-23 01:06:05 +00009014 }
9015 break;
9016 case TARGET_NR_rt_sigtimedwait:
9017 {
bellard66fb9762003-03-23 01:06:05 +00009018 sigset_t set;
9019 struct timespec uts, *puts;
9020 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00009021
Peter Maydellc8157012016-06-30 14:23:24 +01009022 if (arg4 != sizeof(target_sigset_t)) {
9023 ret = -TARGET_EINVAL;
9024 break;
9025 }
9026
Anthony Liguoric227f092009-10-01 16:12:16 -05009027 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00009028 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009029 target_to_host_sigset(&set, p);
9030 unlock_user(p, arg1, 0);
9031 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00009032 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00009033 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00009034 } else {
9035 puts = NULL;
9036 }
Peter Maydellb3f82332016-06-06 19:58:08 +01009037 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
9038 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01009039 if (!is_error(ret)) {
9040 if (arg2) {
9041 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
9042 0);
9043 if (!p) {
9044 goto efault;
9045 }
9046 host_to_target_siginfo(p, &uinfo);
9047 unlock_user(p, arg2, sizeof(target_siginfo_t));
9048 }
9049 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00009050 }
9051 }
9052 break;
9053 case TARGET_NR_rt_sigqueueinfo:
9054 {
9055 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01009056
9057 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
9058 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00009059 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01009060 }
pbrook53a59602006-03-25 19:31:22 +00009061 target_to_host_siginfo(&uinfo, p);
Miloš Stojanovićd8b6d892017-05-15 16:59:44 +02009062 unlock_user(p, arg3, 0);
bellard66fb9762003-03-23 01:06:05 +00009063 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
9064 }
9065 break;
Miloš Stojanovićcf8b8bf2017-05-15 16:59:46 +02009066 case TARGET_NR_rt_tgsigqueueinfo:
9067 {
9068 siginfo_t uinfo;
9069
9070 p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
9071 if (!p) {
9072 goto efault;
9073 }
9074 target_to_host_siginfo(&uinfo, p);
9075 unlock_user(p, arg4, 0);
9076 ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
9077 }
9078 break;
thse5febef2007-04-01 18:31:35 +00009079#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00009080 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009081 if (block_signals()) {
9082 ret = -TARGET_ERESTARTSYS;
9083 } else {
9084 ret = do_sigreturn(cpu_env);
9085 }
bellard66fb9762003-03-23 01:06:05 +00009086 break;
thse5febef2007-04-01 18:31:35 +00009087#endif
bellard66fb9762003-03-23 01:06:05 +00009088 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01009089 if (block_signals()) {
9090 ret = -TARGET_ERESTARTSYS;
9091 } else {
9092 ret = do_rt_sigreturn(cpu_env);
9093 }
bellard66fb9762003-03-23 01:06:05 +00009094 break;
bellard31e31b82003-02-18 22:55:36 +00009095 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00009096 if (!(p = lock_user_string(arg1)))
9097 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009098 ret = get_errno(sethostname(p, arg2));
9099 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009100 break;
9101 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00009102 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009103 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009104 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009105 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00009106 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
9107 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009108 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
9109 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009110 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00009111 ret = get_errno(setrlimit(resource, &rlim));
9112 }
9113 break;
bellard31e31b82003-02-18 22:55:36 +00009114 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00009115 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009116 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00009117 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00009118 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00009119
bellard9de5e442003-03-23 16:49:39 +00009120 ret = get_errno(getrlimit(resource, &rlim));
9121 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009122 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9123 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009124 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9125 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009126 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00009127 }
9128 }
9129 break;
bellard31e31b82003-02-18 22:55:36 +00009130 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00009131 {
9132 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00009133 ret = get_errno(getrusage(arg1, &rusage));
9134 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02009135 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00009136 }
9137 }
9138 break;
bellard31e31b82003-02-18 22:55:36 +00009139 case TARGET_NR_gettimeofday:
9140 {
bellard31e31b82003-02-18 22:55:36 +00009141 struct timeval tv;
9142 ret = get_errno(gettimeofday(&tv, NULL));
9143 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00009144 if (copy_to_user_timeval(arg1, &tv))
9145 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009146 }
9147 }
9148 break;
9149 case TARGET_NR_settimeofday:
9150 {
Paul Burtonb67d8032014-06-22 11:25:41 +01009151 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01009152 struct timezone tz, *ptz = NULL;
9153
Paul Burtonb67d8032014-06-22 11:25:41 +01009154 if (arg1) {
9155 if (copy_from_user_timeval(&tv, arg1)) {
9156 goto efault;
9157 }
9158 ptv = &tv;
9159 }
Paul Burtonef4467e2014-06-22 11:25:40 +01009160
9161 if (arg2) {
9162 if (copy_from_user_timezone(&tz, arg2)) {
9163 goto efault;
9164 }
9165 ptz = &tz;
9166 }
9167
Paul Burtonb67d8032014-06-22 11:25:41 +01009168 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00009169 }
9170 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009171#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00009172 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02009173#if defined(TARGET_WANT_NI_OLD_SELECT)
9174 /* some architectures used to have old_select here
9175 * but now ENOSYS it.
9176 */
9177 ret = -TARGET_ENOSYS;
9178#elif defined(TARGET_WANT_OLD_SYS_SELECT)
9179 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009180#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02009181 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009182#endif
bellardf2674e32003-07-09 12:26:09 +00009183 break;
bellard048f6b42005-11-26 18:47:20 +00009184#endif
Riku Voipio9e423822010-05-07 12:28:05 +00009185#ifdef TARGET_NR_pselect6
9186 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04009187 {
9188 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
9189 fd_set rfds, wfds, efds;
9190 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
9191 struct timespec ts, *ts_ptr;
9192
9193 /*
9194 * The 6th arg is actually two args smashed together,
9195 * so we cannot use the C library.
9196 */
9197 sigset_t set;
9198 struct {
9199 sigset_t *set;
9200 size_t size;
9201 } sig, *sig_ptr;
9202
9203 abi_ulong arg_sigset, arg_sigsize, *arg7;
9204 target_sigset_t *target_sigset;
9205
9206 n = arg1;
9207 rfd_addr = arg2;
9208 wfd_addr = arg3;
9209 efd_addr = arg4;
9210 ts_addr = arg5;
9211
9212 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9213 if (ret) {
9214 goto fail;
9215 }
9216 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9217 if (ret) {
9218 goto fail;
9219 }
9220 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9221 if (ret) {
9222 goto fail;
9223 }
9224
9225 /*
9226 * This takes a timespec, and not a timeval, so we cannot
9227 * use the do_select() helper ...
9228 */
9229 if (ts_addr) {
9230 if (target_to_host_timespec(&ts, ts_addr)) {
9231 goto efault;
9232 }
9233 ts_ptr = &ts;
9234 } else {
9235 ts_ptr = NULL;
9236 }
9237
9238 /* Extract the two packed args for the sigset */
9239 if (arg6) {
9240 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009241 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009242
9243 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9244 if (!arg7) {
9245 goto efault;
9246 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009247 arg_sigset = tswapal(arg7[0]);
9248 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009249 unlock_user(arg7, arg6, 0);
9250
9251 if (arg_sigset) {
9252 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009253 if (arg_sigsize != sizeof(*target_sigset)) {
9254 /* Like the kernel, we enforce correct size sigsets */
9255 ret = -TARGET_EINVAL;
9256 goto fail;
9257 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009258 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9259 sizeof(*target_sigset), 1);
9260 if (!target_sigset) {
9261 goto efault;
9262 }
9263 target_to_host_sigset(&set, target_sigset);
9264 unlock_user(target_sigset, arg_sigset, 0);
9265 } else {
9266 sig.set = NULL;
9267 }
9268 } else {
9269 sig_ptr = NULL;
9270 }
9271
Peter Maydell6df9d382016-05-12 18:47:51 +01009272 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9273 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009274
9275 if (!is_error(ret)) {
9276 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9277 goto efault;
9278 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9279 goto efault;
9280 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9281 goto efault;
9282
9283 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9284 goto efault;
9285 }
9286 }
9287 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009288#endif
Chen Gang704eff62015-08-21 05:37:33 +08009289#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009290 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009291 {
9292 void *p2;
9293 p = lock_user_string(arg1);
9294 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009295 if (!p || !p2)
9296 ret = -TARGET_EFAULT;
9297 else
9298 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009299 unlock_user(p2, arg2, 0);
9300 unlock_user(p, arg1, 0);
9301 }
bellard31e31b82003-02-18 22:55:36 +00009302 break;
Chen Gang704eff62015-08-21 05:37:33 +08009303#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009304#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009305 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009306 {
bellard579a97f2007-11-11 14:26:47 +00009307 void *p2;
thsf0b62432007-09-24 09:25:40 +00009308 p = lock_user_string(arg1);
9309 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009310 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009311 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009312 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009313 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009314 unlock_user(p2, arg3, 0);
9315 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009316 }
9317 break;
9318#endif
bellardebc05482003-09-30 21:08:41 +00009319#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009320 case TARGET_NR_oldlstat:
9321 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009322#endif
Chen Gang704eff62015-08-21 05:37:33 +08009323#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009324 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009325 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009326 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009327 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009328 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009329 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009330 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009331 } else if (!arg3) {
9332 /* Short circuit this for the magic exe check. */
9333 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009334 } else if (is_proc_myself((const char *)p, "exe")) {
9335 char real[PATH_MAX], *temp;
9336 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009337 /* Return value is # of bytes that we wrote to the buffer. */
9338 if (temp == NULL) {
9339 ret = get_errno(-1);
9340 } else {
9341 /* Don't worry about sign mismatch as earlier mapping
9342 * logic would have thrown a bad address error. */
9343 ret = MIN(strlen(real), arg3);
9344 /* We cannot NUL terminate the string. */
9345 memcpy(p2, real, ret);
9346 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009347 } else {
9348 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009349 }
pbrook53a59602006-03-25 19:31:22 +00009350 unlock_user(p2, arg2, ret);
9351 unlock_user(p, arg1, 0);
9352 }
bellard31e31b82003-02-18 22:55:36 +00009353 break;
Chen Gang704eff62015-08-21 05:37:33 +08009354#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009355#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009356 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009357 {
bellard579a97f2007-11-11 14:26:47 +00009358 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009359 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009360 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009361 if (!p || !p2) {
9362 ret = -TARGET_EFAULT;
9363 } else if (is_proc_myself((const char *)p, "exe")) {
9364 char real[PATH_MAX], *temp;
9365 temp = realpath(exec_path, real);
9366 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9367 snprintf((char *)p2, arg4, "%s", real);
9368 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009369 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009370 }
bellard579a97f2007-11-11 14:26:47 +00009371 unlock_user(p2, arg3, ret);
9372 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009373 }
9374 break;
9375#endif
thse5febef2007-04-01 18:31:35 +00009376#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009377 case TARGET_NR_uselib:
9378 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009379#endif
9380#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009381 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009382 if (!(p = lock_user_string(arg1)))
9383 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009384 ret = get_errno(swapon(p, arg2));
9385 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009386 break;
thse5febef2007-04-01 18:31:35 +00009387#endif
bellard31e31b82003-02-18 22:55:36 +00009388 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009389 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9390 /* arg4 must be ignored in all other cases */
9391 p = lock_user_string(arg4);
9392 if (!p) {
9393 goto efault;
9394 }
9395 ret = get_errno(reboot(arg1, arg2, arg3, p));
9396 unlock_user(p, arg4, 0);
9397 } else {
9398 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9399 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009400 break;
thse5febef2007-04-01 18:31:35 +00009401#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009402 case TARGET_NR_readdir:
9403 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009404#endif
9405#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009406 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009407#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9408 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009409 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9410 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009411 {
blueswir1992f48a2007-10-14 16:27:31 +00009412 abi_ulong *v;
9413 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009414 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9415 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009416 v1 = tswapal(v[0]);
9417 v2 = tswapal(v[1]);
9418 v3 = tswapal(v[2]);
9419 v4 = tswapal(v[3]);
9420 v5 = tswapal(v[4]);
9421 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009422 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009423 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009424 target_to_host_bitmask(v4, mmap_flags_tbl),
9425 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009426 }
bellard31e31b82003-02-18 22:55:36 +00009427#else
ths5fafdf22007-09-16 21:08:06 +00009428 ret = get_errno(target_mmap(arg1, arg2, arg3,
9429 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009430 arg5,
9431 arg6));
bellard31e31b82003-02-18 22:55:36 +00009432#endif
bellard6fb883e2003-07-09 17:12:39 +00009433 break;
thse5febef2007-04-01 18:31:35 +00009434#endif
bellarda315a142005-01-30 22:59:18 +00009435#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009436 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009437#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009438#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009439#endif
ths5fafdf22007-09-16 21:08:06 +00009440 ret = get_errno(target_mmap(arg1, arg2, arg3,
9441 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009442 arg5,
bellardc573ff62004-01-04 15:51:36 +00009443 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009444 break;
bellarda315a142005-01-30 22:59:18 +00009445#endif
bellard31e31b82003-02-18 22:55:36 +00009446 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009447 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009448 break;
bellard9de5e442003-03-23 16:49:39 +00009449 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009450 {
Andreas Färber0429a972013-08-26 18:14:44 +02009451 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009452 /* Special hack to detect libc making the stack executable. */
9453 if ((arg3 & PROT_GROWSDOWN)
9454 && arg1 >= ts->info->stack_limit
9455 && arg1 <= ts->info->start_stack) {
9456 arg3 &= ~PROT_GROWSDOWN;
9457 arg2 = arg2 + arg1 - ts->info->stack_limit;
9458 arg1 = ts->info->stack_limit;
9459 }
9460 }
bellard54936002003-05-13 00:25:15 +00009461 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009462 break;
thse5febef2007-04-01 18:31:35 +00009463#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009464 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009465 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009466 break;
thse5febef2007-04-01 18:31:35 +00009467#endif
pbrook53a59602006-03-25 19:31:22 +00009468 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009469#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009470 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009471 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009472 break;
thse5febef2007-04-01 18:31:35 +00009473#endif
9474#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009475 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009476 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009477 break;
thse5febef2007-04-01 18:31:35 +00009478#endif
9479#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009480 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009481 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009482 break;
thse5febef2007-04-01 18:31:35 +00009483#endif
9484#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009485 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009486 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009487 break;
thse5febef2007-04-01 18:31:35 +00009488#endif
9489#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009490 case TARGET_NR_munlockall:
9491 ret = get_errno(munlockall());
9492 break;
thse5febef2007-04-01 18:31:35 +00009493#endif
bellard31e31b82003-02-18 22:55:36 +00009494 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009495 if (!(p = lock_user_string(arg1)))
9496 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009497 ret = get_errno(truncate(p, arg2));
9498 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009499 break;
9500 case TARGET_NR_ftruncate:
9501 ret = get_errno(ftruncate(arg1, arg2));
9502 break;
9503 case TARGET_NR_fchmod:
9504 ret = get_errno(fchmod(arg1, arg2));
9505 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009506#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009507 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009508 if (!(p = lock_user_string(arg2)))
9509 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009510 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009511 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009512 break;
9513#endif
bellard31e31b82003-02-18 22:55:36 +00009514 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009515 /* Note that negative values are valid for getpriority, so we must
9516 differentiate based on errno settings. */
9517 errno = 0;
9518 ret = getpriority(arg1, arg2);
9519 if (ret == -1 && errno != 0) {
9520 ret = -host_to_target_errno(errno);
9521 break;
9522 }
9523#ifdef TARGET_ALPHA
9524 /* Return value is the unbiased priority. Signal no error. */
9525 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9526#else
9527 /* Return value is a biased priority to avoid negative numbers. */
9528 ret = 20 - ret;
9529#endif
bellard31e31b82003-02-18 22:55:36 +00009530 break;
9531 case TARGET_NR_setpriority:
9532 ret = get_errno(setpriority(arg1, arg2, arg3));
9533 break;
bellardebc05482003-09-30 21:08:41 +00009534#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009535 case TARGET_NR_profil:
9536 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009537#endif
bellard31e31b82003-02-18 22:55:36 +00009538 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009539 if (!(p = lock_user_string(arg1)))
9540 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009541 ret = get_errno(statfs(path(p), &stfs));
9542 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009543 convert_statfs:
9544 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009545 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009546
bellard579a97f2007-11-11 14:26:47 +00009547 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9548 goto efault;
9549 __put_user(stfs.f_type, &target_stfs->f_type);
9550 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9551 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9552 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9553 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9554 __put_user(stfs.f_files, &target_stfs->f_files);
9555 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9556 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9557 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9558 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009559 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
Shea Levyd4247ec2018-03-01 06:15:00 -05009560#ifdef _STATFS_F_FLAGS
9561 __put_user(stfs.f_flags, &target_stfs->f_flags);
9562#else
9563 __put_user(0, &target_stfs->f_flags);
9564#endif
Alexander Graf229d3372012-09-19 04:39:53 +02009565 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009566 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009567 }
9568 break;
9569 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009570 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009571 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009572#ifdef TARGET_NR_statfs64
9573 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009574 if (!(p = lock_user_string(arg1)))
9575 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009576 ret = get_errno(statfs(path(p), &stfs));
9577 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009578 convert_statfs64:
9579 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009580 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009581
bellard579a97f2007-11-11 14:26:47 +00009582 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9583 goto efault;
9584 __put_user(stfs.f_type, &target_stfs->f_type);
9585 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9586 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9587 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9588 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9589 __put_user(stfs.f_files, &target_stfs->f_files);
9590 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9591 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9592 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9593 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009594 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9595 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009596 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009597 }
9598 break;
9599 case TARGET_NR_fstatfs64:
9600 ret = get_errno(fstatfs(arg1, &stfs));
9601 goto convert_statfs64;
9602#endif
bellardebc05482003-09-30 21:08:41 +00009603#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009604 case TARGET_NR_ioperm:
9605 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009606#endif
thse5febef2007-04-01 18:31:35 +00009607#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009608 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009609 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009610 break;
thse5febef2007-04-01 18:31:35 +00009611#endif
bellard3532fa72006-06-24 15:06:03 +00009612#ifdef TARGET_NR_accept
9613 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009614 ret = do_accept4(arg1, arg2, arg3, 0);
9615 break;
9616#endif
9617#ifdef TARGET_NR_accept4
9618 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009619 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009620 break;
9621#endif
9622#ifdef TARGET_NR_bind
9623 case TARGET_NR_bind:
9624 ret = do_bind(arg1, arg2, arg3);
9625 break;
9626#endif
9627#ifdef TARGET_NR_connect
9628 case TARGET_NR_connect:
9629 ret = do_connect(arg1, arg2, arg3);
9630 break;
9631#endif
9632#ifdef TARGET_NR_getpeername
9633 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009634 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009635 break;
9636#endif
9637#ifdef TARGET_NR_getsockname
9638 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009639 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009640 break;
9641#endif
9642#ifdef TARGET_NR_getsockopt
9643 case TARGET_NR_getsockopt:
9644 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9645 break;
9646#endif
9647#ifdef TARGET_NR_listen
9648 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009649 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009650 break;
9651#endif
9652#ifdef TARGET_NR_recv
9653 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009654 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009655 break;
9656#endif
9657#ifdef TARGET_NR_recvfrom
9658 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009659 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009660 break;
9661#endif
9662#ifdef TARGET_NR_recvmsg
9663 case TARGET_NR_recvmsg:
9664 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9665 break;
9666#endif
9667#ifdef TARGET_NR_send
9668 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009669 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009670 break;
9671#endif
9672#ifdef TARGET_NR_sendmsg
9673 case TARGET_NR_sendmsg:
9674 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9675 break;
9676#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009677#ifdef TARGET_NR_sendmmsg
9678 case TARGET_NR_sendmmsg:
9679 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9680 break;
9681 case TARGET_NR_recvmmsg:
9682 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9683 break;
9684#endif
bellard3532fa72006-06-24 15:06:03 +00009685#ifdef TARGET_NR_sendto
9686 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009687 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009688 break;
9689#endif
9690#ifdef TARGET_NR_shutdown
9691 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009692 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009693 break;
9694#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009695#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9696 case TARGET_NR_getrandom:
9697 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9698 if (!p) {
9699 goto efault;
9700 }
9701 ret = get_errno(getrandom(p, arg2, arg3));
9702 unlock_user(p, arg1, ret);
9703 break;
9704#endif
bellard3532fa72006-06-24 15:06:03 +00009705#ifdef TARGET_NR_socket
9706 case TARGET_NR_socket:
9707 ret = do_socket(arg1, arg2, arg3);
9708 break;
9709#endif
9710#ifdef TARGET_NR_socketpair
9711 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009712 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009713 break;
9714#endif
9715#ifdef TARGET_NR_setsockopt
9716 case TARGET_NR_setsockopt:
9717 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9718 break;
9719#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009720#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009721 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009722 {
9723 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009724
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009725 switch (arg1) {
9726 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9727 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9728 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9729 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9730 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9731 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9732 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9733 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9734 {
9735 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9736 }
9737 break;
9738 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9739 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9740 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9741 {
9742 ret = -TARGET_EINVAL;
9743 if (len < 0) {
9744 goto fail;
9745 }
9746 ret = 0;
9747 if (len == 0) {
9748 break;
9749 }
9750 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9751 if (!p) {
9752 ret = -TARGET_EFAULT;
9753 goto fail;
9754 }
9755 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9756 unlock_user(p, arg2, arg3);
9757 }
9758 break;
9759 default:
9760 ret = -EINVAL;
9761 break;
9762 }
9763 }
9764 break;
9765#endif
bellard31e31b82003-02-18 22:55:36 +00009766 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009767 {
bellard66fb9762003-03-23 01:06:05 +00009768 struct itimerval value, ovalue, *pvalue;
9769
pbrook53a59602006-03-25 19:31:22 +00009770 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009771 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009772 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9773 || copy_from_user_timeval(&pvalue->it_value,
9774 arg2 + sizeof(struct target_timeval)))
9775 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009776 } else {
9777 pvalue = NULL;
9778 }
9779 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009780 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009781 if (copy_to_user_timeval(arg3,
9782 &ovalue.it_interval)
9783 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9784 &ovalue.it_value))
9785 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009786 }
9787 }
9788 break;
bellard31e31b82003-02-18 22:55:36 +00009789 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009790 {
bellard66fb9762003-03-23 01:06:05 +00009791 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009792
bellard66fb9762003-03-23 01:06:05 +00009793 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009794 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009795 if (copy_to_user_timeval(arg2,
9796 &value.it_interval)
9797 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9798 &value.it_value))
9799 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009800 }
9801 }
9802 break;
Chen Gang704eff62015-08-21 05:37:33 +08009803#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009804 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009805 if (!(p = lock_user_string(arg1)))
9806 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009807 ret = get_errno(stat(path(p), &st));
9808 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009809 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009810#endif
9811#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009812 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009813 if (!(p = lock_user_string(arg1)))
9814 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009815 ret = get_errno(lstat(path(p), &st));
9816 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009817 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009818#endif
bellard31e31b82003-02-18 22:55:36 +00009819 case TARGET_NR_fstat:
9820 {
9821 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009822#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009823 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009824#endif
bellard31e31b82003-02-18 22:55:36 +00009825 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009826 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009827
bellard579a97f2007-11-11 14:26:47 +00009828 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9829 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009830 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009831 __put_user(st.st_dev, &target_st->st_dev);
9832 __put_user(st.st_ino, &target_st->st_ino);
9833 __put_user(st.st_mode, &target_st->st_mode);
9834 __put_user(st.st_uid, &target_st->st_uid);
9835 __put_user(st.st_gid, &target_st->st_gid);
9836 __put_user(st.st_nlink, &target_st->st_nlink);
9837 __put_user(st.st_rdev, &target_st->st_rdev);
9838 __put_user(st.st_size, &target_st->st_size);
9839 __put_user(st.st_blksize, &target_st->st_blksize);
9840 __put_user(st.st_blocks, &target_st->st_blocks);
9841 __put_user(st.st_atime, &target_st->target_st_atime);
9842 __put_user(st.st_mtime, &target_st->target_st_mtime);
9843 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009844 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009845 }
9846 }
9847 break;
bellardebc05482003-09-30 21:08:41 +00009848#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009849 case TARGET_NR_olduname:
9850 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009851#endif
9852#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009853 case TARGET_NR_iopl:
9854 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009855#endif
bellard31e31b82003-02-18 22:55:36 +00009856 case TARGET_NR_vhangup:
9857 ret = get_errno(vhangup());
9858 break;
bellardebc05482003-09-30 21:08:41 +00009859#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009860 case TARGET_NR_idle:
9861 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009862#endif
bellard42ad6ae2005-01-03 22:48:11 +00009863#ifdef TARGET_NR_syscall
9864 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009865 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9866 arg6, arg7, arg8, 0);
9867 break;
bellard42ad6ae2005-01-03 22:48:11 +00009868#endif
bellard31e31b82003-02-18 22:55:36 +00009869 case TARGET_NR_wait4:
9870 {
9871 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009872 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009873 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009874 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009875 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009876 if (target_rusage)
9877 rusage_ptr = &rusage;
9878 else
9879 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009880 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009881 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009882 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009883 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009884 if (put_user_s32(status, status_ptr))
9885 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009886 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009887 if (target_rusage) {
9888 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9889 if (rusage_err) {
9890 ret = rusage_err;
9891 }
9892 }
bellard31e31b82003-02-18 22:55:36 +00009893 }
9894 }
9895 break;
thse5febef2007-04-01 18:31:35 +00009896#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009897 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009898 if (!(p = lock_user_string(arg1)))
9899 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009900 ret = get_errno(swapoff(p));
9901 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009902 break;
thse5febef2007-04-01 18:31:35 +00009903#endif
bellard31e31b82003-02-18 22:55:36 +00009904 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009905 {
pbrook53a59602006-03-25 19:31:22 +00009906 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009907 struct sysinfo value;
9908 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009909 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009910 {
bellard579a97f2007-11-11 14:26:47 +00009911 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9912 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009913 __put_user(value.uptime, &target_value->uptime);
9914 __put_user(value.loads[0], &target_value->loads[0]);
9915 __put_user(value.loads[1], &target_value->loads[1]);
9916 __put_user(value.loads[2], &target_value->loads[2]);
9917 __put_user(value.totalram, &target_value->totalram);
9918 __put_user(value.freeram, &target_value->freeram);
9919 __put_user(value.sharedram, &target_value->sharedram);
9920 __put_user(value.bufferram, &target_value->bufferram);
9921 __put_user(value.totalswap, &target_value->totalswap);
9922 __put_user(value.freeswap, &target_value->freeswap);
9923 __put_user(value.procs, &target_value->procs);
9924 __put_user(value.totalhigh, &target_value->totalhigh);
9925 __put_user(value.freehigh, &target_value->freehigh);
9926 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009927 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009928 }
9929 }
9930 break;
thse5febef2007-04-01 18:31:35 +00009931#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009932 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +01009933 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
9934 break;
thse5febef2007-04-01 18:31:35 +00009935#endif
aurel32e5289082009-04-18 16:16:12 +00009936#ifdef TARGET_NR_semget
9937 case TARGET_NR_semget:
9938 ret = get_errno(semget(arg1, arg2, arg3));
9939 break;
9940#endif
9941#ifdef TARGET_NR_semop
9942 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009943 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009944 break;
9945#endif
9946#ifdef TARGET_NR_semctl
9947 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009948 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009949 break;
9950#endif
aurel32eeb438c2008-10-13 21:08:55 +00009951#ifdef TARGET_NR_msgctl
9952 case TARGET_NR_msgctl:
9953 ret = do_msgctl(arg1, arg2, arg3);
9954 break;
9955#endif
9956#ifdef TARGET_NR_msgget
9957 case TARGET_NR_msgget:
9958 ret = get_errno(msgget(arg1, arg2));
9959 break;
9960#endif
9961#ifdef TARGET_NR_msgrcv
9962 case TARGET_NR_msgrcv:
9963 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9964 break;
9965#endif
9966#ifdef TARGET_NR_msgsnd
9967 case TARGET_NR_msgsnd:
9968 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9969 break;
9970#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009971#ifdef TARGET_NR_shmget
9972 case TARGET_NR_shmget:
9973 ret = get_errno(shmget(arg1, arg2, arg3));
9974 break;
9975#endif
9976#ifdef TARGET_NR_shmctl
9977 case TARGET_NR_shmctl:
9978 ret = do_shmctl(arg1, arg2, arg3);
9979 break;
9980#endif
9981#ifdef TARGET_NR_shmat
9982 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +01009983 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009984 break;
9985#endif
9986#ifdef TARGET_NR_shmdt
9987 case TARGET_NR_shmdt:
9988 ret = do_shmdt(arg1);
9989 break;
9990#endif
bellard31e31b82003-02-18 22:55:36 +00009991 case TARGET_NR_fsync:
9992 ret = get_errno(fsync(arg1));
9993 break;
bellard31e31b82003-02-18 22:55:36 +00009994 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009995 /* Linux manages to have three different orderings for its
9996 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9997 * match the kernel's CONFIG_CLONE_* settings.
9998 * Microblaze is further special in that it uses a sixth
9999 * implicit argument to clone for the TLS pointer.
10000 */
10001#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +020010002 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +010010003#elif defined(TARGET_CLONE_BACKWARDS)
10004 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
10005#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +020010006 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010007#else
Peter Maydell4ce62432013-07-16 18:44:57 +010010008 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +000010009#endif
bellard1b6b0292003-03-22 17:31:38 +000010010 break;
bellardec86b0f2003-04-11 00:15:04 +000010011#ifdef __NR_exit_group
10012 /* new thread calls */
10013 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +020010014#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000010015 _mcleanup();
10016#endif
bellarde9009672005-04-26 20:42:36 +000010017 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +000010018 ret = get_errno(exit_group(arg1));
10019 break;
10020#endif
bellard31e31b82003-02-18 22:55:36 +000010021 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +000010022 if (!(p = lock_user_string(arg1)))
10023 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010024 ret = get_errno(setdomainname(p, arg2));
10025 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +000010026 break;
10027 case TARGET_NR_uname:
10028 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +000010029 {
10030 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +000010031
bellard579a97f2007-11-11 14:26:47 +000010032 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
10033 goto efault;
bellard29e619b2004-09-13 21:41:04 +000010034 ret = get_errno(sys_uname(buf));
10035 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +010010036 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +000010037 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +010010038 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +000010039 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +010010040 if (qemu_uname_release && *qemu_uname_release) {
10041 g_strlcpy(buf->release, qemu_uname_release,
10042 sizeof(buf->release));
10043 }
bellard29e619b2004-09-13 21:41:04 +000010044 }
pbrook53a59602006-03-25 19:31:22 +000010045 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +000010046 }
bellard31e31b82003-02-18 22:55:36 +000010047 break;
bellard6dbad632003-03-16 18:05:05 +000010048#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +000010049 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +000010050 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +000010051 break;
j_mayer84409dd2007-04-06 08:56:50 +000010052#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +000010053 case TARGET_NR_vm86old:
10054 goto unimplemented;
10055 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +000010056 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +000010057 break;
10058#endif
j_mayer84409dd2007-04-06 08:56:50 +000010059#endif
bellard31e31b82003-02-18 22:55:36 +000010060 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +020010061 {
10062 struct timex host_buf;
10063
10064 if (target_to_host_timex(&host_buf, arg1) != 0) {
10065 goto efault;
10066 }
10067 ret = get_errno(adjtimex(&host_buf));
10068 if (!is_error(ret)) {
10069 if (host_to_target_timex(arg1, &host_buf) != 0) {
10070 goto efault;
10071 }
10072 }
10073 }
10074 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +020010075#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
10076 case TARGET_NR_clock_adjtime:
10077 {
10078 struct timex htx, *phtx = &htx;
10079
10080 if (target_to_host_timex(phtx, arg2) != 0) {
10081 goto efault;
10082 }
10083 ret = get_errno(clock_adjtime(arg1, phtx));
10084 if (!is_error(ret) && phtx) {
10085 if (host_to_target_timex(arg2, phtx) != 0) {
10086 goto efault;
10087 }
10088 }
10089 }
10090 break;
10091#endif
thse5febef2007-04-01 18:31:35 +000010092#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +000010093 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +000010094#endif
bellard31e31b82003-02-18 22:55:36 +000010095 case TARGET_NR_init_module:
10096 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +000010097#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +000010098 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +000010099#endif
bellard31e31b82003-02-18 22:55:36 +000010100 goto unimplemented;
10101 case TARGET_NR_quotactl:
10102 goto unimplemented;
10103 case TARGET_NR_getpgid:
10104 ret = get_errno(getpgid(arg1));
10105 break;
10106 case TARGET_NR_fchdir:
10107 ret = get_errno(fchdir(arg1));
10108 break;
j_mayer84409dd2007-04-06 08:56:50 +000010109#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +000010110 case TARGET_NR_bdflush:
10111 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +000010112#endif
thse5febef2007-04-01 18:31:35 +000010113#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +000010114 case TARGET_NR_sysfs:
10115 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010116#endif
bellard31e31b82003-02-18 22:55:36 +000010117 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +000010118 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +000010119 break;
thse5febef2007-04-01 18:31:35 +000010120#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +000010121 case TARGET_NR_afs_syscall:
10122 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010123#endif
j_mayer7a3148a2007-04-05 07:13:51 +000010124#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +000010125 case TARGET_NR__llseek:
10126 {
10127 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +000010128#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +010010129 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +000010130 if (res == -1) {
10131 ret = get_errno(res);
10132 } else {
10133 ret = 0;
10134 }
10135#else
bellard31e31b82003-02-18 22:55:36 +000010136 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +000010137#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +000010138 if ((ret == 0) && put_user_s64(res, arg4)) {
10139 goto efault;
10140 }
bellard31e31b82003-02-18 22:55:36 +000010141 }
10142 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010143#endif
Chen Gang704eff62015-08-21 05:37:33 +080010144#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +000010145 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +010010146#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +020010147#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +000010148 {
pbrook53a59602006-03-25 19:31:22 +000010149 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +000010150 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010151 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +000010152
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010153 dirp = g_try_malloc(count);
10154 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +000010155 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +000010156 goto fail;
10157 }
ths3b46e622007-09-17 08:09:54 +000010158
bellard4add45b2003-06-05 01:52:59 +000010159 ret = get_errno(sys_getdents(arg1, dirp, count));
10160 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010161 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +000010162 struct target_dirent *tde;
10163 int len = ret;
10164 int reclen, treclen;
10165 int count1, tnamelen;
10166
10167 count1 = 0;
10168 de = dirp;
bellard579a97f2007-11-11 14:26:47 +000010169 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10170 goto efault;
bellard4add45b2003-06-05 01:52:59 +000010171 tde = target_dirp;
10172 while (len > 0) {
10173 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010174 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
10175 assert(tnamelen >= 0);
10176 treclen = tnamelen + offsetof(struct target_dirent, d_name);
10177 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +000010178 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +020010179 tde->d_ino = tswapal(de->d_ino);
10180 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +040010181 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +000010182 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +000010183 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +000010184 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +000010185 count1 += treclen;
10186 }
10187 ret = count1;
bellard579a97f2007-11-11 14:26:47 +000010188 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +000010189 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +053010190 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +000010191 }
10192#else
bellard31e31b82003-02-18 22:55:36 +000010193 {
aurel326556a832008-10-13 21:08:17 +000010194 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010195 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +000010196
bellard579a97f2007-11-11 14:26:47 +000010197 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10198 goto efault;
bellard72f03902003-02-18 23:33:18 +000010199 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +000010200 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010201 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010202 int len = ret;
10203 int reclen;
10204 de = dirp;
10205 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010206 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010207 if (reclen > len)
10208 break;
bellard8083a3e2003-03-24 23:12:16 +000010209 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010210 tswapls(&de->d_ino);
10211 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010212 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010213 len -= reclen;
10214 }
10215 }
pbrook53a59602006-03-25 19:31:22 +000010216 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010217 }
bellard4add45b2003-06-05 01:52:59 +000010218#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010219#else
10220 /* Implement getdents in terms of getdents64 */
10221 {
10222 struct linux_dirent64 *dirp;
10223 abi_long count = arg3;
10224
10225 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10226 if (!dirp) {
10227 goto efault;
10228 }
10229 ret = get_errno(sys_getdents64(arg1, dirp, count));
10230 if (!is_error(ret)) {
10231 /* Convert the dirent64 structs to target dirent. We do this
10232 * in-place, since we can guarantee that a target_dirent is no
10233 * larger than a dirent64; however this means we have to be
10234 * careful to read everything before writing in the new format.
10235 */
10236 struct linux_dirent64 *de;
10237 struct target_dirent *tde;
10238 int len = ret;
10239 int tlen = 0;
10240
10241 de = dirp;
10242 tde = (struct target_dirent *)dirp;
10243 while (len > 0) {
10244 int namelen, treclen;
10245 int reclen = de->d_reclen;
10246 uint64_t ino = de->d_ino;
10247 int64_t off = de->d_off;
10248 uint8_t type = de->d_type;
10249
10250 namelen = strlen(de->d_name);
10251 treclen = offsetof(struct target_dirent, d_name)
10252 + namelen + 2;
10253 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10254
10255 memmove(tde->d_name, de->d_name, namelen + 1);
10256 tde->d_ino = tswapal(ino);
10257 tde->d_off = tswapal(off);
10258 tde->d_reclen = tswap16(treclen);
10259 /* The target_dirent type is in what was formerly a padding
10260 * byte at the end of the structure:
10261 */
10262 *(((char *)tde) + treclen - 1) = type;
10263
10264 de = (struct linux_dirent64 *)((char *)de + reclen);
10265 tde = (struct target_dirent *)((char *)tde + treclen);
10266 len -= reclen;
10267 tlen += treclen;
10268 }
10269 ret = tlen;
10270 }
10271 unlock_user(dirp, arg2, ret);
10272 }
10273#endif
bellard31e31b82003-02-18 22:55:36 +000010274 break;
Chen Gang704eff62015-08-21 05:37:33 +080010275#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010276#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010277 case TARGET_NR_getdents64:
10278 {
aurel326556a832008-10-13 21:08:17 +000010279 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010280 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010281 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10282 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010283 ret = get_errno(sys_getdents64(arg1, dirp, count));
10284 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010285 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010286 int len = ret;
10287 int reclen;
10288 de = dirp;
10289 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010290 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010291 if (reclen > len)
10292 break;
bellard8083a3e2003-03-24 23:12:16 +000010293 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010294 tswap64s((uint64_t *)&de->d_ino);
10295 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010296 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010297 len -= reclen;
10298 }
10299 }
pbrook53a59602006-03-25 19:31:22 +000010300 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010301 }
10302 break;
bellarda541f292004-04-12 20:39:29 +000010303#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010304#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010305 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010306 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010307 break;
thse5febef2007-04-01 18:31:35 +000010308#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010309#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10310# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010311 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010312# endif
10313# ifdef TARGET_NR_ppoll
10314 case TARGET_NR_ppoll:
10315# endif
bellard9de5e442003-03-23 16:49:39 +000010316 {
pbrook53a59602006-03-25 19:31:22 +000010317 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010318 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010319 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010320 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010321
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010322 pfd = NULL;
10323 target_pfd = NULL;
10324 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010325 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10326 ret = -TARGET_EINVAL;
10327 break;
10328 }
10329
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010330 target_pfd = lock_user(VERIFY_WRITE, arg1,
10331 sizeof(struct target_pollfd) * nfds, 1);
10332 if (!target_pfd) {
10333 goto efault;
10334 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010335
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010336 pfd = alloca(sizeof(struct pollfd) * nfds);
10337 for (i = 0; i < nfds; i++) {
10338 pfd[i].fd = tswap32(target_pfd[i].fd);
10339 pfd[i].events = tswap16(target_pfd[i].events);
10340 }
bellard9de5e442003-03-23 16:49:39 +000010341 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010342
Peter Maydella6130232016-06-06 19:58:10 +010010343 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010344# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010345 case TARGET_NR_ppoll:
10346 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010347 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10348 target_sigset_t *target_set;
10349 sigset_t _set, *set = &_set;
10350
10351 if (arg3) {
10352 if (target_to_host_timespec(timeout_ts, arg3)) {
10353 unlock_user(target_pfd, arg1, 0);
10354 goto efault;
10355 }
10356 } else {
10357 timeout_ts = NULL;
10358 }
10359
10360 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010361 if (arg5 != sizeof(target_sigset_t)) {
10362 unlock_user(target_pfd, arg1, 0);
10363 ret = -TARGET_EINVAL;
10364 break;
10365 }
10366
Mike Frysingerd8035d42011-02-07 01:05:51 -050010367 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10368 if (!target_set) {
10369 unlock_user(target_pfd, arg1, 0);
10370 goto efault;
10371 }
10372 target_to_host_sigset(set, target_set);
10373 } else {
10374 set = NULL;
10375 }
10376
Peter Maydella6130232016-06-06 19:58:10 +010010377 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10378 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010379
10380 if (!is_error(ret) && arg3) {
10381 host_to_target_timespec(arg3, timeout_ts);
10382 }
10383 if (arg4) {
10384 unlock_user(target_set, arg4, 0);
10385 }
Peter Maydella6130232016-06-06 19:58:10 +010010386 break;
10387 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010388# endif
Peter Maydella6130232016-06-06 19:58:10 +010010389# ifdef TARGET_NR_poll
10390 case TARGET_NR_poll:
10391 {
10392 struct timespec ts, *pts;
10393
10394 if (arg3 >= 0) {
10395 /* Convert ms to secs, ns */
10396 ts.tv_sec = arg3 / 1000;
10397 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10398 pts = &ts;
10399 } else {
10400 /* -ve poll() timeout means "infinite" */
10401 pts = NULL;
10402 }
10403 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10404 break;
10405 }
10406# endif
10407 default:
10408 g_assert_not_reached();
10409 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010410
bellard9de5e442003-03-23 16:49:39 +000010411 if (!is_error(ret)) {
10412 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010413 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010414 }
10415 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010416 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010417 }
10418 break;
thse5febef2007-04-01 18:31:35 +000010419#endif
bellard31e31b82003-02-18 22:55:36 +000010420 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010421 /* NOTE: the flock constant seems to be the same for every
10422 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010423 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010424 break;
10425 case TARGET_NR_readv:
10426 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010427 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10428 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010429 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010430 unlock_iovec(vec, arg2, arg3, 1);
10431 } else {
10432 ret = -host_to_target_errno(errno);
10433 }
bellard31e31b82003-02-18 22:55:36 +000010434 }
10435 break;
10436 case TARGET_NR_writev:
10437 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010438 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10439 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010440 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010441 unlock_iovec(vec, arg2, arg3, 0);
10442 } else {
10443 ret = -host_to_target_errno(errno);
10444 }
bellard31e31b82003-02-18 22:55:36 +000010445 }
10446 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010447#if defined(TARGET_NR_preadv)
10448 case TARGET_NR_preadv:
10449 {
10450 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10451 if (vec != NULL) {
10452 ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
10453 unlock_iovec(vec, arg2, arg3, 1);
10454 } else {
10455 ret = -host_to_target_errno(errno);
10456 }
10457 }
10458 break;
10459#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010460#if defined(TARGET_NR_pwritev)
10461 case TARGET_NR_pwritev:
10462 {
10463 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10464 if (vec != NULL) {
10465 ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
10466 unlock_iovec(vec, arg2, arg3, 0);
10467 } else {
10468 ret = -host_to_target_errno(errno);
10469 }
10470 }
10471 break;
10472#endif
bellard31e31b82003-02-18 22:55:36 +000010473 case TARGET_NR_getsid:
10474 ret = get_errno(getsid(arg1));
10475 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010476#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010477 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010478 ret = get_errno(fdatasync(arg1));
10479 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010480#endif
Chen Gang704eff62015-08-21 05:37:33 +080010481#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010482 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010483 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010484 return value. */
ths0da46a62007-10-20 20:23:07 +000010485 ret = -TARGET_ENOTDIR;
10486 break;
Chen Gang704eff62015-08-21 05:37:33 +080010487#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010488 case TARGET_NR_sched_getaffinity:
10489 {
10490 unsigned int mask_size;
10491 unsigned long *mask;
10492
10493 /*
10494 * sched_getaffinity needs multiples of ulong, so need to take
10495 * care of mismatches between target ulong and host ulong sizes.
10496 */
10497 if (arg2 & (sizeof(abi_ulong) - 1)) {
10498 ret = -TARGET_EINVAL;
10499 break;
10500 }
10501 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10502
10503 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010504 memset(mask, 0, mask_size);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010505 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10506
10507 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010508 if (ret > arg2) {
10509 /* More data returned than the caller's buffer will fit.
10510 * This only happens if sizeof(abi_long) < sizeof(long)
10511 * and the caller passed us a buffer holding an odd number
10512 * of abi_longs. If the host kernel is actually using the
10513 * extra 4 bytes then fail EINVAL; otherwise we can just
10514 * ignore them and only copy the interesting part.
10515 */
10516 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10517 if (numcpus > arg2 * 8) {
10518 ret = -TARGET_EINVAL;
10519 break;
10520 }
10521 ret = arg2;
10522 }
10523
Samuel Thibault5fdefcf2018-02-11 18:47:04 +010010524 if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
10525 goto efault;
10526 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010527 }
10528 }
10529 break;
10530 case TARGET_NR_sched_setaffinity:
10531 {
10532 unsigned int mask_size;
10533 unsigned long *mask;
10534
10535 /*
10536 * sched_setaffinity needs multiples of ulong, so need to take
10537 * care of mismatches between target ulong and host ulong sizes.
10538 */
10539 if (arg2 & (sizeof(abi_ulong) - 1)) {
10540 ret = -TARGET_EINVAL;
10541 break;
10542 }
10543 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
Mike Frysinger737de1d2011-02-07 01:05:55 -050010544 mask = alloca(mask_size);
Samuel Thibault2e0a8712018-01-09 21:16:43 +010010545
10546 ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
10547 if (ret) {
10548 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -050010549 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010550
10551 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10552 }
10553 break;
Samuel Thibaultb827c3e2018-01-12 09:14:35 +010010554 case TARGET_NR_getcpu:
10555 {
10556 unsigned cpu, node;
10557 ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
10558 arg2 ? &node : NULL,
10559 NULL));
10560 if (is_error(ret)) {
10561 goto fail;
10562 }
10563 if (arg1 && put_user_u32(cpu, arg1)) {
10564 goto efault;
10565 }
10566 if (arg2 && put_user_u32(node, arg2)) {
10567 goto efault;
10568 }
10569 }
10570 break;
bellard31e31b82003-02-18 22:55:36 +000010571 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010572 {
pbrook53a59602006-03-25 19:31:22 +000010573 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010574 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010575
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010576 if (arg2 == 0) {
10577 return -TARGET_EINVAL;
10578 }
bellard579a97f2007-11-11 14:26:47 +000010579 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10580 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010581 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010582 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010583 ret = get_errno(sched_setparam(arg1, &schp));
10584 }
10585 break;
bellard31e31b82003-02-18 22:55:36 +000010586 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010587 {
pbrook53a59602006-03-25 19:31:22 +000010588 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010589 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010590
10591 if (arg2 == 0) {
10592 return -TARGET_EINVAL;
10593 }
bellard5cd43932003-03-29 16:54:36 +000010594 ret = get_errno(sched_getparam(arg1, &schp));
10595 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010596 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10597 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010598 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010599 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010600 }
10601 }
10602 break;
bellard31e31b82003-02-18 22:55:36 +000010603 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010604 {
pbrook53a59602006-03-25 19:31:22 +000010605 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010606 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010607 if (arg3 == 0) {
10608 return -TARGET_EINVAL;
10609 }
bellard579a97f2007-11-11 14:26:47 +000010610 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10611 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010612 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010613 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010614 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10615 }
10616 break;
bellard31e31b82003-02-18 22:55:36 +000010617 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010618 ret = get_errno(sched_getscheduler(arg1));
10619 break;
bellard31e31b82003-02-18 22:55:36 +000010620 case TARGET_NR_sched_yield:
10621 ret = get_errno(sched_yield());
10622 break;
10623 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010624 ret = get_errno(sched_get_priority_max(arg1));
10625 break;
bellard31e31b82003-02-18 22:55:36 +000010626 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010627 ret = get_errno(sched_get_priority_min(arg1));
10628 break;
bellard31e31b82003-02-18 22:55:36 +000010629 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010630 {
bellard5cd43932003-03-29 16:54:36 +000010631 struct timespec ts;
10632 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10633 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010634 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010635 }
10636 }
10637 break;
bellard31e31b82003-02-18 22:55:36 +000010638 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010639 {
bellard1b6b0292003-03-22 17:31:38 +000010640 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010641 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010642 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010643 if (is_error(ret) && arg2) {
10644 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010645 }
10646 }
10647 break;
thse5febef2007-04-01 18:31:35 +000010648#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010649 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010650 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010651#endif
10652#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010653 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010654 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010655#endif
bellard31e31b82003-02-18 22:55:36 +000010656 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010657 switch (arg1) {
10658 case PR_GET_PDEATHSIG:
10659 {
10660 int deathsig;
10661 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10662 if (!is_error(ret) && arg2
10663 && put_user_ual(deathsig, arg2)) {
10664 goto efault;
thse5574482007-02-11 20:03:13 +000010665 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010666 break;
10667 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010668#ifdef PR_GET_NAME
10669 case PR_GET_NAME:
10670 {
10671 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10672 if (!name) {
10673 goto efault;
10674 }
10675 ret = get_errno(prctl(arg1, (unsigned long)name,
10676 arg3, arg4, arg5));
10677 unlock_user(name, arg2, 16);
10678 break;
10679 }
10680 case PR_SET_NAME:
10681 {
10682 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10683 if (!name) {
10684 goto efault;
10685 }
10686 ret = get_errno(prctl(arg1, (unsigned long)name,
10687 arg3, arg4, arg5));
10688 unlock_user(name, arg2, 0);
10689 break;
10690 }
10691#endif
Richard Henderson85fc7162018-03-09 17:09:43 +000010692#ifdef TARGET_AARCH64
10693 case TARGET_PR_SVE_SET_VL:
10694 /* We cannot support either PR_SVE_SET_VL_ONEXEC
10695 or PR_SVE_VL_INHERIT. Therefore, anything above
10696 ARM_MAX_VQ results in EINVAL. */
10697 ret = -TARGET_EINVAL;
10698 if (arm_feature(cpu_env, ARM_FEATURE_SVE)
10699 && arg2 >= 0 && arg2 <= ARM_MAX_VQ * 16 && !(arg2 & 15)) {
10700 CPUARMState *env = cpu_env;
10701 int old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
10702 int vq = MAX(arg2 / 16, 1);
10703
10704 if (vq < old_vq) {
10705 aarch64_sve_narrow_vq(env, vq);
10706 }
10707 env->vfp.zcr_el[1] = vq - 1;
10708 ret = vq * 16;
10709 }
10710 break;
10711 case TARGET_PR_SVE_GET_VL:
10712 ret = -TARGET_EINVAL;
10713 if (arm_feature(cpu_env, ARM_FEATURE_SVE)) {
10714 CPUARMState *env = cpu_env;
10715 ret = ((env->vfp.zcr_el[1] & 0xf) + 1) * 16;
10716 }
10717 break;
10718#endif /* AARCH64 */
James Cowgilla8b154a2017-11-06 18:03:51 +000010719 case PR_GET_SECCOMP:
10720 case PR_SET_SECCOMP:
10721 /* Disable seccomp to prevent the target disabling syscalls we
10722 * need. */
10723 ret = -TARGET_EINVAL;
10724 break;
Peter Maydell1e6722f2012-02-03 14:48:03 +000010725 default:
10726 /* Most prctl options have no pointer arguments */
10727 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10728 break;
10729 }
ths39b9aae2007-02-11 18:36:44 +000010730 break;
bellardd2fd1af2007-11-14 18:08:56 +000010731#ifdef TARGET_NR_arch_prctl
10732 case TARGET_NR_arch_prctl:
10733#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10734 ret = do_arch_prctl(cpu_env, arg1, arg2);
10735 break;
10736#else
10737 goto unimplemented;
10738#endif
10739#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010740#ifdef TARGET_NR_pread64
10741 case TARGET_NR_pread64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010742 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010743 arg4 = arg5;
10744 arg5 = arg6;
10745 }
aurel32f2c7ba12008-03-28 22:32:06 +000010746 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10747 goto efault;
10748 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10749 unlock_user(p, arg2, ret);
10750 break;
10751 case TARGET_NR_pwrite64:
James Clarke8bf8e9d2017-09-15 20:33:13 +010010752 if (regpairs_aligned(cpu_env, num)) {
Alexander Grafae017a52012-09-29 15:32:39 +000010753 arg4 = arg5;
10754 arg5 = arg6;
10755 }
aurel32f2c7ba12008-03-28 22:32:06 +000010756 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10757 goto efault;
10758 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10759 unlock_user(p, arg2, 0);
10760 break;
10761#endif
bellard31e31b82003-02-18 22:55:36 +000010762 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010763 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10764 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010765 ret = get_errno(sys_getcwd1(p, arg2));
10766 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010767 break;
10768 case TARGET_NR_capget:
10769 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010770 {
10771 struct target_user_cap_header *target_header;
10772 struct target_user_cap_data *target_data = NULL;
10773 struct __user_cap_header_struct header;
10774 struct __user_cap_data_struct data[2];
10775 struct __user_cap_data_struct *dataptr = NULL;
10776 int i, target_datalen;
10777 int data_items = 1;
10778
10779 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10780 goto efault;
10781 }
10782 header.version = tswap32(target_header->version);
10783 header.pid = tswap32(target_header->pid);
10784
Peter Maydellec864872014-03-19 16:07:30 +000010785 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010786 /* Version 2 and up takes pointer to two user_data structs */
10787 data_items = 2;
10788 }
10789
10790 target_datalen = sizeof(*target_data) * data_items;
10791
10792 if (arg2) {
10793 if (num == TARGET_NR_capget) {
10794 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10795 } else {
10796 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10797 }
10798 if (!target_data) {
10799 unlock_user_struct(target_header, arg1, 0);
10800 goto efault;
10801 }
10802
10803 if (num == TARGET_NR_capset) {
10804 for (i = 0; i < data_items; i++) {
10805 data[i].effective = tswap32(target_data[i].effective);
10806 data[i].permitted = tswap32(target_data[i].permitted);
10807 data[i].inheritable = tswap32(target_data[i].inheritable);
10808 }
10809 }
10810
10811 dataptr = data;
10812 }
10813
10814 if (num == TARGET_NR_capget) {
10815 ret = get_errno(capget(&header, dataptr));
10816 } else {
10817 ret = get_errno(capset(&header, dataptr));
10818 }
10819
10820 /* The kernel always updates version for both capget and capset */
10821 target_header->version = tswap32(header.version);
10822 unlock_user_struct(target_header, arg1, 1);
10823
10824 if (arg2) {
10825 if (num == TARGET_NR_capget) {
10826 for (i = 0; i < data_items; i++) {
10827 target_data[i].effective = tswap32(data[i].effective);
10828 target_data[i].permitted = tswap32(data[i].permitted);
10829 target_data[i].inheritable = tswap32(data[i].inheritable);
10830 }
10831 unlock_user(target_data, arg2, target_datalen);
10832 } else {
10833 unlock_user(target_data, arg2, 0);
10834 }
10835 }
10836 break;
10837 }
bellard31e31b82003-02-18 22:55:36 +000010838 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010839 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010840 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010841
10842#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010843 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010844 {
10845 off_t *offp = NULL;
10846 off_t off;
10847 if (arg3) {
10848 ret = get_user_sal(off, arg3);
10849 if (is_error(ret)) {
10850 break;
10851 }
10852 offp = &off;
10853 }
10854 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10855 if (!is_error(ret) && arg3) {
10856 abi_long ret2 = put_user_sal(off, arg3);
10857 if (is_error(ret2)) {
10858 ret = ret2;
10859 }
10860 }
10861 break;
10862 }
10863#ifdef TARGET_NR_sendfile64
10864 case TARGET_NR_sendfile64:
10865 {
10866 off_t *offp = NULL;
10867 off_t off;
10868 if (arg3) {
10869 ret = get_user_s64(off, arg3);
10870 if (is_error(ret)) {
10871 break;
10872 }
10873 offp = &off;
10874 }
10875 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10876 if (!is_error(ret) && arg3) {
10877 abi_long ret2 = put_user_s64(off, arg3);
10878 if (is_error(ret2)) {
10879 ret = ret2;
10880 }
10881 }
10882 break;
10883 }
10884#endif
10885#else
10886 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010887#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010888 case TARGET_NR_sendfile64:
10889#endif
bellard5cd43932003-03-29 16:54:36 +000010890 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010891#endif
10892
bellardebc05482003-09-30 21:08:41 +000010893#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010894 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010895 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010896#endif
10897#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010898 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010899 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010900#endif
bellard048f6b42005-11-26 18:47:20 +000010901#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010902 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010010903 ret = get_errno(do_fork(cpu_env,
10904 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000010905 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010906 break;
bellard048f6b42005-11-26 18:47:20 +000010907#endif
bellardebc05482003-09-30 21:08:41 +000010908#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010909 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010910 {
10911 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010912 int resource = target_to_host_resource(arg1);
10913 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010914 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010915 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010916 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10917 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010918 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10919 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010920 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010921 }
10922 break;
10923 }
bellardebc05482003-09-30 21:08:41 +000010924#endif
bellarda315a142005-01-30 22:59:18 +000010925#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010926 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010927 if (!(p = lock_user_string(arg1)))
10928 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010929 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10930 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010931 break;
bellarda315a142005-01-30 22:59:18 +000010932#endif
10933#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010934 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010935 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010936 break;
bellarda315a142005-01-30 22:59:18 +000010937#endif
10938#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010939 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010940 if (!(p = lock_user_string(arg1)))
10941 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010942 ret = get_errno(stat(path(p), &st));
10943 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010944 if (!is_error(ret))
10945 ret = host_to_target_stat64(cpu_env, arg2, &st);
10946 break;
bellarda315a142005-01-30 22:59:18 +000010947#endif
10948#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010949 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010950 if (!(p = lock_user_string(arg1)))
10951 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010952 ret = get_errno(lstat(path(p), &st));
10953 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010954 if (!is_error(ret))
10955 ret = host_to_target_stat64(cpu_env, arg2, &st);
10956 break;
bellarda315a142005-01-30 22:59:18 +000010957#endif
10958#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010959 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010960 ret = get_errno(fstat(arg1, &st));
10961 if (!is_error(ret))
10962 ret = host_to_target_stat64(cpu_env, arg2, &st);
10963 break;
bellardec86b0f2003-04-11 00:15:04 +000010964#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010965#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010966#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010967 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010968#endif
10969#ifdef TARGET_NR_newfstatat
10970 case TARGET_NR_newfstatat:
10971#endif
balrog6a24a772008-09-20 02:23:36 +000010972 if (!(p = lock_user_string(arg2)))
10973 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010974 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010975 if (!is_error(ret))
10976 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010977 break;
bellarda315a142005-01-30 22:59:18 +000010978#endif
Chen Gang704eff62015-08-21 05:37:33 +080010979#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010980 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010981 if (!(p = lock_user_string(arg1)))
10982 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010983 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10984 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010985 break;
Chen Gang704eff62015-08-21 05:37:33 +080010986#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010987#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010988 case TARGET_NR_getuid:
10989 ret = get_errno(high2lowuid(getuid()));
10990 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010991#endif
10992#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010993 case TARGET_NR_getgid:
10994 ret = get_errno(high2lowgid(getgid()));
10995 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010996#endif
10997#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010998 case TARGET_NR_geteuid:
10999 ret = get_errno(high2lowuid(geteuid()));
11000 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011001#endif
11002#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000011003 case TARGET_NR_getegid:
11004 ret = get_errno(high2lowgid(getegid()));
11005 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030011006#endif
bellard67867302003-11-23 17:05:30 +000011007 case TARGET_NR_setreuid:
11008 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
11009 break;
11010 case TARGET_NR_setregid:
11011 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
11012 break;
11013 case TARGET_NR_getgroups:
11014 {
11015 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011016 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000011017 gid_t *grouplist;
11018 int i;
11019
11020 grouplist = alloca(gidsetsize * sizeof(gid_t));
11021 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011022 if (gidsetsize == 0)
11023 break;
bellard67867302003-11-23 17:05:30 +000011024 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000011025 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000011026 if (!target_grouplist)
11027 goto efault;
balroga2155fc2008-09-20 02:12:08 +000011028 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030011029 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011030 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000011031 }
11032 }
11033 break;
11034 case TARGET_NR_setgroups:
11035 {
11036 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030011037 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011038 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000011039 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011040 if (gidsetsize) {
11041 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000011042 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050011043 if (!target_grouplist) {
11044 ret = -TARGET_EFAULT;
11045 goto fail;
11046 }
11047 for (i = 0; i < gidsetsize; i++) {
11048 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
11049 }
11050 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000011051 }
bellard67867302003-11-23 17:05:30 +000011052 ret = get_errno(setgroups(gidsetsize, grouplist));
11053 }
11054 break;
11055 case TARGET_NR_fchown:
11056 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
11057 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011058#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000011059 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000011060 if (!(p = lock_user_string(arg2)))
11061 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010011062 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
11063 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000011064 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000011065 break;
11066#endif
bellard67867302003-11-23 17:05:30 +000011067#ifdef TARGET_NR_setresuid
11068 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011069 ret = get_errno(sys_setresuid(low2highuid(arg1),
11070 low2highuid(arg2),
11071 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000011072 break;
11073#endif
11074#ifdef TARGET_NR_getresuid
11075 case TARGET_NR_getresuid:
11076 {
pbrook53a59602006-03-25 19:31:22 +000011077 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000011078 ret = get_errno(getresuid(&ruid, &euid, &suid));
11079 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011080 if (put_user_id(high2lowuid(ruid), arg1)
11081 || put_user_id(high2lowuid(euid), arg2)
11082 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000011083 goto efault;
bellard67867302003-11-23 17:05:30 +000011084 }
11085 }
11086 break;
11087#endif
11088#ifdef TARGET_NR_getresgid
11089 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011090 ret = get_errno(sys_setresgid(low2highgid(arg1),
11091 low2highgid(arg2),
11092 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000011093 break;
11094#endif
11095#ifdef TARGET_NR_getresgid
11096 case TARGET_NR_getresgid:
11097 {
pbrook53a59602006-03-25 19:31:22 +000011098 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000011099 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11100 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000011101 if (put_user_id(high2lowgid(rgid), arg1)
11102 || put_user_id(high2lowgid(egid), arg2)
11103 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000011104 goto efault;
bellard67867302003-11-23 17:05:30 +000011105 }
11106 }
11107 break;
11108#endif
Chen Gang704eff62015-08-21 05:37:33 +080011109#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000011110 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000011111 if (!(p = lock_user_string(arg1)))
11112 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011113 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
11114 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000011115 break;
Chen Gang704eff62015-08-21 05:37:33 +080011116#endif
bellard67867302003-11-23 17:05:30 +000011117 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011118 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000011119 break;
11120 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011121 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000011122 break;
11123 case TARGET_NR_setfsuid:
11124 ret = get_errno(setfsuid(arg1));
11125 break;
11126 case TARGET_NR_setfsgid:
11127 ret = get_errno(setfsgid(arg1));
11128 break;
bellard67867302003-11-23 17:05:30 +000011129
bellarda315a142005-01-30 22:59:18 +000011130#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000011131 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000011132 if (!(p = lock_user_string(arg1)))
11133 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011134 ret = get_errno(lchown(p, arg2, arg3));
11135 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011136 break;
bellarda315a142005-01-30 22:59:18 +000011137#endif
11138#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000011139 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000011140 ret = get_errno(getuid());
11141 break;
bellarda315a142005-01-30 22:59:18 +000011142#endif
aurel3264b4d282008-11-14 17:20:15 +000011143
11144#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
11145 /* Alpha specific */
11146 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011147 {
11148 uid_t euid;
11149 euid=geteuid();
11150 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
11151 }
aurel3264b4d282008-11-14 17:20:15 +000011152 ret = get_errno(getuid());
11153 break;
11154#endif
11155#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
11156 /* Alpha specific */
11157 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011158 {
11159 uid_t egid;
11160 egid=getegid();
11161 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
11162 }
aurel3264b4d282008-11-14 17:20:15 +000011163 ret = get_errno(getgid());
11164 break;
11165#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080011166#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
11167 /* Alpha specific */
11168 case TARGET_NR_osf_getsysinfo:
11169 ret = -TARGET_EOPNOTSUPP;
11170 switch (arg1) {
11171 case TARGET_GSI_IEEE_FP_CONTROL:
11172 {
11173 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
11174
11175 /* Copied from linux ieee_fpcr_to_swcr. */
11176 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
11177 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
11178 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
11179 | SWCR_TRAP_ENABLE_DZE
11180 | SWCR_TRAP_ENABLE_OVF);
11181 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
11182 | SWCR_TRAP_ENABLE_INE);
11183 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
11184 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
11185
11186 if (put_user_u64 (swcr, arg2))
11187 goto efault;
11188 ret = 0;
11189 }
11190 break;
11191
11192 /* case GSI_IEEE_STATE_AT_SIGNAL:
11193 -- Not implemented in linux kernel.
11194 case GSI_UACPROC:
11195 -- Retrieves current unaligned access state; not much used.
11196 case GSI_PROC_TYPE:
11197 -- Retrieves implver information; surely not used.
11198 case GSI_GET_HWRPB:
11199 -- Grabs a copy of the HWRPB; surely not used.
11200 */
11201 }
11202 break;
11203#endif
11204#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
11205 /* Alpha specific */
11206 case TARGET_NR_osf_setsysinfo:
11207 ret = -TARGET_EOPNOTSUPP;
11208 switch (arg1) {
11209 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080011210 {
11211 uint64_t swcr, fpcr, orig_fpcr;
11212
Richard Henderson6e06d512012-06-01 09:08:21 -070011213 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080011214 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070011215 }
11216 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011217 fpcr = orig_fpcr & FPCR_DYN_MASK;
11218
11219 /* Copied from linux ieee_swcr_to_fpcr. */
11220 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
11221 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
11222 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
11223 | SWCR_TRAP_ENABLE_DZE
11224 | SWCR_TRAP_ENABLE_OVF)) << 48;
11225 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
11226 | SWCR_TRAP_ENABLE_INE)) << 57;
11227 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
11228 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
11229
Richard Henderson6e06d512012-06-01 09:08:21 -070011230 cpu_alpha_store_fpcr(cpu_env, fpcr);
11231 ret = 0;
11232 }
11233 break;
11234
11235 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
11236 {
11237 uint64_t exc, fpcr, orig_fpcr;
11238 int si_code;
11239
11240 if (get_user_u64(exc, arg2)) {
11241 goto efault;
11242 }
11243
11244 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
11245
11246 /* We only add to the exception status here. */
11247 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
11248
11249 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011250 ret = 0;
11251
Richard Henderson6e06d512012-06-01 09:08:21 -070011252 /* Old exceptions are not signaled. */
11253 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011254
Richard Henderson6e06d512012-06-01 09:08:21 -070011255 /* If any exceptions set by this call,
11256 and are unmasked, send a signal. */
11257 si_code = 0;
11258 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11259 si_code = TARGET_FPE_FLTRES;
11260 }
11261 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11262 si_code = TARGET_FPE_FLTUND;
11263 }
11264 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11265 si_code = TARGET_FPE_FLTOVF;
11266 }
11267 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11268 si_code = TARGET_FPE_FLTDIV;
11269 }
11270 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11271 si_code = TARGET_FPE_FLTINV;
11272 }
11273 if (si_code != 0) {
11274 target_siginfo_t info;
11275 info.si_signo = SIGFPE;
11276 info.si_errno = 0;
11277 info.si_code = si_code;
11278 info._sifields._sigfault._addr
11279 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011280 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11281 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011282 }
11283 }
11284 break;
11285
11286 /* case SSI_NVPAIRS:
11287 -- Used with SSIN_UACPROC to enable unaligned accesses.
11288 case SSI_IEEE_STATE_AT_SIGNAL:
11289 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11290 -- Not implemented in linux kernel
11291 */
11292 }
11293 break;
11294#endif
11295#ifdef TARGET_NR_osf_sigprocmask
11296 /* Alpha specific. */
11297 case TARGET_NR_osf_sigprocmask:
11298 {
11299 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011300 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011301 sigset_t set, oldset;
11302
11303 switch(arg1) {
11304 case TARGET_SIG_BLOCK:
11305 how = SIG_BLOCK;
11306 break;
11307 case TARGET_SIG_UNBLOCK:
11308 how = SIG_UNBLOCK;
11309 break;
11310 case TARGET_SIG_SETMASK:
11311 how = SIG_SETMASK;
11312 break;
11313 default:
11314 ret = -TARGET_EINVAL;
11315 goto fail;
11316 }
11317 mask = arg2;
11318 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011319 ret = do_sigprocmask(how, &set, &oldset);
11320 if (!ret) {
11321 host_to_target_old_sigset(&mask, &oldset);
11322 ret = mask;
11323 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011324 }
11325 break;
11326#endif
aurel3264b4d282008-11-14 17:20:15 +000011327
bellarda315a142005-01-30 22:59:18 +000011328#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011329 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011330 ret = get_errno(getgid());
11331 break;
bellarda315a142005-01-30 22:59:18 +000011332#endif
11333#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011334 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011335 ret = get_errno(geteuid());
11336 break;
bellarda315a142005-01-30 22:59:18 +000011337#endif
11338#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011339 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011340 ret = get_errno(getegid());
11341 break;
bellarda315a142005-01-30 22:59:18 +000011342#endif
11343#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011344 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011345 ret = get_errno(setreuid(arg1, arg2));
11346 break;
bellarda315a142005-01-30 22:59:18 +000011347#endif
11348#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011349 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011350 ret = get_errno(setregid(arg1, arg2));
11351 break;
bellarda315a142005-01-30 22:59:18 +000011352#endif
11353#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011354 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011355 {
11356 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011357 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011358 gid_t *grouplist;
11359 int i;
11360
11361 grouplist = alloca(gidsetsize * sizeof(gid_t));
11362 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011363 if (gidsetsize == 0)
11364 break;
bellard99c475a2005-01-31 20:45:13 +000011365 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011366 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11367 if (!target_grouplist) {
11368 ret = -TARGET_EFAULT;
11369 goto fail;
11370 }
balroga2155fc2008-09-20 02:12:08 +000011371 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011372 target_grouplist[i] = tswap32(grouplist[i]);
11373 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011374 }
11375 }
11376 break;
bellarda315a142005-01-30 22:59:18 +000011377#endif
11378#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011379 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011380 {
11381 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011382 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011383 gid_t *grouplist;
11384 int i;
ths3b46e622007-09-17 08:09:54 +000011385
bellard99c475a2005-01-31 20:45:13 +000011386 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011387 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11388 if (!target_grouplist) {
11389 ret = -TARGET_EFAULT;
11390 goto fail;
11391 }
bellard99c475a2005-01-31 20:45:13 +000011392 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011393 grouplist[i] = tswap32(target_grouplist[i]);
11394 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011395 ret = get_errno(setgroups(gidsetsize, grouplist));
11396 }
11397 break;
bellarda315a142005-01-30 22:59:18 +000011398#endif
11399#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011400 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011401 ret = get_errno(fchown(arg1, arg2, arg3));
11402 break;
bellarda315a142005-01-30 22:59:18 +000011403#endif
11404#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011405 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011406 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011407 break;
bellarda315a142005-01-30 22:59:18 +000011408#endif
11409#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011410 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011411 {
pbrook53a59602006-03-25 19:31:22 +000011412 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011413 ret = get_errno(getresuid(&ruid, &euid, &suid));
11414 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011415 if (put_user_u32(ruid, arg1)
11416 || put_user_u32(euid, arg2)
11417 || put_user_u32(suid, arg3))
11418 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011419 }
11420 }
11421 break;
bellarda315a142005-01-30 22:59:18 +000011422#endif
11423#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011424 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011425 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011426 break;
bellarda315a142005-01-30 22:59:18 +000011427#endif
11428#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011429 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011430 {
pbrook53a59602006-03-25 19:31:22 +000011431 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011432 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11433 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011434 if (put_user_u32(rgid, arg1)
11435 || put_user_u32(egid, arg2)
11436 || put_user_u32(sgid, arg3))
11437 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011438 }
11439 }
11440 break;
bellarda315a142005-01-30 22:59:18 +000011441#endif
11442#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011443 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011444 if (!(p = lock_user_string(arg1)))
11445 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011446 ret = get_errno(chown(p, arg2, arg3));
11447 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011448 break;
bellarda315a142005-01-30 22:59:18 +000011449#endif
11450#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011451 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011452 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011453 break;
bellarda315a142005-01-30 22:59:18 +000011454#endif
11455#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011456 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011457 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011458 break;
bellarda315a142005-01-30 22:59:18 +000011459#endif
11460#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011461 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011462 ret = get_errno(setfsuid(arg1));
11463 break;
bellarda315a142005-01-30 22:59:18 +000011464#endif
11465#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011466 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011467 ret = get_errno(setfsgid(arg1));
11468 break;
bellarda315a142005-01-30 22:59:18 +000011469#endif
bellard67867302003-11-23 17:05:30 +000011470
bellard31e31b82003-02-18 22:55:36 +000011471 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011472 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011473#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011474 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011475 {
11476 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011477 ret = -TARGET_ENOMEM;
11478 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11479 if (!a) {
11480 goto fail;
11481 }
aurel3204bb9ac2008-10-01 21:46:41 +000011482 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011483 p = lock_user_string(arg3);
11484 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011485 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011486 }
aurel3204bb9ac2008-10-01 21:46:41 +000011487 ret = get_errno(mincore(a, arg2, p));
11488 unlock_user(p, arg3, ret);
11489 mincore_fail:
11490 unlock_user(a, arg1, 0);
11491 }
11492 break;
bellardffa65c32004-01-04 23:57:22 +000011493#endif
aurel32408321b2008-10-01 21:46:32 +000011494#ifdef TARGET_NR_arm_fadvise64_64
11495 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011496 /* arm_fadvise64_64 looks like fadvise64_64 but
11497 * with different argument order: fd, advice, offset, len
11498 * rather than the usual fd, offset, len, advice.
11499 * Note that offset and len are both 64-bit so appear as
11500 * pairs of 32-bit registers.
11501 */
11502 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11503 target_offset64(arg5, arg6), arg2);
11504 ret = -host_to_target_errno(ret);
11505 break;
aurel32408321b2008-10-01 21:46:32 +000011506#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011507
11508#if TARGET_ABI_BITS == 32
11509
11510#ifdef TARGET_NR_fadvise64_64
11511 case TARGET_NR_fadvise64_64:
Laurent Vivier43046b52017-03-02 01:11:45 +010011512#if defined(TARGET_PPC)
11513 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11514 ret = arg2;
11515 arg2 = arg3;
11516 arg3 = arg4;
11517 arg4 = arg5;
11518 arg5 = arg6;
11519 arg6 = ret;
11520#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011521 /* 6 args: fd, offset (high, low), len (high, low), advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011522 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011523 /* offset is in (3,4), len in (5,6) and advice in 7 */
11524 arg2 = arg3;
11525 arg3 = arg4;
11526 arg4 = arg5;
11527 arg5 = arg6;
11528 arg6 = arg7;
11529 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011530#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011531 ret = -host_to_target_errno(posix_fadvise(arg1,
11532 target_offset64(arg2, arg3),
11533 target_offset64(arg4, arg5),
11534 arg6));
11535 break;
11536#endif
11537
11538#ifdef TARGET_NR_fadvise64
11539 case TARGET_NR_fadvise64:
11540 /* 5 args: fd, offset (high, low), len, advice */
James Clarke8bf8e9d2017-09-15 20:33:13 +010011541 if (regpairs_aligned(cpu_env, num)) {
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011542 /* offset is in (3,4), len in 5 and advice in 6 */
11543 arg2 = arg3;
11544 arg3 = arg4;
11545 arg4 = arg5;
11546 arg5 = arg6;
11547 }
11548 ret = -host_to_target_errno(posix_fadvise(arg1,
11549 target_offset64(arg2, arg3),
11550 arg4, arg5));
11551 break;
11552#endif
11553
11554#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011555#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011556#ifdef TARGET_NR_fadvise64_64
11557 case TARGET_NR_fadvise64_64:
11558#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011559#ifdef TARGET_NR_fadvise64
11560 case TARGET_NR_fadvise64:
11561#endif
11562#ifdef TARGET_S390X
11563 switch (arg4) {
11564 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11565 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11566 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11567 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11568 default: break;
11569 }
11570#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011571 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11572 break;
aurel32408321b2008-10-01 21:46:32 +000011573#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011574#endif /* end of 64-bit ABI fadvise handling */
11575
bellardffa65c32004-01-04 23:57:22 +000011576#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011577 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011578 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011579 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011580 This will break MADV_DONTNEED.
11581 This is a hint, so ignoring and returning success is ok. */
11582 ret = get_errno(0);
11583 break;
bellardffa65c32004-01-04 23:57:22 +000011584#endif
blueswir1992f48a2007-10-14 16:27:31 +000011585#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011586 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011587 {
thsb1e341e2007-03-20 21:50:52 +000011588 int cmd;
bellard77e46722003-04-29 20:39:06 +000011589 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011590 from_flock64_fn *copyfrom = copy_from_user_flock64;
11591 to_flock64_fn *copyto = copy_to_user_flock64;
11592
pbrookce4defa2006-02-09 16:49:55 +000011593#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010011594 if (((CPUARMState *)cpu_env)->eabi) {
11595 copyfrom = copy_from_user_eabi_flock64;
11596 copyto = copy_to_user_eabi_flock64;
11597 }
pbrookce4defa2006-02-09 16:49:55 +000011598#endif
bellard77e46722003-04-29 20:39:06 +000011599
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011600 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011601 if (cmd == -TARGET_EINVAL) {
11602 ret = cmd;
11603 break;
11604 }
thsb1e341e2007-03-20 21:50:52 +000011605
bellard60cd49d2003-03-16 22:53:56 +000011606 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011607 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011608 ret = copyfrom(&fl, arg3);
11609 if (ret) {
11610 break;
ths58134272007-03-31 18:59:32 +000011611 }
thsb1e341e2007-03-20 21:50:52 +000011612 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011613 if (ret == 0) {
11614 ret = copyto(arg3, &fl);
11615 }
bellard77e46722003-04-29 20:39:06 +000011616 break;
11617
thsb1e341e2007-03-20 21:50:52 +000011618 case TARGET_F_SETLK64:
11619 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011620 ret = copyfrom(&fl, arg3);
11621 if (ret) {
11622 break;
pbrookce4defa2006-02-09 16:49:55 +000011623 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011624 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011625 break;
bellard60cd49d2003-03-16 22:53:56 +000011626 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011627 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011628 break;
11629 }
bellard77e46722003-04-29 20:39:06 +000011630 break;
11631 }
bellard60cd49d2003-03-16 22:53:56 +000011632#endif
ths7d600c82006-12-08 01:32:58 +000011633#ifdef TARGET_NR_cacheflush
11634 case TARGET_NR_cacheflush:
11635 /* self-modifying code is handled automatically, so nothing needed */
11636 ret = 0;
11637 break;
11638#endif
bellardebc05482003-09-30 21:08:41 +000011639#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011640 case TARGET_NR_security:
11641 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011642#endif
bellardc573ff62004-01-04 15:51:36 +000011643#ifdef TARGET_NR_getpagesize
11644 case TARGET_NR_getpagesize:
11645 ret = TARGET_PAGE_SIZE;
11646 break;
11647#endif
bellard31e31b82003-02-18 22:55:36 +000011648 case TARGET_NR_gettid:
11649 ret = get_errno(gettid());
11650 break;
thse5febef2007-04-01 18:31:35 +000011651#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011652 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011653#if TARGET_ABI_BITS == 32
James Clarke8bf8e9d2017-09-15 20:33:13 +010011654 if (regpairs_aligned(cpu_env, num)) {
aurel322054ac92008-10-13 21:08:07 +000011655 arg2 = arg3;
11656 arg3 = arg4;
11657 arg4 = arg5;
11658 }
Lena Djokic77c68502016-11-24 17:08:56 +010011659 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011660#else
11661 ret = get_errno(readahead(arg1, arg2, arg3));
11662#endif
11663 break;
thse5febef2007-04-01 18:31:35 +000011664#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011665#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011666#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011667 case TARGET_NR_listxattr:
11668 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011669 {
11670 void *p, *b = 0;
11671 if (arg2) {
11672 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11673 if (!b) {
11674 ret = -TARGET_EFAULT;
11675 break;
11676 }
11677 }
11678 p = lock_user_string(arg1);
11679 if (p) {
11680 if (num == TARGET_NR_listxattr) {
11681 ret = get_errno(listxattr(p, b, arg3));
11682 } else {
11683 ret = get_errno(llistxattr(p, b, arg3));
11684 }
11685 } else {
11686 ret = -TARGET_EFAULT;
11687 }
11688 unlock_user(p, arg1, 0);
11689 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011690 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011691 }
11692 case TARGET_NR_flistxattr:
11693 {
11694 void *b = 0;
11695 if (arg2) {
11696 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11697 if (!b) {
11698 ret = -TARGET_EFAULT;
11699 break;
11700 }
11701 }
11702 ret = get_errno(flistxattr(arg1, b, arg3));
11703 unlock_user(b, arg2, arg3);
11704 break;
11705 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011706 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011707 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011708 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011709 void *p, *n, *v = 0;
11710 if (arg3) {
11711 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11712 if (!v) {
11713 ret = -TARGET_EFAULT;
11714 break;
11715 }
11716 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011717 p = lock_user_string(arg1);
11718 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011719 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011720 if (num == TARGET_NR_setxattr) {
11721 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11722 } else {
11723 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11724 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011725 } else {
11726 ret = -TARGET_EFAULT;
11727 }
11728 unlock_user(p, arg1, 0);
11729 unlock_user(n, arg2, 0);
11730 unlock_user(v, arg3, 0);
11731 }
11732 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011733 case TARGET_NR_fsetxattr:
11734 {
11735 void *n, *v = 0;
11736 if (arg3) {
11737 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11738 if (!v) {
11739 ret = -TARGET_EFAULT;
11740 break;
11741 }
11742 }
11743 n = lock_user_string(arg2);
11744 if (n) {
11745 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11746 } else {
11747 ret = -TARGET_EFAULT;
11748 }
11749 unlock_user(n, arg2, 0);
11750 unlock_user(v, arg3, 0);
11751 }
11752 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011753 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011754 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011755 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011756 void *p, *n, *v = 0;
11757 if (arg3) {
11758 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11759 if (!v) {
11760 ret = -TARGET_EFAULT;
11761 break;
11762 }
11763 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011764 p = lock_user_string(arg1);
11765 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011766 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011767 if (num == TARGET_NR_getxattr) {
11768 ret = get_errno(getxattr(p, n, v, arg4));
11769 } else {
11770 ret = get_errno(lgetxattr(p, n, v, arg4));
11771 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011772 } else {
11773 ret = -TARGET_EFAULT;
11774 }
11775 unlock_user(p, arg1, 0);
11776 unlock_user(n, arg2, 0);
11777 unlock_user(v, arg3, arg4);
11778 }
11779 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011780 case TARGET_NR_fgetxattr:
11781 {
11782 void *n, *v = 0;
11783 if (arg3) {
11784 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11785 if (!v) {
11786 ret = -TARGET_EFAULT;
11787 break;
11788 }
11789 }
11790 n = lock_user_string(arg2);
11791 if (n) {
11792 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11793 } else {
11794 ret = -TARGET_EFAULT;
11795 }
11796 unlock_user(n, arg2, 0);
11797 unlock_user(v, arg3, arg4);
11798 }
11799 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011800 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011801 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011802 {
11803 void *p, *n;
11804 p = lock_user_string(arg1);
11805 n = lock_user_string(arg2);
11806 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011807 if (num == TARGET_NR_removexattr) {
11808 ret = get_errno(removexattr(p, n));
11809 } else {
11810 ret = get_errno(lremovexattr(p, n));
11811 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011812 } else {
11813 ret = -TARGET_EFAULT;
11814 }
11815 unlock_user(p, arg1, 0);
11816 unlock_user(n, arg2, 0);
11817 }
11818 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011819 case TARGET_NR_fremovexattr:
11820 {
11821 void *n;
11822 n = lock_user_string(arg2);
11823 if (n) {
11824 ret = get_errno(fremovexattr(arg1, n));
11825 } else {
11826 ret = -TARGET_EFAULT;
11827 }
11828 unlock_user(n, arg2, 0);
11829 }
11830 break;
bellardebc05482003-09-30 21:08:41 +000011831#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011832#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011833#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011834 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011835#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011836 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011837 ret = 0;
11838 break;
edgar_iglef967792009-01-07 14:19:38 +000011839#elif defined(TARGET_CRIS)
11840 if (arg1 & 0xff)
11841 ret = -TARGET_EINVAL;
11842 else {
11843 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11844 ret = 0;
11845 }
11846 break;
bellard8d18e892007-11-14 15:18:40 +000011847#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11848 ret = do_set_thread_area(cpu_env, arg1);
11849 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011850#elif defined(TARGET_M68K)
11851 {
Andreas Färber0429a972013-08-26 18:14:44 +020011852 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011853 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011854 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011855 break;
11856 }
ths6f5b89a2007-03-02 20:48:00 +000011857#else
11858 goto unimplemented_nowarn;
11859#endif
11860#endif
11861#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011862 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011863#if defined(TARGET_I386) && defined(TARGET_ABI32)
11864 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011865 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011866#elif defined(TARGET_M68K)
11867 {
Andreas Färber0429a972013-08-26 18:14:44 +020011868 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011869 ret = ts->tp_value;
11870 break;
11871 }
bellard8d18e892007-11-14 15:18:40 +000011872#else
bellard5cd43932003-03-29 16:54:36 +000011873 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011874#endif
bellard8d18e892007-11-14 15:18:40 +000011875#endif
bellard48dc41e2006-06-21 18:15:50 +000011876#ifdef TARGET_NR_getdomainname
11877 case TARGET_NR_getdomainname:
11878 goto unimplemented_nowarn;
11879#endif
ths6f5b89a2007-03-02 20:48:00 +000011880
thsb5906f92007-03-19 13:32:45 +000011881#ifdef TARGET_NR_clock_gettime
11882 case TARGET_NR_clock_gettime:
11883 {
11884 struct timespec ts;
11885 ret = get_errno(clock_gettime(arg1, &ts));
11886 if (!is_error(ret)) {
11887 host_to_target_timespec(arg2, &ts);
11888 }
11889 break;
11890 }
11891#endif
11892#ifdef TARGET_NR_clock_getres
11893 case TARGET_NR_clock_getres:
11894 {
11895 struct timespec ts;
11896 ret = get_errno(clock_getres(arg1, &ts));
11897 if (!is_error(ret)) {
11898 host_to_target_timespec(arg2, &ts);
11899 }
11900 break;
11901 }
11902#endif
pbrook63d76512008-05-29 13:43:29 +000011903#ifdef TARGET_NR_clock_nanosleep
11904 case TARGET_NR_clock_nanosleep:
11905 {
11906 struct timespec ts;
11907 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011908 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11909 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011910 if (arg4)
11911 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011912
11913#if defined(TARGET_PPC)
11914 /* clock_nanosleep is odd in that it returns positive errno values.
11915 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011916 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011917 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11918 }
11919#endif
pbrook63d76512008-05-29 13:43:29 +000011920 break;
11921 }
11922#endif
thsb5906f92007-03-19 13:32:45 +000011923
ths6f5b89a2007-03-02 20:48:00 +000011924#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11925 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011926 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11927 break;
ths6f5b89a2007-03-02 20:48:00 +000011928#endif
11929
ths4cae1d12007-07-12 11:06:53 +000011930 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011931 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011932 break;
ths4cae1d12007-07-12 11:06:53 +000011933
ths71455572007-06-21 21:45:30 +000011934 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011935 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011936 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011937 break;
ths71455572007-06-21 21:45:30 +000011938
ths4f2b1fe2007-06-21 21:57:12 +000011939#ifdef TARGET_NR_set_robust_list
11940 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011941 case TARGET_NR_get_robust_list:
11942 /* The ABI for supporting robust futexes has userspace pass
11943 * the kernel a pointer to a linked list which is updated by
11944 * userspace after the syscall; the list is walked by the kernel
11945 * when the thread exits. Since the linked list in QEMU guest
11946 * memory isn't a valid linked list for the host and we have
11947 * no way to reliably intercept the thread-death event, we can't
11948 * support these. Silently return ENOSYS so that guest userspace
11949 * falls back to a non-robust futex implementation (which should
11950 * be OK except in the corner case of the guest crashing while
11951 * holding a mutex that is shared with another process via
11952 * shared memory).
11953 */
11954 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011955#endif
11956
Peter Maydell1acae9f2013-07-02 14:04:12 +010011957#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011958 case TARGET_NR_utimensat:
11959 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011960 struct timespec *tsp, ts[2];
11961 if (!arg3) {
11962 tsp = NULL;
11963 } else {
11964 target_to_host_timespec(ts, arg3);
11965 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11966 tsp = ts;
11967 }
ths9007f0e2007-09-25 17:50:37 +000011968 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011969 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011970 else {
bellard579a97f2007-11-11 14:26:47 +000011971 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011972 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011973 goto fail;
11974 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011975 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011976 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011977 }
11978 }
11979 break;
11980#endif
pbrookbd0c5662008-05-29 14:34:11 +000011981 case TARGET_NR_futex:
11982 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11983 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011984#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011985 case TARGET_NR_inotify_init:
11986 ret = get_errno(sys_inotify_init());
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011987 if (ret >= 0) {
11988 fd_trans_register(ret, &target_inotify_trans);
11989 }
aurel3239b59762008-10-01 21:46:50 +000011990 break;
11991#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011992#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011993#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11994 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010011995 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
11996 fcntl_flags_tbl)));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030011997 if (ret >= 0) {
11998 fd_trans_register(ret, &target_inotify_trans);
11999 }
Riku Voipioc05c7a72010-03-26 15:25:11 +000012000 break;
12001#endif
Stefan Weila1606b02010-03-28 11:44:41 +020012002#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012003#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000012004 case TARGET_NR_inotify_add_watch:
12005 p = lock_user_string(arg2);
12006 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
12007 unlock_user(p, arg2, 0);
12008 break;
12009#endif
aurel32dbfe4c32009-04-08 21:29:30 +000012010#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000012011 case TARGET_NR_inotify_rm_watch:
12012 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
12013 break;
12014#endif
ths9007f0e2007-09-25 17:50:37 +000012015
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070012016#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000012017 case TARGET_NR_mq_open:
12018 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012019 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010012020 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012021 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000012022
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012023 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010012024 pposix_mq_attr = NULL;
12025 if (arg4) {
12026 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
12027 goto efault;
12028 }
12029 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050012030 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020012031 p = lock_user_string(arg1 - 1);
12032 if (!p) {
12033 goto efault;
12034 }
Lena Djokic26400772016-11-24 17:08:58 +010012035 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000012036 unlock_user (p, arg1, 0);
12037 }
12038 break;
12039
12040 case TARGET_NR_mq_unlink:
12041 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010012042 if (!p) {
12043 ret = -TARGET_EFAULT;
12044 break;
12045 }
aurel3224e10032009-04-15 16:11:43 +000012046 ret = get_errno(mq_unlink(p));
12047 unlock_user (p, arg1, 0);
12048 break;
12049
12050 case TARGET_NR_mq_timedsend:
12051 {
12052 struct timespec ts;
12053
12054 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12055 if (arg5 != 0) {
12056 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012057 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000012058 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012059 } else {
12060 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000012061 }
aurel3224e10032009-04-15 16:11:43 +000012062 unlock_user (p, arg2, arg3);
12063 }
12064 break;
12065
12066 case TARGET_NR_mq_timedreceive:
12067 {
12068 struct timespec ts;
12069 unsigned int prio;
12070
12071 p = lock_user (VERIFY_READ, arg2, arg3, 1);
12072 if (arg5 != 0) {
12073 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012074 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12075 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000012076 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010012077 } else {
12078 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
12079 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000012080 }
aurel3224e10032009-04-15 16:11:43 +000012081 unlock_user (p, arg2, arg3);
12082 if (arg4 != 0)
12083 put_user_u32(prio, arg4);
12084 }
12085 break;
12086
12087 /* Not implemented for now... */
12088/* case TARGET_NR_mq_notify: */
12089/* break; */
12090
12091 case TARGET_NR_mq_getsetattr:
12092 {
12093 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
12094 ret = 0;
aurel3224e10032009-04-15 16:11:43 +000012095 if (arg2 != 0) {
12096 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
Max Filippova23ea402018-03-31 08:20:15 -070012097 ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
12098 &posix_mq_attr_out));
12099 } else if (arg3 != 0) {
12100 ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
aurel3224e10032009-04-15 16:11:43 +000012101 }
Max Filippova23ea402018-03-31 08:20:15 -070012102 if (ret == 0 && arg3 != 0) {
12103 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
12104 }
aurel3224e10032009-04-15 16:11:43 +000012105 }
12106 break;
12107#endif
12108
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012109#ifdef CONFIG_SPLICE
12110#ifdef TARGET_NR_tee
12111 case TARGET_NR_tee:
12112 {
12113 ret = get_errno(tee(arg1,arg2,arg3,arg4));
12114 }
12115 break;
12116#endif
12117#ifdef TARGET_NR_splice
12118 case TARGET_NR_splice:
12119 {
12120 loff_t loff_in, loff_out;
12121 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010012122 if (arg2) {
12123 if (get_user_u64(loff_in, arg2)) {
12124 goto efault;
12125 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012126 ploff_in = &loff_in;
12127 }
Andreas Schwab17644b32015-03-10 17:11:35 +010012128 if (arg4) {
12129 if (get_user_u64(loff_out, arg4)) {
12130 goto efault;
12131 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012132 ploff_out = &loff_out;
12133 }
12134 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010012135 if (arg2) {
12136 if (put_user_u64(loff_in, arg2)) {
12137 goto efault;
12138 }
12139 }
12140 if (arg4) {
12141 if (put_user_u64(loff_out, arg4)) {
12142 goto efault;
12143 }
12144 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012145 }
12146 break;
12147#endif
12148#ifdef TARGET_NR_vmsplice
12149 case TARGET_NR_vmsplice:
12150 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070012151 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
12152 if (vec != NULL) {
12153 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
12154 unlock_iovec(vec, arg2, arg3, 0);
12155 } else {
12156 ret = -host_to_target_errno(errno);
12157 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053012158 }
12159 break;
12160#endif
12161#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030012162#ifdef CONFIG_EVENTFD
12163#if defined(TARGET_NR_eventfd)
12164 case TARGET_NR_eventfd:
12165 ret = get_errno(eventfd(arg1, 0));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012166 if (ret >= 0) {
12167 fd_trans_register(ret, &target_eventfd_trans);
12168 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012169 break;
12170#endif
12171#if defined(TARGET_NR_eventfd2)
12172 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020012173 {
12174 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
12175 if (arg2 & TARGET_O_NONBLOCK) {
12176 host_flags |= O_NONBLOCK;
12177 }
12178 if (arg2 & TARGET_O_CLOEXEC) {
12179 host_flags |= O_CLOEXEC;
12180 }
12181 ret = get_errno(eventfd(arg1, host_flags));
Philippe Mathieu-Daudéb929f7e2017-07-26 23:42:19 -030012182 if (ret >= 0) {
12183 fd_trans_register(ret, &target_eventfd_trans);
12184 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012185 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020012186 }
Riku Voipioc2882b92009-08-12 15:08:24 +030012187#endif
12188#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030012189#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
12190 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010012191#if TARGET_ABI_BITS == 32
12192 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
12193 target_offset64(arg5, arg6)));
12194#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030012195 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010012196#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030012197 break;
12198#endif
Peter Maydellc727f472011-01-06 11:05:10 +000012199#if defined(CONFIG_SYNC_FILE_RANGE)
12200#if defined(TARGET_NR_sync_file_range)
12201 case TARGET_NR_sync_file_range:
12202#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030012203#if defined(TARGET_MIPS)
12204 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12205 target_offset64(arg5, arg6), arg7));
12206#else
Peter Maydellc727f472011-01-06 11:05:10 +000012207 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
12208 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030012209#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000012210#else
12211 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
12212#endif
12213 break;
12214#endif
12215#if defined(TARGET_NR_sync_file_range2)
12216 case TARGET_NR_sync_file_range2:
12217 /* This is like sync_file_range but the arguments are reordered */
12218#if TARGET_ABI_BITS == 32
12219 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
12220 target_offset64(arg5, arg6), arg2));
12221#else
12222 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
12223#endif
12224 break;
12225#endif
12226#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020012227#if defined(TARGET_NR_signalfd4)
12228 case TARGET_NR_signalfd4:
12229 ret = do_signalfd4(arg1, arg2, arg4);
12230 break;
12231#endif
12232#if defined(TARGET_NR_signalfd)
12233 case TARGET_NR_signalfd:
12234 ret = do_signalfd4(arg1, arg2, 0);
12235 break;
12236#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000012237#if defined(CONFIG_EPOLL)
12238#if defined(TARGET_NR_epoll_create)
12239 case TARGET_NR_epoll_create:
12240 ret = get_errno(epoll_create(arg1));
12241 break;
12242#endif
12243#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
12244 case TARGET_NR_epoll_create1:
12245 ret = get_errno(epoll_create1(arg1));
12246 break;
12247#endif
12248#if defined(TARGET_NR_epoll_ctl)
12249 case TARGET_NR_epoll_ctl:
12250 {
12251 struct epoll_event ep;
12252 struct epoll_event *epp = 0;
12253 if (arg4) {
12254 struct target_epoll_event *target_ep;
12255 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
12256 goto efault;
12257 }
12258 ep.events = tswap32(target_ep->events);
12259 /* The epoll_data_t union is just opaque data to the kernel,
12260 * so we transfer all 64 bits across and need not worry what
12261 * actual data type it is.
12262 */
12263 ep.data.u64 = tswap64(target_ep->data.u64);
12264 unlock_user_struct(target_ep, arg4, 0);
12265 epp = &ep;
12266 }
12267 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12268 break;
12269 }
12270#endif
12271
Peter Maydell227f0212016-06-06 19:58:11 +010012272#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012273#if defined(TARGET_NR_epoll_wait)
12274 case TARGET_NR_epoll_wait:
12275#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012276#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012277 case TARGET_NR_epoll_pwait:
12278#endif
12279 {
12280 struct target_epoll_event *target_ep;
12281 struct epoll_event *ep;
12282 int epfd = arg1;
12283 int maxevents = arg3;
12284 int timeout = arg4;
12285
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012286 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12287 ret = -TARGET_EINVAL;
12288 break;
12289 }
12290
Peter Maydell3b6edd12011-02-15 18:35:05 +000012291 target_ep = lock_user(VERIFY_WRITE, arg2,
12292 maxevents * sizeof(struct target_epoll_event), 1);
12293 if (!target_ep) {
12294 goto efault;
12295 }
12296
Peter Maydell04c95f42016-07-18 15:36:00 +010012297 ep = g_try_new(struct epoll_event, maxevents);
12298 if (!ep) {
12299 unlock_user(target_ep, arg2, 0);
12300 ret = -TARGET_ENOMEM;
12301 break;
12302 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012303
12304 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012305#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012306 case TARGET_NR_epoll_pwait:
12307 {
12308 target_sigset_t *target_set;
12309 sigset_t _set, *set = &_set;
12310
12311 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012312 if (arg6 != sizeof(target_sigset_t)) {
12313 ret = -TARGET_EINVAL;
12314 break;
12315 }
12316
Peter Maydell3b6edd12011-02-15 18:35:05 +000012317 target_set = lock_user(VERIFY_READ, arg5,
12318 sizeof(target_sigset_t), 1);
12319 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012320 ret = -TARGET_EFAULT;
12321 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012322 }
12323 target_to_host_sigset(set, target_set);
12324 unlock_user(target_set, arg5, 0);
12325 } else {
12326 set = NULL;
12327 }
12328
Peter Maydell227f0212016-06-06 19:58:11 +010012329 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12330 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012331 break;
12332 }
12333#endif
12334#if defined(TARGET_NR_epoll_wait)
12335 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012336 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12337 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012338 break;
12339#endif
12340 default:
12341 ret = -TARGET_ENOSYS;
12342 }
12343 if (!is_error(ret)) {
12344 int i;
12345 for (i = 0; i < ret; i++) {
12346 target_ep[i].events = tswap32(ep[i].events);
12347 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12348 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012349 unlock_user(target_ep, arg2,
12350 ret * sizeof(struct target_epoll_event));
12351 } else {
12352 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012353 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012354 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012355 break;
12356 }
12357#endif
12358#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012359#ifdef TARGET_NR_prlimit64
12360 case TARGET_NR_prlimit64:
12361 {
12362 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12363 struct target_rlimit64 *target_rnew, *target_rold;
12364 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012365 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012366 if (arg3) {
12367 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12368 goto efault;
12369 }
12370 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12371 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12372 unlock_user_struct(target_rnew, arg3, 0);
12373 rnewp = &rnew;
12374 }
12375
Felix Janda95018012014-12-02 22:11:17 +010012376 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012377 if (!is_error(ret) && arg4) {
12378 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12379 goto efault;
12380 }
12381 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12382 target_rold->rlim_max = tswap64(rold.rlim_max);
12383 unlock_user_struct(target_rold, arg4, 1);
12384 }
12385 break;
12386 }
12387#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012388#ifdef TARGET_NR_gethostname
12389 case TARGET_NR_gethostname:
12390 {
12391 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12392 if (name) {
12393 ret = get_errno(gethostname(name, arg2));
12394 unlock_user(name, arg1, arg2);
12395 } else {
12396 ret = -TARGET_EFAULT;
12397 }
12398 break;
12399 }
12400#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012401#ifdef TARGET_NR_atomic_cmpxchg_32
12402 case TARGET_NR_atomic_cmpxchg_32:
12403 {
12404 /* should use start_exclusive from main.c */
12405 abi_ulong mem_value;
12406 if (get_user_u32(mem_value, arg6)) {
12407 target_siginfo_t info;
12408 info.si_signo = SIGSEGV;
12409 info.si_errno = 0;
12410 info.si_code = TARGET_SEGV_MAPERR;
12411 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012412 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12413 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012414 ret = 0xdeadbeef;
12415
12416 }
12417 if (mem_value == arg2)
12418 put_user_u32(arg1, arg6);
12419 ret = mem_value;
12420 break;
12421 }
12422#endif
12423#ifdef TARGET_NR_atomic_barrier
12424 case TARGET_NR_atomic_barrier:
12425 {
12426 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012427 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012428 break;
12429 }
12430#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012431
12432#ifdef TARGET_NR_timer_create
12433 case TARGET_NR_timer_create:
12434 {
12435 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12436
12437 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012438
12439 int clkid = arg1;
12440 int timer_index = next_free_host_timer();
12441
12442 if (timer_index < 0) {
12443 ret = -TARGET_EAGAIN;
12444 } else {
12445 timer_t *phtimer = g_posix_timers + timer_index;
12446
12447 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012448 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012449 ret = target_to_host_sigevent(phost_sevp, arg2);
12450 if (ret != 0) {
12451 break;
12452 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012453 }
12454
12455 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12456 if (ret) {
12457 phtimer = NULL;
12458 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012459 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012460 goto efault;
12461 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012462 }
12463 }
12464 break;
12465 }
12466#endif
12467
12468#ifdef TARGET_NR_timer_settime
12469 case TARGET_NR_timer_settime:
12470 {
12471 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12472 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012473 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012474
Alexander Grafaecc8862014-11-10 21:33:03 +010012475 if (timerid < 0) {
12476 ret = timerid;
12477 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012478 ret = -TARGET_EINVAL;
12479 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012480 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012481 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12482
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012483 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12484 goto efault;
12485 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012486 ret = get_errno(
12487 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012488 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12489 goto efault;
12490 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012491 }
12492 break;
12493 }
12494#endif
12495
12496#ifdef TARGET_NR_timer_gettime
12497 case TARGET_NR_timer_gettime:
12498 {
12499 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012500 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012501
Alexander Grafaecc8862014-11-10 21:33:03 +010012502 if (timerid < 0) {
12503 ret = timerid;
12504 } else if (!arg2) {
12505 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012506 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012507 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012508 struct itimerspec hspec;
12509 ret = get_errno(timer_gettime(htimer, &hspec));
12510
12511 if (host_to_target_itimerspec(arg2, &hspec)) {
12512 ret = -TARGET_EFAULT;
12513 }
12514 }
12515 break;
12516 }
12517#endif
12518
12519#ifdef TARGET_NR_timer_getoverrun
12520 case TARGET_NR_timer_getoverrun:
12521 {
12522 /* args: timer_t timerid */
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;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012527 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012528 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012529 ret = get_errno(timer_getoverrun(htimer));
12530 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012531 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012532 break;
12533 }
12534#endif
12535
12536#ifdef TARGET_NR_timer_delete
12537 case TARGET_NR_timer_delete:
12538 {
12539 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012540 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012541
Alexander Grafaecc8862014-11-10 21:33:03 +010012542 if (timerid < 0) {
12543 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012544 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012545 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012546 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012547 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012548 }
12549 break;
12550 }
12551#endif
12552
Riku Voipio51834342014-06-22 11:25:42 +010012553#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12554 case TARGET_NR_timerfd_create:
12555 ret = get_errno(timerfd_create(arg1,
12556 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12557 break;
12558#endif
12559
12560#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12561 case TARGET_NR_timerfd_gettime:
12562 {
12563 struct itimerspec its_curr;
12564
12565 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12566
12567 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12568 goto efault;
12569 }
12570 }
12571 break;
12572#endif
12573
12574#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12575 case TARGET_NR_timerfd_settime:
12576 {
12577 struct itimerspec its_new, its_old, *p_new;
12578
12579 if (arg3) {
12580 if (target_to_host_itimerspec(&its_new, arg3)) {
12581 goto efault;
12582 }
12583 p_new = &its_new;
12584 } else {
12585 p_new = NULL;
12586 }
12587
12588 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12589
12590 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12591 goto efault;
12592 }
12593 }
12594 break;
12595#endif
12596
Paul Burtonab31cda2014-06-22 11:25:43 +010012597#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12598 case TARGET_NR_ioprio_get:
12599 ret = get_errno(ioprio_get(arg1, arg2));
12600 break;
12601#endif
12602
12603#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12604 case TARGET_NR_ioprio_set:
12605 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12606 break;
12607#endif
12608
Riku Voipio9af5c902014-08-12 15:58:57 +030012609#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12610 case TARGET_NR_setns:
12611 ret = get_errno(setns(arg1, arg2));
12612 break;
12613#endif
12614#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12615 case TARGET_NR_unshare:
12616 ret = get_errno(unshare(arg1));
12617 break;
12618#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012619#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12620 case TARGET_NR_kcmp:
12621 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12622 break;
12623#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012624
bellard31e31b82003-02-18 22:55:36 +000012625 default:
12626 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000012627 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012628#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 +000012629 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012630#endif
ths0da46a62007-10-20 20:23:07 +000012631 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012632 break;
12633 }
bellard579a97f2007-11-11 14:26:47 +000012634fail:
bellardc573ff62004-01-04 15:51:36 +000012635#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012636 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012637#endif
thsb92c47c2007-11-01 00:07:38 +000012638 if(do_strace)
12639 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020012640 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012641 return ret;
bellard579a97f2007-11-11 14:26:47 +000012642efault:
12643 ret = -TARGET_EFAULT;
12644 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012645}