blob: 11a311f9dbdb424b37d19c5a856f066080bca5e9 [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>
Aurelien Jarno60e99242010-03-29 02:12:51 +020039#ifdef __ia64__
40int __clone2(int (*fn)(void *), void *child_stack_base,
41 size_t stack_size, int flags, void *arg, ...);
42#endif
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000044#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000045#include <sys/uio.h>
Felix Janda0839f112016-09-30 19:40:21 -040046#include <poll.h>
bellard32f36bc2003-03-30 21:29:48 +000047#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000048#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000049#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000050#include <sys/statfs.h>
Aleksandar Markovic38860a02016-10-10 13:23:29 +020051#include <time.h>
bellardebc05482003-09-30 21:08:41 +000052#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000053#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020054#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000055//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000056#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000057#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020058#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000059#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020060#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030061#ifdef CONFIG_TIMERFD
62#include <sys/timerfd.h>
63#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020064#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000065#include <sys/gmon.h>
66#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030067#ifdef CONFIG_EVENTFD
68#include <sys/eventfd.h>
69#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000070#ifdef CONFIG_EPOLL
71#include <sys/epoll.h>
72#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070073#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010074#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070075#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000076#ifdef CONFIG_SENDFILE
77#include <sys/sendfile.h>
78#endif
bellard31e31b82003-02-18 22:55:36 +000079
80#define termios host_termios
81#define winsize host_winsize
82#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000083#define sgttyb host_sgttyb /* same as target */
84#define tchars host_tchars /* same as target */
85#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000086
87#include <linux/termios.h>
88#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000089#include <linux/cdrom.h>
90#include <linux/hdreg.h>
91#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000092#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000093#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030094#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000095#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000096#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000097#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020098#include <linux/fb.h>
99#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100100#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000101#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100102#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200103#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100104#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200105#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200106#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200107#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200108#include <linux/rtnetlink.h>
Laurent Vivierc5dff282016-06-27 18:54:30 +0200109#include <linux/if_bridge.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200110#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200111#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000112#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200113#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000114
bellard3ef693a2003-03-23 20:17:16 +0000115#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000116
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100117#ifndef CLONE_IO
118#define CLONE_IO 0x80000000 /* Clone io context */
119#endif
120
121/* We can't directly call the host clone syscall, because this will
122 * badly confuse libc (breaking mutexes, for example). So we must
123 * divide clone flags into:
124 * * flag combinations that look like pthread_create()
125 * * flag combinations that look like fork()
126 * * flags we can implement within QEMU itself
127 * * flags we can't support and will return an error for
128 */
129/* For thread creation, all these flags must be present; for
130 * fork, none must be present.
131 */
132#define CLONE_THREAD_FLAGS \
133 (CLONE_VM | CLONE_FS | CLONE_FILES | \
134 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
135
136/* These flags are ignored:
137 * CLONE_DETACHED is now ignored by the kernel;
138 * CLONE_IO is just an optimisation hint to the I/O scheduler
139 */
140#define CLONE_IGNORED_FLAGS \
141 (CLONE_DETACHED | CLONE_IO)
142
143/* Flags for fork which we can implement within QEMU itself */
144#define CLONE_OPTIONAL_FORK_FLAGS \
145 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
146 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
147
148/* Flags for thread creation which we can implement within QEMU itself */
149#define CLONE_OPTIONAL_THREAD_FLAGS \
150 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
151 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
152
153#define CLONE_INVALID_FORK_FLAGS \
154 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
155
156#define CLONE_INVALID_THREAD_FLAGS \
157 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
158 CLONE_IGNORED_FLAGS))
159
160/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
161 * have almost all been allocated. We cannot support any of
162 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
163 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
164 * The checks against the invalid thread masks above will catch these.
165 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
166 */
pbrook30813ce2008-06-02 15:45:44 +0000167
bellard72f03902003-02-18 23:33:18 +0000168//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100169/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
170 * once. This exercises the codepaths for restart.
171 */
172//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000173
bellard1a9353d2003-03-16 20:28:50 +0000174//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000175#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
176#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000177
bellard70a194b2003-08-11 22:20:16 +0000178#undef _syscall0
179#undef _syscall1
180#undef _syscall2
181#undef _syscall3
182#undef _syscall4
183#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000184#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000185
bellard83fcb512006-06-14 13:37:16 +0000186#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000187static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000188{ \
189 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000190}
191
bellard83fcb512006-06-14 13:37:16 +0000192#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000193static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000194{ \
195 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000196}
197
bellard83fcb512006-06-14 13:37:16 +0000198#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000199static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000200{ \
201 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000202}
203
bellard83fcb512006-06-14 13:37:16 +0000204#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000205static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000206{ \
207 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000208}
209
bellard83fcb512006-06-14 13:37:16 +0000210#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000211static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000212{ \
213 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000214}
215
bellard83fcb512006-06-14 13:37:16 +0000216#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
217 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000218static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000219{ \
220 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000221}
bellard83fcb512006-06-14 13:37:16 +0000222
223
224#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
225 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000226static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
227 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000228{ \
229 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
230}
231
bellard70a194b2003-08-11 22:20:16 +0000232
bellard31e31b82003-02-18 22:55:36 +0000233#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000234#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000235#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000236#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000237#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000238#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000239#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000240#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000241#define __NR_sys_inotify_init __NR_inotify_init
242#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
243#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000244
Alexander Graf42a39fb2011-04-15 17:32:45 +0200245#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
246 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000247#define __NR__llseek __NR_lseek
248#endif
249
James Hogana29e5ba2014-03-25 21:51:08 +0000250/* Newer kernel ports have llseek() instead of _llseek() */
251#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
252#define TARGET_NR__llseek TARGET_NR_llseek
253#endif
254
bellard72f03902003-02-18 23:33:18 +0000255#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000256_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000257#else
ths0da46a62007-10-20 20:23:07 +0000258/* This is a replacement for the host gettid() and must return a host
259 errno. */
bellard72f03902003-02-18 23:33:18 +0000260static int gettid(void) {
261 return -ENOSYS;
262}
263#endif
Chen Gang704eff62015-08-21 05:37:33 +0800264#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000265_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100266#endif
267#if !defined(__NR_getdents) || \
268 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000269_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
270#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700271#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000272_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
273 loff_t *, res, uint, wh);
274#endif
275_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
276_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);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200293_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
294 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000295_syscall2(int, capget, struct __user_cap_header_struct *, header,
296 struct __user_cap_data_struct *, data);
297_syscall2(int, capset, struct __user_cap_header_struct *, header,
298 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100299#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
300_syscall2(int, ioprio_get, int, which, int, who)
301#endif
302#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
303_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
304#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100305#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
306_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
307#endif
aurel323b3f24a2009-04-15 16:12:13 +0000308
Laurent Vivier2f147882016-09-25 22:20:20 +0200309#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
310_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
311 unsigned long, idx1, unsigned long, idx2)
312#endif
313
aurel323b3f24a2009-04-15 16:12:13 +0000314static bitmask_transtbl fcntl_flags_tbl[] = {
315 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
316 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
317 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
318 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
319 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
320 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
321 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
322 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700323 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000324 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
325 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
326 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
327 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000328#if defined(O_DIRECT)
329 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
330#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700331#if defined(O_NOATIME)
332 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
333#endif
334#if defined(O_CLOEXEC)
335 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
336#endif
337#if defined(O_PATH)
338 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
339#endif
340 /* Don't terminate the list prematurely on 64-bit host+guest. */
341#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
342 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
343#endif
aurel323b3f24a2009-04-15 16:12:13 +0000344 { 0, 0, 0, 0 }
345};
346
Michal Privoznik60c6b792016-08-19 10:06:40 +0200347enum {
348 QEMU_IFLA_BR_UNSPEC,
349 QEMU_IFLA_BR_FORWARD_DELAY,
350 QEMU_IFLA_BR_HELLO_TIME,
351 QEMU_IFLA_BR_MAX_AGE,
352 QEMU_IFLA_BR_AGEING_TIME,
353 QEMU_IFLA_BR_STP_STATE,
354 QEMU_IFLA_BR_PRIORITY,
355 QEMU_IFLA_BR_VLAN_FILTERING,
356 QEMU_IFLA_BR_VLAN_PROTOCOL,
357 QEMU_IFLA_BR_GROUP_FWD_MASK,
358 QEMU_IFLA_BR_ROOT_ID,
359 QEMU_IFLA_BR_BRIDGE_ID,
360 QEMU_IFLA_BR_ROOT_PORT,
361 QEMU_IFLA_BR_ROOT_PATH_COST,
362 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
363 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
364 QEMU_IFLA_BR_HELLO_TIMER,
365 QEMU_IFLA_BR_TCN_TIMER,
366 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
367 QEMU_IFLA_BR_GC_TIMER,
368 QEMU_IFLA_BR_GROUP_ADDR,
369 QEMU_IFLA_BR_FDB_FLUSH,
370 QEMU_IFLA_BR_MCAST_ROUTER,
371 QEMU_IFLA_BR_MCAST_SNOOPING,
372 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
373 QEMU_IFLA_BR_MCAST_QUERIER,
374 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
375 QEMU_IFLA_BR_MCAST_HASH_MAX,
376 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
377 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
378 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
379 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
380 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
381 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
382 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
383 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
384 QEMU_IFLA_BR_NF_CALL_IPTABLES,
385 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
386 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
387 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
388 QEMU_IFLA_BR_PAD,
389 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
390 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
391 QEMU___IFLA_BR_MAX,
392};
393
394enum {
395 QEMU_IFLA_UNSPEC,
396 QEMU_IFLA_ADDRESS,
397 QEMU_IFLA_BROADCAST,
398 QEMU_IFLA_IFNAME,
399 QEMU_IFLA_MTU,
400 QEMU_IFLA_LINK,
401 QEMU_IFLA_QDISC,
402 QEMU_IFLA_STATS,
403 QEMU_IFLA_COST,
404 QEMU_IFLA_PRIORITY,
405 QEMU_IFLA_MASTER,
406 QEMU_IFLA_WIRELESS,
407 QEMU_IFLA_PROTINFO,
408 QEMU_IFLA_TXQLEN,
409 QEMU_IFLA_MAP,
410 QEMU_IFLA_WEIGHT,
411 QEMU_IFLA_OPERSTATE,
412 QEMU_IFLA_LINKMODE,
413 QEMU_IFLA_LINKINFO,
414 QEMU_IFLA_NET_NS_PID,
415 QEMU_IFLA_IFALIAS,
416 QEMU_IFLA_NUM_VF,
417 QEMU_IFLA_VFINFO_LIST,
418 QEMU_IFLA_STATS64,
419 QEMU_IFLA_VF_PORTS,
420 QEMU_IFLA_PORT_SELF,
421 QEMU_IFLA_AF_SPEC,
422 QEMU_IFLA_GROUP,
423 QEMU_IFLA_NET_NS_FD,
424 QEMU_IFLA_EXT_MASK,
425 QEMU_IFLA_PROMISCUITY,
426 QEMU_IFLA_NUM_TX_QUEUES,
427 QEMU_IFLA_NUM_RX_QUEUES,
428 QEMU_IFLA_CARRIER,
429 QEMU_IFLA_PHYS_PORT_ID,
430 QEMU_IFLA_CARRIER_CHANGES,
431 QEMU_IFLA_PHYS_SWITCH_ID,
432 QEMU_IFLA_LINK_NETNSID,
433 QEMU_IFLA_PHYS_PORT_NAME,
434 QEMU_IFLA_PROTO_DOWN,
435 QEMU_IFLA_GSO_MAX_SEGS,
436 QEMU_IFLA_GSO_MAX_SIZE,
437 QEMU_IFLA_PAD,
438 QEMU_IFLA_XDP,
439 QEMU___IFLA_MAX
440};
441
442enum {
443 QEMU_IFLA_BRPORT_UNSPEC,
444 QEMU_IFLA_BRPORT_STATE,
445 QEMU_IFLA_BRPORT_PRIORITY,
446 QEMU_IFLA_BRPORT_COST,
447 QEMU_IFLA_BRPORT_MODE,
448 QEMU_IFLA_BRPORT_GUARD,
449 QEMU_IFLA_BRPORT_PROTECT,
450 QEMU_IFLA_BRPORT_FAST_LEAVE,
451 QEMU_IFLA_BRPORT_LEARNING,
452 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
453 QEMU_IFLA_BRPORT_PROXYARP,
454 QEMU_IFLA_BRPORT_LEARNING_SYNC,
455 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
456 QEMU_IFLA_BRPORT_ROOT_ID,
457 QEMU_IFLA_BRPORT_BRIDGE_ID,
458 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
459 QEMU_IFLA_BRPORT_DESIGNATED_COST,
460 QEMU_IFLA_BRPORT_ID,
461 QEMU_IFLA_BRPORT_NO,
462 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
463 QEMU_IFLA_BRPORT_CONFIG_PENDING,
464 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
465 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
466 QEMU_IFLA_BRPORT_HOLD_TIMER,
467 QEMU_IFLA_BRPORT_FLUSH,
468 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
469 QEMU_IFLA_BRPORT_PAD,
470 QEMU___IFLA_BRPORT_MAX
471};
472
473enum {
474 QEMU_IFLA_INFO_UNSPEC,
475 QEMU_IFLA_INFO_KIND,
476 QEMU_IFLA_INFO_DATA,
477 QEMU_IFLA_INFO_XSTATS,
478 QEMU_IFLA_INFO_SLAVE_KIND,
479 QEMU_IFLA_INFO_SLAVE_DATA,
480 QEMU___IFLA_INFO_MAX,
481};
482
483enum {
484 QEMU_IFLA_INET_UNSPEC,
485 QEMU_IFLA_INET_CONF,
486 QEMU___IFLA_INET_MAX,
487};
488
489enum {
490 QEMU_IFLA_INET6_UNSPEC,
491 QEMU_IFLA_INET6_FLAGS,
492 QEMU_IFLA_INET6_CONF,
493 QEMU_IFLA_INET6_STATS,
494 QEMU_IFLA_INET6_MCAST,
495 QEMU_IFLA_INET6_CACHEINFO,
496 QEMU_IFLA_INET6_ICMP6STATS,
497 QEMU_IFLA_INET6_TOKEN,
498 QEMU_IFLA_INET6_ADDR_GEN_MODE,
499 QEMU___IFLA_INET6_MAX
500};
501
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100502typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100503typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200504typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100505 TargetFdDataFunc host_to_target_data;
506 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100507 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200508} TargetFdTrans;
509
510static TargetFdTrans **target_fd_trans;
511
512static unsigned int target_fd_max;
513
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200514static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
515{
516 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
517 return target_fd_trans[fd]->target_to_host_data;
518 }
519 return NULL;
520}
521
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100522static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200523{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100524 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100525 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200526 }
527 return NULL;
528}
529
Laurent Vivier7b36f782015-10-28 21:40:44 +0100530static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
531{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100532 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100533 return target_fd_trans[fd]->target_to_host_addr;
534 }
535 return NULL;
536}
537
Laurent Viviere36800c2015-10-02 14:48:09 +0200538static void fd_trans_register(int fd, TargetFdTrans *trans)
539{
540 unsigned int oldmax;
541
542 if (fd >= target_fd_max) {
543 oldmax = target_fd_max;
544 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100545 target_fd_trans = g_renew(TargetFdTrans *,
546 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200547 memset((void *)(target_fd_trans + oldmax), 0,
548 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
549 }
550 target_fd_trans[fd] = trans;
551}
552
553static void fd_trans_unregister(int fd)
554{
555 if (fd >= 0 && fd < target_fd_max) {
556 target_fd_trans[fd] = NULL;
557 }
558}
559
560static void fd_trans_dup(int oldfd, int newfd)
561{
562 fd_trans_unregister(newfd);
563 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
564 fd_trans_register(newfd, target_fd_trans[oldfd]);
565 }
566}
567
aurel323b3f24a2009-04-15 16:12:13 +0000568static int sys_getcwd1(char *buf, size_t size)
569{
570 if (getcwd(buf, size) == NULL) {
571 /* getcwd() sets errno */
572 return (-1);
573 }
aurel32aaf4ad32009-04-16 14:17:14 +0000574 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000575}
576
Peter Maydell1acae9f2013-07-02 14:04:12 +0100577#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100578#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100579#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000580_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
581 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100582#else
583static int sys_utimensat(int dirfd, const char *pathname,
584 const struct timespec times[2], int flags)
585{
586 errno = ENOSYS;
587 return -1;
588}
ths9007f0e2007-09-25 17:50:37 +0000589#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100590#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000591
592#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000593#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000594
aurel3239b59762008-10-01 21:46:50 +0000595#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000596static int sys_inotify_init(void)
597{
598 return (inotify_init());
599}
aurel3239b59762008-10-01 21:46:50 +0000600#endif
601#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000602static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
603{
604 return (inotify_add_watch(fd, pathname, mask));
605}
aurel3239b59762008-10-01 21:46:50 +0000606#endif
607#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000608static int sys_inotify_rm_watch(int fd, int32_t wd)
609{
aurel328690e422009-04-17 13:50:32 +0000610 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000611}
aurel3239b59762008-10-01 21:46:50 +0000612#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000613#ifdef CONFIG_INOTIFY1
614#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
615static int sys_inotify_init1(int flags)
616{
617 return (inotify_init1(flags));
618}
619#endif
620#endif
aurel323b3f24a2009-04-15 16:12:13 +0000621#else
622/* Userspace can usually survive runtime without inotify */
623#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000624#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000625#undef TARGET_NR_inotify_add_watch
626#undef TARGET_NR_inotify_rm_watch
627#endif /* CONFIG_INOTIFY */
628
Peter Maydell163a05a2011-06-27 17:44:52 +0100629#if defined(TARGET_NR_prlimit64)
630#ifndef __NR_prlimit64
631# define __NR_prlimit64 -1
632#endif
633#define __NR_sys_prlimit64 __NR_prlimit64
634/* The glibc rlimit structure may not be that used by the underlying syscall */
635struct host_rlimit64 {
636 uint64_t rlim_cur;
637 uint64_t rlim_max;
638};
639_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
640 const struct host_rlimit64 *, new_limit,
641 struct host_rlimit64 *, old_limit)
642#endif
643
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100644
645#if defined(TARGET_NR_timer_create)
646/* Maxiumum of 32 active POSIX timers allowed at any one time. */
647static timer_t g_posix_timers[32] = { 0, } ;
648
649static inline int next_free_host_timer(void)
650{
651 int k ;
652 /* FIXME: Does finding the next free slot require a lock? */
653 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
654 if (g_posix_timers[k] == 0) {
655 g_posix_timers[k] = (timer_t) 1;
656 return k;
657 }
658 }
659 return -1;
660}
661#endif
662
Riku Voipio48e515d2011-07-12 15:40:51 +0300663/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000664#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300665static inline int regpairs_aligned(void *cpu_env) {
666 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
667}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200668#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
Riku Voipio48e515d2011-07-12 15:40:51 +0300669static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000670#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
671/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
672 * of registers which translates to the same as ARM/MIPS, because we start with
673 * r3 as arg1 */
674static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300675#else
676static inline int regpairs_aligned(void *cpu_env) { return 0; }
677#endif
678
thsb92c47c2007-11-01 00:07:38 +0000679#define ERRNO_TABLE_SIZE 1200
680
681/* target_to_host_errno_table[] is initialized from
682 * host_to_target_errno_table[] in syscall_init(). */
683static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
684};
685
ths637947f2007-06-01 12:09:19 +0000686/*
thsfe8f0962007-07-12 10:59:21 +0000687 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000688 * minus the errnos that are not actually generic to all archs.
689 */
thsb92c47c2007-11-01 00:07:38 +0000690static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800691 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000692 [EIDRM] = TARGET_EIDRM,
693 [ECHRNG] = TARGET_ECHRNG,
694 [EL2NSYNC] = TARGET_EL2NSYNC,
695 [EL3HLT] = TARGET_EL3HLT,
696 [EL3RST] = TARGET_EL3RST,
697 [ELNRNG] = TARGET_ELNRNG,
698 [EUNATCH] = TARGET_EUNATCH,
699 [ENOCSI] = TARGET_ENOCSI,
700 [EL2HLT] = TARGET_EL2HLT,
701 [EDEADLK] = TARGET_EDEADLK,
702 [ENOLCK] = TARGET_ENOLCK,
703 [EBADE] = TARGET_EBADE,
704 [EBADR] = TARGET_EBADR,
705 [EXFULL] = TARGET_EXFULL,
706 [ENOANO] = TARGET_ENOANO,
707 [EBADRQC] = TARGET_EBADRQC,
708 [EBADSLT] = TARGET_EBADSLT,
709 [EBFONT] = TARGET_EBFONT,
710 [ENOSTR] = TARGET_ENOSTR,
711 [ENODATA] = TARGET_ENODATA,
712 [ETIME] = TARGET_ETIME,
713 [ENOSR] = TARGET_ENOSR,
714 [ENONET] = TARGET_ENONET,
715 [ENOPKG] = TARGET_ENOPKG,
716 [EREMOTE] = TARGET_EREMOTE,
717 [ENOLINK] = TARGET_ENOLINK,
718 [EADV] = TARGET_EADV,
719 [ESRMNT] = TARGET_ESRMNT,
720 [ECOMM] = TARGET_ECOMM,
721 [EPROTO] = TARGET_EPROTO,
722 [EDOTDOT] = TARGET_EDOTDOT,
723 [EMULTIHOP] = TARGET_EMULTIHOP,
724 [EBADMSG] = TARGET_EBADMSG,
725 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
726 [EOVERFLOW] = TARGET_EOVERFLOW,
727 [ENOTUNIQ] = TARGET_ENOTUNIQ,
728 [EBADFD] = TARGET_EBADFD,
729 [EREMCHG] = TARGET_EREMCHG,
730 [ELIBACC] = TARGET_ELIBACC,
731 [ELIBBAD] = TARGET_ELIBBAD,
732 [ELIBSCN] = TARGET_ELIBSCN,
733 [ELIBMAX] = TARGET_ELIBMAX,
734 [ELIBEXEC] = TARGET_ELIBEXEC,
735 [EILSEQ] = TARGET_EILSEQ,
736 [ENOSYS] = TARGET_ENOSYS,
737 [ELOOP] = TARGET_ELOOP,
738 [ERESTART] = TARGET_ERESTART,
739 [ESTRPIPE] = TARGET_ESTRPIPE,
740 [ENOTEMPTY] = TARGET_ENOTEMPTY,
741 [EUSERS] = TARGET_EUSERS,
742 [ENOTSOCK] = TARGET_ENOTSOCK,
743 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
744 [EMSGSIZE] = TARGET_EMSGSIZE,
745 [EPROTOTYPE] = TARGET_EPROTOTYPE,
746 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
747 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
748 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
749 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
750 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
751 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
752 [EADDRINUSE] = TARGET_EADDRINUSE,
753 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
754 [ENETDOWN] = TARGET_ENETDOWN,
755 [ENETUNREACH] = TARGET_ENETUNREACH,
756 [ENETRESET] = TARGET_ENETRESET,
757 [ECONNABORTED] = TARGET_ECONNABORTED,
758 [ECONNRESET] = TARGET_ECONNRESET,
759 [ENOBUFS] = TARGET_ENOBUFS,
760 [EISCONN] = TARGET_EISCONN,
761 [ENOTCONN] = TARGET_ENOTCONN,
762 [EUCLEAN] = TARGET_EUCLEAN,
763 [ENOTNAM] = TARGET_ENOTNAM,
764 [ENAVAIL] = TARGET_ENAVAIL,
765 [EISNAM] = TARGET_EISNAM,
766 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200767 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000768 [ESHUTDOWN] = TARGET_ESHUTDOWN,
769 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
770 [ETIMEDOUT] = TARGET_ETIMEDOUT,
771 [ECONNREFUSED] = TARGET_ECONNREFUSED,
772 [EHOSTDOWN] = TARGET_EHOSTDOWN,
773 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
774 [EALREADY] = TARGET_EALREADY,
775 [EINPROGRESS] = TARGET_EINPROGRESS,
776 [ESTALE] = TARGET_ESTALE,
777 [ECANCELED] = TARGET_ECANCELED,
778 [ENOMEDIUM] = TARGET_ENOMEDIUM,
779 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000780#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000781 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000782#endif
783#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000784 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000785#endif
786#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000787 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000788#endif
789#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000790 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000791#endif
792#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000793 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000794#endif
795#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000796 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000797#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200798#ifdef ENOMSG
799 [ENOMSG] = TARGET_ENOMSG,
800#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800801#ifdef ERKFILL
802 [ERFKILL] = TARGET_ERFKILL,
803#endif
804#ifdef EHWPOISON
805 [EHWPOISON] = TARGET_EHWPOISON,
806#endif
thsb92c47c2007-11-01 00:07:38 +0000807};
ths637947f2007-06-01 12:09:19 +0000808
809static inline int host_to_target_errno(int err)
810{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100811 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
812 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000813 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100814 }
ths637947f2007-06-01 12:09:19 +0000815 return err;
816}
817
thsb92c47c2007-11-01 00:07:38 +0000818static inline int target_to_host_errno(int err)
819{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100820 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
821 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000822 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100823 }
thsb92c47c2007-11-01 00:07:38 +0000824 return err;
825}
826
blueswir1992f48a2007-10-14 16:27:31 +0000827static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000828{
829 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000830 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000831 else
832 return ret;
833}
834
blueswir1992f48a2007-10-14 16:27:31 +0000835static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000836{
blueswir1992f48a2007-10-14 16:27:31 +0000837 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000838}
839
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100840const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000841{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100842 if (err == TARGET_ERESTARTSYS) {
843 return "To be restarted";
844 }
845 if (err == TARGET_QEMU_ESIGRETURN) {
846 return "Successful exit from sigreturn";
847 }
848
Alexander Graf962b2892011-11-21 12:04:07 +0100849 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
850 return NULL;
851 }
thsb92c47c2007-11-01 00:07:38 +0000852 return strerror(target_to_host_errno(err));
853}
854
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100855#define safe_syscall0(type, name) \
856static type safe_##name(void) \
857{ \
858 return safe_syscall(__NR_##name); \
859}
860
861#define safe_syscall1(type, name, type1, arg1) \
862static type safe_##name(type1 arg1) \
863{ \
864 return safe_syscall(__NR_##name, arg1); \
865}
866
867#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
868static type safe_##name(type1 arg1, type2 arg2) \
869{ \
870 return safe_syscall(__NR_##name, arg1, arg2); \
871}
872
873#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
874static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
875{ \
876 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
877}
878
879#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
880 type4, arg4) \
881static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
882{ \
883 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
884}
885
886#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
887 type4, arg4, type5, arg5) \
888static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
889 type5 arg5) \
890{ \
891 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
892}
893
894#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
895 type4, arg4, type5, arg5, type6, arg6) \
896static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
897 type5 arg5, type6 arg6) \
898{ \
899 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
900}
901
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100902safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
903safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100904safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
905 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100906safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
907 struct rusage *, rusage)
908safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
909 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100910safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100911safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
912 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100913safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
914 struct timespec *, tsp, const sigset_t *, sigmask,
915 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100916safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
917 int, maxevents, int, timeout, const sigset_t *, sigmask,
918 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100919safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
920 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100921safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100922safe_syscall2(int, kill, pid_t, pid, int, sig)
923safe_syscall2(int, tkill, int, tid, int, sig)
924safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100925safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
926safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200927safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
928 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200929safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
930 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100931safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
932 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100933safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
934 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
935safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
936 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
937safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
938safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100939safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100940safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
941 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100942safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
943 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100944safe_syscall2(int, nanosleep, const struct timespec *, req,
945 struct timespec *, rem)
946#ifdef TARGET_NR_clock_nanosleep
947safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
948 const struct timespec *, req, struct timespec *, rem)
949#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100950#ifdef __NR_msgsnd
951safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
952 int, flags)
953safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
954 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100955safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
956 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100957#else
958/* This host kernel architecture uses a single ipc syscall; fake up
959 * wrappers for the sub-operations to hide this implementation detail.
960 * Annoyingly we can't include linux/ipc.h to get the constant definitions
961 * for the call parameter because some structs in there conflict with the
962 * sys/ipc.h ones. So we just define them here, and rely on them being
963 * the same for all host architectures.
964 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100965#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100966#define Q_MSGSND 11
967#define Q_MSGRCV 12
968#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
969
970safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
971 void *, ptr, long, fifth)
972static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
973{
974 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
975}
976static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
977{
978 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
979}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100980static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
981 const struct timespec *timeout)
982{
983 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
984 (long)timeout);
985}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100986#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100987#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
988safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
989 size_t, len, unsigned, prio, const struct timespec *, timeout)
990safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
991 size_t, len, unsigned *, prio, const struct timespec *, timeout)
992#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100993/* We do ioctl like this rather than via safe_syscall3 to preserve the
994 * "third argument might be integer or pointer or not present" behaviour of
995 * the libc function.
996 */
997#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +0100998/* Similarly for fcntl. Note that callers must always:
999 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1000 * use the flock64 struct rather than unsuffixed flock
1001 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1002 */
1003#ifdef __NR_fcntl64
1004#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1005#else
1006#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1007#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001008
Paul Burton8289d112014-06-22 11:25:33 +01001009static inline int host_to_target_sock_type(int host_type)
1010{
1011 int target_type;
1012
1013 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1014 case SOCK_DGRAM:
1015 target_type = TARGET_SOCK_DGRAM;
1016 break;
1017 case SOCK_STREAM:
1018 target_type = TARGET_SOCK_STREAM;
1019 break;
1020 default:
1021 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1022 break;
1023 }
1024
1025#if defined(SOCK_CLOEXEC)
1026 if (host_type & SOCK_CLOEXEC) {
1027 target_type |= TARGET_SOCK_CLOEXEC;
1028 }
1029#endif
1030
1031#if defined(SOCK_NONBLOCK)
1032 if (host_type & SOCK_NONBLOCK) {
1033 target_type |= TARGET_SOCK_NONBLOCK;
1034 }
1035#endif
1036
1037 return target_type;
1038}
1039
blueswir1992f48a2007-10-14 16:27:31 +00001040static abi_ulong target_brk;
1041static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001042static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001043
blueswir1992f48a2007-10-14 16:27:31 +00001044void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001045{
blueswir14c1de732007-07-07 20:45:44 +00001046 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001047 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001048}
1049
vincent4d1de872011-06-14 21:56:33 +00001050//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1051#define DEBUGF_BRK(message, args...)
1052
ths0da46a62007-10-20 20:23:07 +00001053/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001054abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001055{
blueswir1992f48a2007-10-14 16:27:31 +00001056 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001057 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001058
Paul Brook3a0c6c42012-02-09 19:04:27 +00001059 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001060
vincent4d1de872011-06-14 21:56:33 +00001061 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001062 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001063 return target_brk;
1064 }
1065 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001066 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1067 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001068 return target_brk;
1069 }
bellard31e31b82003-02-18 22:55:36 +00001070
vincent4d1de872011-06-14 21:56:33 +00001071 /* If the new brk is less than the highest page reserved to the
1072 * target heap allocation, set it and we're almost done... */
1073 if (new_brk <= brk_page) {
1074 /* Heap contents are initialized to zero, as for anonymous
1075 * mapped pages. */
1076 if (new_brk > target_brk) {
1077 memset(g2h(target_brk), 0, new_brk - target_brk);
1078 }
bellard31e31b82003-02-18 22:55:36 +00001079 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001080 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001081 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001082 }
1083
Peter Maydell00faf082011-04-18 16:34:24 +01001084 /* We need to allocate more memory after the brk... Note that
1085 * we don't use MAP_FIXED because that will map over the top of
1086 * any existing mapping (like the one with the host libc or qemu
1087 * itself); instead we treat "mapped but at wrong address" as
1088 * a failure and unmap again.
1089 */
vincent4d1de872011-06-14 21:56:33 +00001090 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001091 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001092 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001093 MAP_ANON|MAP_PRIVATE, 0, 0));
1094
1095 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001096 /* Heap contents are initialized to zero, as for anonymous
1097 * mapped pages. Technically the new pages are already
1098 * initialized to zero since they *are* anonymous mapped
1099 * pages, however we have to take care with the contents that
1100 * come from the remaining part of the previous page: it may
1101 * contains garbage data due to a previous heap usage (grown
1102 * then shrunken). */
1103 memset(g2h(target_brk), 0, brk_page - target_brk);
1104
Peter Maydell00faf082011-04-18 16:34:24 +01001105 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001106 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001107 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1108 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001109 return target_brk;
1110 } else if (mapped_addr != -1) {
1111 /* Mapped but at wrong address, meaning there wasn't actually
1112 * enough space for this brk.
1113 */
1114 target_munmap(mapped_addr, new_alloc_size);
1115 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001116 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001117 }
1118 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001119 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001120 }
balrog7ab240a2008-04-26 12:17:34 +00001121
Richard Henderson7dd46c02010-05-03 10:07:49 -07001122#if defined(TARGET_ALPHA)
1123 /* We (partially) emulate OSF/1 on Alpha, which requires we
1124 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001125 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001126#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001127 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001128 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001129}
1130
ths26edcf42007-12-09 02:25:24 +00001131static inline abi_long copy_from_user_fdset(fd_set *fds,
1132 abi_ulong target_fds_addr,
1133 int n)
bellard31e31b82003-02-18 22:55:36 +00001134{
ths26edcf42007-12-09 02:25:24 +00001135 int i, nw, j, k;
1136 abi_ulong b, *target_fds;
1137
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001138 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001139 if (!(target_fds = lock_user(VERIFY_READ,
1140 target_fds_addr,
1141 sizeof(abi_ulong) * nw,
1142 1)))
1143 return -TARGET_EFAULT;
1144
1145 FD_ZERO(fds);
1146 k = 0;
1147 for (i = 0; i < nw; i++) {
1148 /* grab the abi_ulong */
1149 __get_user(b, &target_fds[i]);
1150 for (j = 0; j < TARGET_ABI_BITS; j++) {
1151 /* check the bit inside the abi_ulong */
1152 if ((b >> j) & 1)
1153 FD_SET(k, fds);
1154 k++;
bellard31e31b82003-02-18 22:55:36 +00001155 }
bellard31e31b82003-02-18 22:55:36 +00001156 }
ths26edcf42007-12-09 02:25:24 +00001157
1158 unlock_user(target_fds, target_fds_addr, 0);
1159
1160 return 0;
bellard31e31b82003-02-18 22:55:36 +00001161}
1162
Mike Frysinger055e0902011-06-03 17:01:49 -04001163static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1164 abi_ulong target_fds_addr,
1165 int n)
1166{
1167 if (target_fds_addr) {
1168 if (copy_from_user_fdset(fds, target_fds_addr, n))
1169 return -TARGET_EFAULT;
1170 *fds_ptr = fds;
1171 } else {
1172 *fds_ptr = NULL;
1173 }
1174 return 0;
1175}
1176
ths26edcf42007-12-09 02:25:24 +00001177static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1178 const fd_set *fds,
1179 int n)
bellard31e31b82003-02-18 22:55:36 +00001180{
bellard31e31b82003-02-18 22:55:36 +00001181 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001182 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001183 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001184
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001185 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001186 if (!(target_fds = lock_user(VERIFY_WRITE,
1187 target_fds_addr,
1188 sizeof(abi_ulong) * nw,
1189 0)))
1190 return -TARGET_EFAULT;
1191
1192 k = 0;
1193 for (i = 0; i < nw; i++) {
1194 v = 0;
1195 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001196 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001197 k++;
bellard31e31b82003-02-18 22:55:36 +00001198 }
ths26edcf42007-12-09 02:25:24 +00001199 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001200 }
ths26edcf42007-12-09 02:25:24 +00001201
1202 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1203
1204 return 0;
bellard31e31b82003-02-18 22:55:36 +00001205}
1206
bellardc596ed12003-07-13 17:32:31 +00001207#if defined(__alpha__)
1208#define HOST_HZ 1024
1209#else
1210#define HOST_HZ 100
1211#endif
1212
blueswir1992f48a2007-10-14 16:27:31 +00001213static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001214{
1215#if HOST_HZ == TARGET_HZ
1216 return ticks;
1217#else
1218 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1219#endif
1220}
1221
bellard579a97f2007-11-11 14:26:47 +00001222static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1223 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001224{
pbrook53a59602006-03-25 19:31:22 +00001225 struct target_rusage *target_rusage;
1226
bellard579a97f2007-11-11 14:26:47 +00001227 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1228 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001229 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1230 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1231 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1232 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1233 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1234 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1235 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1236 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1237 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1238 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1239 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1240 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1241 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1242 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1243 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1244 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1245 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1246 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001247 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001248
1249 return 0;
bellardb4091862003-05-16 15:39:34 +00001250}
1251
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001252static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001253{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001254 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001255 rlim_t result;
1256
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001257 target_rlim_swap = tswapal(target_rlim);
1258 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1259 return RLIM_INFINITY;
1260
1261 result = target_rlim_swap;
1262 if (target_rlim_swap != (rlim_t)result)
1263 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001264
1265 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001266}
1267
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001268static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001269{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001270 abi_ulong target_rlim_swap;
1271 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001272
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001273 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001274 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001275 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001276 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001277 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001278
1279 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001280}
1281
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001282static inline int target_to_host_resource(int code)
1283{
1284 switch (code) {
1285 case TARGET_RLIMIT_AS:
1286 return RLIMIT_AS;
1287 case TARGET_RLIMIT_CORE:
1288 return RLIMIT_CORE;
1289 case TARGET_RLIMIT_CPU:
1290 return RLIMIT_CPU;
1291 case TARGET_RLIMIT_DATA:
1292 return RLIMIT_DATA;
1293 case TARGET_RLIMIT_FSIZE:
1294 return RLIMIT_FSIZE;
1295 case TARGET_RLIMIT_LOCKS:
1296 return RLIMIT_LOCKS;
1297 case TARGET_RLIMIT_MEMLOCK:
1298 return RLIMIT_MEMLOCK;
1299 case TARGET_RLIMIT_MSGQUEUE:
1300 return RLIMIT_MSGQUEUE;
1301 case TARGET_RLIMIT_NICE:
1302 return RLIMIT_NICE;
1303 case TARGET_RLIMIT_NOFILE:
1304 return RLIMIT_NOFILE;
1305 case TARGET_RLIMIT_NPROC:
1306 return RLIMIT_NPROC;
1307 case TARGET_RLIMIT_RSS:
1308 return RLIMIT_RSS;
1309 case TARGET_RLIMIT_RTPRIO:
1310 return RLIMIT_RTPRIO;
1311 case TARGET_RLIMIT_SIGPENDING:
1312 return RLIMIT_SIGPENDING;
1313 case TARGET_RLIMIT_STACK:
1314 return RLIMIT_STACK;
1315 default:
1316 return code;
1317 }
1318}
1319
ths788f5ec2007-12-09 02:37:05 +00001320static inline abi_long copy_from_user_timeval(struct timeval *tv,
1321 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001322{
pbrook53a59602006-03-25 19:31:22 +00001323 struct target_timeval *target_tv;
1324
ths788f5ec2007-12-09 02:37:05 +00001325 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001326 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001327
1328 __get_user(tv->tv_sec, &target_tv->tv_sec);
1329 __get_user(tv->tv_usec, &target_tv->tv_usec);
1330
1331 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001332
1333 return 0;
bellard31e31b82003-02-18 22:55:36 +00001334}
1335
ths788f5ec2007-12-09 02:37:05 +00001336static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1337 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001338{
pbrook53a59602006-03-25 19:31:22 +00001339 struct target_timeval *target_tv;
1340
ths788f5ec2007-12-09 02:37:05 +00001341 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001342 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001343
1344 __put_user(tv->tv_sec, &target_tv->tv_sec);
1345 __put_user(tv->tv_usec, &target_tv->tv_usec);
1346
1347 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001348
1349 return 0;
bellard31e31b82003-02-18 22:55:36 +00001350}
1351
Paul Burtonef4467e2014-06-22 11:25:40 +01001352static inline abi_long copy_from_user_timezone(struct timezone *tz,
1353 abi_ulong target_tz_addr)
1354{
1355 struct target_timezone *target_tz;
1356
1357 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1358 return -TARGET_EFAULT;
1359 }
1360
1361 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1362 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1363
1364 unlock_user_struct(target_tz, target_tz_addr, 0);
1365
1366 return 0;
1367}
1368
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001369#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1370#include <mqueue.h>
1371
aurel3224e10032009-04-15 16:11:43 +00001372static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1373 abi_ulong target_mq_attr_addr)
1374{
1375 struct target_mq_attr *target_mq_attr;
1376
1377 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1378 target_mq_attr_addr, 1))
1379 return -TARGET_EFAULT;
1380
1381 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1382 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1383 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1384 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1385
1386 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1387
1388 return 0;
1389}
1390
1391static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1392 const struct mq_attr *attr)
1393{
1394 struct target_mq_attr *target_mq_attr;
1395
1396 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1397 target_mq_attr_addr, 0))
1398 return -TARGET_EFAULT;
1399
1400 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1401 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1402 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1403 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1404
1405 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1406
1407 return 0;
1408}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001409#endif
bellard31e31b82003-02-18 22:55:36 +00001410
Mike Frysinger055e0902011-06-03 17:01:49 -04001411#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001412/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001413static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001414 abi_ulong rfd_addr, abi_ulong wfd_addr,
1415 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001416{
1417 fd_set rfds, wfds, efds;
1418 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001419 struct timeval tv;
1420 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001421 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001422
Mike Frysinger055e0902011-06-03 17:01:49 -04001423 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1424 if (ret) {
1425 return ret;
pbrook53a59602006-03-25 19:31:22 +00001426 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001427 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1428 if (ret) {
1429 return ret;
pbrook53a59602006-03-25 19:31:22 +00001430 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001431 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1432 if (ret) {
1433 return ret;
pbrook53a59602006-03-25 19:31:22 +00001434 }
ths3b46e622007-09-17 08:09:54 +00001435
ths26edcf42007-12-09 02:25:24 +00001436 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001437 if (copy_from_user_timeval(&tv, target_tv_addr))
1438 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001439 ts.tv_sec = tv.tv_sec;
1440 ts.tv_nsec = tv.tv_usec * 1000;
1441 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001442 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001443 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001444 }
ths26edcf42007-12-09 02:25:24 +00001445
Peter Maydell6df9d382016-05-12 18:47:51 +01001446 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1447 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001448
ths26edcf42007-12-09 02:25:24 +00001449 if (!is_error(ret)) {
1450 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1451 return -TARGET_EFAULT;
1452 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1453 return -TARGET_EFAULT;
1454 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1455 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001456
Peter Maydell6df9d382016-05-12 18:47:51 +01001457 if (target_tv_addr) {
1458 tv.tv_sec = ts.tv_sec;
1459 tv.tv_usec = ts.tv_nsec / 1000;
1460 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1461 return -TARGET_EFAULT;
1462 }
1463 }
bellard31e31b82003-02-18 22:55:36 +00001464 }
bellard579a97f2007-11-11 14:26:47 +00001465
bellard31e31b82003-02-18 22:55:36 +00001466 return ret;
1467}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001468
1469#if defined(TARGET_WANT_OLD_SYS_SELECT)
1470static abi_long do_old_select(abi_ulong arg1)
1471{
1472 struct target_sel_arg_struct *sel;
1473 abi_ulong inp, outp, exp, tvp;
1474 long nsel;
1475
1476 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1477 return -TARGET_EFAULT;
1478 }
1479
1480 nsel = tswapal(sel->n);
1481 inp = tswapal(sel->inp);
1482 outp = tswapal(sel->outp);
1483 exp = tswapal(sel->exp);
1484 tvp = tswapal(sel->tvp);
1485
1486 unlock_user_struct(sel, arg1, 0);
1487
1488 return do_select(nsel, inp, outp, exp, tvp);
1489}
1490#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001491#endif
bellard31e31b82003-02-18 22:55:36 +00001492
Riku Voipio099d6b02009-05-05 12:10:04 +03001493static abi_long do_pipe2(int host_pipe[], int flags)
1494{
1495#ifdef CONFIG_PIPE2
1496 return pipe2(host_pipe, flags);
1497#else
1498 return -ENOSYS;
1499#endif
1500}
1501
Richard Hendersonfb41a662010-05-03 10:07:52 -07001502static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1503 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001504{
1505 int host_pipe[2];
1506 abi_long ret;
1507 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1508
1509 if (is_error(ret))
1510 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001511
1512 /* Several targets have special calling conventions for the original
1513 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1514 if (!is_pipe2) {
1515#if defined(TARGET_ALPHA)
1516 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1517 return host_pipe[0];
1518#elif defined(TARGET_MIPS)
1519 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1520 return host_pipe[0];
1521#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001522 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001523 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001524#elif defined(TARGET_SPARC)
1525 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1526 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001527#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001528 }
1529
Riku Voipio099d6b02009-05-05 12:10:04 +03001530 if (put_user_s32(host_pipe[0], pipedes)
1531 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1532 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001533 return get_errno(ret);
1534}
1535
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001536static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1537 abi_ulong target_addr,
1538 socklen_t len)
1539{
1540 struct target_ip_mreqn *target_smreqn;
1541
1542 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1543 if (!target_smreqn)
1544 return -TARGET_EFAULT;
1545 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1546 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1547 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001548 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001549 unlock_user(target_smreqn, target_addr, 0);
1550
1551 return 0;
1552}
1553
Laurent Vivier7b36f782015-10-28 21:40:44 +01001554static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001555 abi_ulong target_addr,
1556 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001557{
aurel32607175e2009-04-15 16:11:59 +00001558 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1559 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001560 struct target_sockaddr *target_saddr;
1561
Laurent Vivier7b36f782015-10-28 21:40:44 +01001562 if (fd_trans_target_to_host_addr(fd)) {
1563 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1564 }
1565
bellard579a97f2007-11-11 14:26:47 +00001566 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1567 if (!target_saddr)
1568 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001569
1570 sa_family = tswap16(target_saddr->sa_family);
1571
1572 /* Oops. The caller might send a incomplete sun_path; sun_path
1573 * must be terminated by \0 (see the manual page), but
1574 * unfortunately it is quite common to specify sockaddr_un
1575 * length as "strlen(x->sun_path)" while it should be
1576 * "strlen(...) + 1". We'll fix that here if needed.
1577 * Linux kernel has a similar feature.
1578 */
1579
1580 if (sa_family == AF_UNIX) {
1581 if (len < unix_maxlen && len > 0) {
1582 char *cp = (char*)target_saddr;
1583
1584 if ( cp[len-1] && !cp[len] )
1585 len++;
1586 }
1587 if (len > unix_maxlen)
1588 len = unix_maxlen;
1589 }
1590
pbrook53a59602006-03-25 19:31:22 +00001591 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001592 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001593 if (sa_family == AF_NETLINK) {
1594 struct sockaddr_nl *nladdr;
1595
1596 nladdr = (struct sockaddr_nl *)addr;
1597 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1598 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1599 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001600 struct target_sockaddr_ll *lladdr;
1601
1602 lladdr = (struct target_sockaddr_ll *)addr;
1603 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1604 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1605 }
pbrook53a59602006-03-25 19:31:22 +00001606 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001607
1608 return 0;
bellard7854b052003-03-29 17:22:23 +00001609}
1610
bellard579a97f2007-11-11 14:26:47 +00001611static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1612 struct sockaddr *addr,
1613 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001614{
pbrook53a59602006-03-25 19:31:22 +00001615 struct target_sockaddr *target_saddr;
1616
Peter Maydella1e22192016-07-07 15:44:43 +01001617 if (len == 0) {
1618 return 0;
1619 }
1620
bellard579a97f2007-11-11 14:26:47 +00001621 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1622 if (!target_saddr)
1623 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001624 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001625 if (len >= offsetof(struct target_sockaddr, sa_family) +
1626 sizeof(target_saddr->sa_family)) {
1627 target_saddr->sa_family = tswap16(addr->sa_family);
1628 }
1629 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001630 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1631 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1632 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001633 } else if (addr->sa_family == AF_PACKET) {
1634 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1635 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1636 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001637 }
pbrook53a59602006-03-25 19:31:22 +00001638 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001639
1640 return 0;
bellard7854b052003-03-29 17:22:23 +00001641}
1642
bellard5a4a8982007-11-11 17:39:18 +00001643static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1644 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001645{
1646 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001647 abi_long msg_controllen;
1648 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001649 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001650 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001651
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001652 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001653 if (msg_controllen < sizeof (struct target_cmsghdr))
1654 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001655 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001656 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001657 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001658 if (!target_cmsg)
1659 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001660
1661 while (cmsg && target_cmsg) {
1662 void *data = CMSG_DATA(cmsg);
1663 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1664
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001665 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001666 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1667
1668 space += CMSG_SPACE(len);
1669 if (space > msgh->msg_controllen) {
1670 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001671 /* This is a QEMU bug, since we allocated the payload
1672 * area ourselves (unlike overflow in host-to-target
1673 * conversion, which is just the guest giving us a buffer
1674 * that's too small). It can't happen for the payload types
1675 * we currently support; if it becomes an issue in future
1676 * we would need to improve our allocation strategy to
1677 * something more intelligent than "twice the size of the
1678 * target buffer we're reading from".
1679 */
bellard31febb72005-12-18 20:03:27 +00001680 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001681 break;
1682 }
1683
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001684 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1685 cmsg->cmsg_level = SOL_SOCKET;
1686 } else {
1687 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1688 }
bellard7854b052003-03-29 17:22:23 +00001689 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1690 cmsg->cmsg_len = CMSG_LEN(len);
1691
Alex Suykov30b8b682014-12-23 07:52:58 +02001692 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001693 int *fd = (int *)data;
1694 int *target_fd = (int *)target_data;
1695 int i, numfds = len / sizeof(int);
1696
Peter Maydell876e23c2015-05-26 19:46:32 +01001697 for (i = 0; i < numfds; i++) {
1698 __get_user(fd[i], target_fd + i);
1699 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001700 } else if (cmsg->cmsg_level == SOL_SOCKET
1701 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1702 struct ucred *cred = (struct ucred *)data;
1703 struct target_ucred *target_cred =
1704 (struct target_ucred *)target_data;
1705
Peter Maydell876e23c2015-05-26 19:46:32 +01001706 __get_user(cred->pid, &target_cred->pid);
1707 __get_user(cred->uid, &target_cred->uid);
1708 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001709 } else {
1710 gemu_log("Unsupported ancillary data: %d/%d\n",
1711 cmsg->cmsg_level, cmsg->cmsg_type);
1712 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001713 }
1714
1715 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001716 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1717 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001718 }
bellard5a4a8982007-11-11 17:39:18 +00001719 unlock_user(target_cmsg, target_cmsg_addr, 0);
1720 the_end:
bellard7854b052003-03-29 17:22:23 +00001721 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001722 return 0;
bellard7854b052003-03-29 17:22:23 +00001723}
1724
bellard5a4a8982007-11-11 17:39:18 +00001725static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1726 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001727{
1728 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001729 abi_long msg_controllen;
1730 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001731 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001732 socklen_t space = 0;
1733
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001734 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001735 if (msg_controllen < sizeof (struct target_cmsghdr))
1736 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001737 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001738 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001739 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001740 if (!target_cmsg)
1741 return -TARGET_EFAULT;
1742
bellard7854b052003-03-29 17:22:23 +00001743 while (cmsg && target_cmsg) {
1744 void *data = CMSG_DATA(cmsg);
1745 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1746
1747 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001748 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001749
Peter Maydellc2aeb252015-05-26 19:46:31 +01001750 /* We never copy a half-header but may copy half-data;
1751 * this is Linux's behaviour in put_cmsg(). Note that
1752 * truncation here is a guest problem (which we report
1753 * to the guest via the CTRUNC bit), unlike truncation
1754 * in target_to_host_cmsg, which is a QEMU bug.
1755 */
1756 if (msg_controllen < sizeof(struct cmsghdr)) {
1757 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001758 break;
1759 }
1760
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001761 if (cmsg->cmsg_level == SOL_SOCKET) {
1762 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1763 } else {
1764 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1765 }
bellard7854b052003-03-29 17:22:23 +00001766 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001767
Peter Maydellc2aeb252015-05-26 19:46:31 +01001768 tgt_len = TARGET_CMSG_LEN(len);
1769
1770 /* Payload types which need a different size of payload on
1771 * the target must adjust tgt_len here.
1772 */
1773 switch (cmsg->cmsg_level) {
1774 case SOL_SOCKET:
1775 switch (cmsg->cmsg_type) {
1776 case SO_TIMESTAMP:
1777 tgt_len = sizeof(struct target_timeval);
1778 break;
1779 default:
1780 break;
1781 }
1782 default:
1783 break;
1784 }
1785
1786 if (msg_controllen < tgt_len) {
1787 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1788 tgt_len = msg_controllen;
1789 }
1790
1791 /* We must now copy-and-convert len bytes of payload
1792 * into tgt_len bytes of destination space. Bear in mind
1793 * that in both source and destination we may be dealing
1794 * with a truncated value!
1795 */
Huw Davies52b65492014-04-17 14:02:47 +01001796 switch (cmsg->cmsg_level) {
1797 case SOL_SOCKET:
1798 switch (cmsg->cmsg_type) {
1799 case SCM_RIGHTS:
1800 {
1801 int *fd = (int *)data;
1802 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001803 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001804
Peter Maydell876e23c2015-05-26 19:46:32 +01001805 for (i = 0; i < numfds; i++) {
1806 __put_user(fd[i], target_fd + i);
1807 }
Huw Davies52b65492014-04-17 14:02:47 +01001808 break;
1809 }
1810 case SO_TIMESTAMP:
1811 {
1812 struct timeval *tv = (struct timeval *)data;
1813 struct target_timeval *target_tv =
1814 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001815
Peter Maydellc2aeb252015-05-26 19:46:31 +01001816 if (len != sizeof(struct timeval) ||
1817 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001818 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001819 }
Huw Davies52b65492014-04-17 14:02:47 +01001820
1821 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001822 __put_user(tv->tv_sec, &target_tv->tv_sec);
1823 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001824 break;
1825 }
Huw Davies4bc29752014-04-17 14:02:48 +01001826 case SCM_CREDENTIALS:
1827 {
1828 struct ucred *cred = (struct ucred *)data;
1829 struct target_ucred *target_cred =
1830 (struct target_ucred *)target_data;
1831
1832 __put_user(cred->pid, &target_cred->pid);
1833 __put_user(cred->uid, &target_cred->uid);
1834 __put_user(cred->gid, &target_cred->gid);
1835 break;
1836 }
Huw Davies52b65492014-04-17 14:02:47 +01001837 default:
1838 goto unimplemented;
1839 }
1840 break;
1841
1842 default:
1843 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001844 gemu_log("Unsupported ancillary data: %d/%d\n",
1845 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001846 memcpy(target_data, data, MIN(len, tgt_len));
1847 if (tgt_len > len) {
1848 memset(target_data + len, 0, tgt_len - len);
1849 }
bellard7854b052003-03-29 17:22:23 +00001850 }
1851
Peter Maydellc2aeb252015-05-26 19:46:31 +01001852 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001853 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001854 if (msg_controllen < tgt_space) {
1855 tgt_space = msg_controllen;
1856 }
1857 msg_controllen -= tgt_space;
1858 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001859 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001860 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1861 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001862 }
bellard5a4a8982007-11-11 17:39:18 +00001863 unlock_user(target_cmsg, target_cmsg_addr, space);
1864 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001865 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001866 return 0;
bellard7854b052003-03-29 17:22:23 +00001867}
1868
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001869static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1870{
1871 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1872 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1873 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1874 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1875 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1876}
1877
1878static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1879 size_t len,
1880 abi_long (*host_to_target_nlmsg)
1881 (struct nlmsghdr *))
1882{
1883 uint32_t nlmsg_len;
1884 abi_long ret;
1885
1886 while (len > sizeof(struct nlmsghdr)) {
1887
1888 nlmsg_len = nlh->nlmsg_len;
1889 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1890 nlmsg_len > len) {
1891 break;
1892 }
1893
1894 switch (nlh->nlmsg_type) {
1895 case NLMSG_DONE:
1896 tswap_nlmsghdr(nlh);
1897 return 0;
1898 case NLMSG_NOOP:
1899 break;
1900 case NLMSG_ERROR:
1901 {
1902 struct nlmsgerr *e = NLMSG_DATA(nlh);
1903 e->error = tswap32(e->error);
1904 tswap_nlmsghdr(&e->msg);
1905 tswap_nlmsghdr(nlh);
1906 return 0;
1907 }
1908 default:
1909 ret = host_to_target_nlmsg(nlh);
1910 if (ret < 0) {
1911 tswap_nlmsghdr(nlh);
1912 return ret;
1913 }
1914 break;
1915 }
1916 tswap_nlmsghdr(nlh);
1917 len -= NLMSG_ALIGN(nlmsg_len);
1918 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1919 }
1920 return 0;
1921}
1922
1923static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1924 size_t len,
1925 abi_long (*target_to_host_nlmsg)
1926 (struct nlmsghdr *))
1927{
1928 int ret;
1929
1930 while (len > sizeof(struct nlmsghdr)) {
1931 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1932 tswap32(nlh->nlmsg_len) > len) {
1933 break;
1934 }
1935 tswap_nlmsghdr(nlh);
1936 switch (nlh->nlmsg_type) {
1937 case NLMSG_DONE:
1938 return 0;
1939 case NLMSG_NOOP:
1940 break;
1941 case NLMSG_ERROR:
1942 {
1943 struct nlmsgerr *e = NLMSG_DATA(nlh);
1944 e->error = tswap32(e->error);
1945 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02001946 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001947 }
1948 default:
1949 ret = target_to_host_nlmsg(nlh);
1950 if (ret < 0) {
1951 return ret;
1952 }
1953 }
1954 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1955 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1956 }
1957 return 0;
1958}
1959
Laurent Vivier575b22b2016-06-02 22:14:15 +02001960#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02001961static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
1962 size_t len, void *context,
1963 abi_long (*host_to_target_nlattr)
1964 (struct nlattr *,
1965 void *context))
1966{
1967 unsigned short nla_len;
1968 abi_long ret;
1969
1970 while (len > sizeof(struct nlattr)) {
1971 nla_len = nlattr->nla_len;
1972 if (nla_len < sizeof(struct nlattr) ||
1973 nla_len > len) {
1974 break;
1975 }
1976 ret = host_to_target_nlattr(nlattr, context);
1977 nlattr->nla_len = tswap16(nlattr->nla_len);
1978 nlattr->nla_type = tswap16(nlattr->nla_type);
1979 if (ret < 0) {
1980 return ret;
1981 }
1982 len -= NLA_ALIGN(nla_len);
1983 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
1984 }
1985 return 0;
1986}
1987
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001988static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1989 size_t len,
1990 abi_long (*host_to_target_rtattr)
1991 (struct rtattr *))
1992{
1993 unsigned short rta_len;
1994 abi_long ret;
1995
1996 while (len > sizeof(struct rtattr)) {
1997 rta_len = rtattr->rta_len;
1998 if (rta_len < sizeof(struct rtattr) ||
1999 rta_len > len) {
2000 break;
2001 }
2002 ret = host_to_target_rtattr(rtattr);
2003 rtattr->rta_len = tswap16(rtattr->rta_len);
2004 rtattr->rta_type = tswap16(rtattr->rta_type);
2005 if (ret < 0) {
2006 return ret;
2007 }
2008 len -= RTA_ALIGN(rta_len);
2009 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2010 }
2011 return 0;
2012}
2013
Laurent Vivierc5dff282016-06-27 18:54:30 +02002014#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2015
2016static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2017 void *context)
2018{
2019 uint16_t *u16;
2020 uint32_t *u32;
2021 uint64_t *u64;
2022
2023 switch (nlattr->nla_type) {
2024 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002025 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002026 break;
2027 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002028 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002029 break;
2030 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002031 case QEMU_IFLA_BR_VLAN_FILTERING:
2032 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2033 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2034 case QEMU_IFLA_BR_MCAST_ROUTER:
2035 case QEMU_IFLA_BR_MCAST_SNOOPING:
2036 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2037 case QEMU_IFLA_BR_MCAST_QUERIER:
2038 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2039 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2040 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002041 break;
2042 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002043 case QEMU_IFLA_BR_PRIORITY:
2044 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2045 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2046 case QEMU_IFLA_BR_ROOT_PORT:
2047 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002048 u16 = NLA_DATA(nlattr);
2049 *u16 = tswap16(*u16);
2050 break;
2051 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002052 case QEMU_IFLA_BR_FORWARD_DELAY:
2053 case QEMU_IFLA_BR_HELLO_TIME:
2054 case QEMU_IFLA_BR_MAX_AGE:
2055 case QEMU_IFLA_BR_AGEING_TIME:
2056 case QEMU_IFLA_BR_STP_STATE:
2057 case QEMU_IFLA_BR_ROOT_PATH_COST:
2058 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2059 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2060 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2061 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002062 u32 = NLA_DATA(nlattr);
2063 *u32 = tswap32(*u32);
2064 break;
2065 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002066 case QEMU_IFLA_BR_HELLO_TIMER:
2067 case QEMU_IFLA_BR_TCN_TIMER:
2068 case QEMU_IFLA_BR_GC_TIMER:
2069 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2070 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2071 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2072 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2073 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2074 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2075 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002076 u64 = NLA_DATA(nlattr);
2077 *u64 = tswap64(*u64);
2078 break;
2079 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002080 case QEMU_IFLA_BR_ROOT_ID:
2081 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002082 break;
2083 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002084 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002085 break;
2086 }
2087 return 0;
2088}
2089
2090static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2091 void *context)
2092{
2093 uint16_t *u16;
2094 uint32_t *u32;
2095 uint64_t *u64;
2096
2097 switch (nlattr->nla_type) {
2098 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002099 case QEMU_IFLA_BRPORT_STATE:
2100 case QEMU_IFLA_BRPORT_MODE:
2101 case QEMU_IFLA_BRPORT_GUARD:
2102 case QEMU_IFLA_BRPORT_PROTECT:
2103 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2104 case QEMU_IFLA_BRPORT_LEARNING:
2105 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2106 case QEMU_IFLA_BRPORT_PROXYARP:
2107 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2108 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2109 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2110 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2111 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002112 break;
2113 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002114 case QEMU_IFLA_BRPORT_PRIORITY:
2115 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2116 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2117 case QEMU_IFLA_BRPORT_ID:
2118 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002119 u16 = NLA_DATA(nlattr);
2120 *u16 = tswap16(*u16);
2121 break;
2122 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002123 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002124 u32 = NLA_DATA(nlattr);
2125 *u32 = tswap32(*u32);
2126 break;
2127 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002128 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2129 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2130 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002131 u64 = NLA_DATA(nlattr);
2132 *u64 = tswap64(*u64);
2133 break;
2134 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002135 case QEMU_IFLA_BRPORT_ROOT_ID:
2136 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002137 break;
2138 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002139 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002140 break;
2141 }
2142 return 0;
2143}
2144
2145struct linkinfo_context {
2146 int len;
2147 char *name;
2148 int slave_len;
2149 char *slave_name;
2150};
2151
2152static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2153 void *context)
2154{
2155 struct linkinfo_context *li_context = context;
2156
2157 switch (nlattr->nla_type) {
2158 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002159 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002160 li_context->name = NLA_DATA(nlattr);
2161 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2162 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002163 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002164 li_context->slave_name = NLA_DATA(nlattr);
2165 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2166 break;
2167 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002168 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002169 /* FIXME: only used by CAN */
2170 break;
2171 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002172 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002173 if (strncmp(li_context->name, "bridge",
2174 li_context->len) == 0) {
2175 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2176 nlattr->nla_len,
2177 NULL,
2178 host_to_target_data_bridge_nlattr);
2179 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002180 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002181 }
2182 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002183 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002184 if (strncmp(li_context->slave_name, "bridge",
2185 li_context->slave_len) == 0) {
2186 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2187 nlattr->nla_len,
2188 NULL,
2189 host_to_target_slave_data_bridge_nlattr);
2190 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002191 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002192 li_context->slave_name);
2193 }
2194 break;
2195 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002196 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002197 break;
2198 }
2199
2200 return 0;
2201}
2202
2203static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2204 void *context)
2205{
2206 uint32_t *u32;
2207 int i;
2208
2209 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002210 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002211 u32 = NLA_DATA(nlattr);
2212 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2213 i++) {
2214 u32[i] = tswap32(u32[i]);
2215 }
2216 break;
2217 default:
2218 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2219 }
2220 return 0;
2221}
2222
2223static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2224 void *context)
2225{
2226 uint32_t *u32;
2227 uint64_t *u64;
2228 struct ifla_cacheinfo *ci;
2229 int i;
2230
2231 switch (nlattr->nla_type) {
2232 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002233 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002234 break;
2235 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002236 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002237 break;
2238 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002239 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002240 u32 = NLA_DATA(nlattr);
2241 *u32 = tswap32(*u32);
2242 break;
2243 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002244 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002245 u32 = NLA_DATA(nlattr);
2246 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2247 i++) {
2248 u32[i] = tswap32(u32[i]);
2249 }
2250 break;
2251 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002252 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002253 ci = NLA_DATA(nlattr);
2254 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2255 ci->tstamp = tswap32(ci->tstamp);
2256 ci->reachable_time = tswap32(ci->reachable_time);
2257 ci->retrans_time = tswap32(ci->retrans_time);
2258 break;
2259 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002260 case QEMU_IFLA_INET6_STATS:
2261 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002262 u64 = NLA_DATA(nlattr);
2263 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2264 i++) {
2265 u64[i] = tswap64(u64[i]);
2266 }
2267 break;
2268 default:
2269 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2270 }
2271 return 0;
2272}
2273
2274static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2275 void *context)
2276{
2277 switch (nlattr->nla_type) {
2278 case AF_INET:
2279 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2280 NULL,
2281 host_to_target_data_inet_nlattr);
2282 case AF_INET6:
2283 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2284 NULL,
2285 host_to_target_data_inet6_nlattr);
2286 default:
2287 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2288 break;
2289 }
2290 return 0;
2291}
2292
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002293static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2294{
2295 uint32_t *u32;
2296 struct rtnl_link_stats *st;
2297 struct rtnl_link_stats64 *st64;
2298 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002299 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002300
2301 switch (rtattr->rta_type) {
2302 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002303 case QEMU_IFLA_ADDRESS:
2304 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002305 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002306 case QEMU_IFLA_IFNAME:
2307 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002308 break;
2309 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002310 case QEMU_IFLA_OPERSTATE:
2311 case QEMU_IFLA_LINKMODE:
2312 case QEMU_IFLA_CARRIER:
2313 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002314 break;
2315 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002316 case QEMU_IFLA_MTU:
2317 case QEMU_IFLA_LINK:
2318 case QEMU_IFLA_WEIGHT:
2319 case QEMU_IFLA_TXQLEN:
2320 case QEMU_IFLA_CARRIER_CHANGES:
2321 case QEMU_IFLA_NUM_RX_QUEUES:
2322 case QEMU_IFLA_NUM_TX_QUEUES:
2323 case QEMU_IFLA_PROMISCUITY:
2324 case QEMU_IFLA_EXT_MASK:
2325 case QEMU_IFLA_LINK_NETNSID:
2326 case QEMU_IFLA_GROUP:
2327 case QEMU_IFLA_MASTER:
2328 case QEMU_IFLA_NUM_VF:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002329 u32 = RTA_DATA(rtattr);
2330 *u32 = tswap32(*u32);
2331 break;
2332 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002333 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002334 st = RTA_DATA(rtattr);
2335 st->rx_packets = tswap32(st->rx_packets);
2336 st->tx_packets = tswap32(st->tx_packets);
2337 st->rx_bytes = tswap32(st->rx_bytes);
2338 st->tx_bytes = tswap32(st->tx_bytes);
2339 st->rx_errors = tswap32(st->rx_errors);
2340 st->tx_errors = tswap32(st->tx_errors);
2341 st->rx_dropped = tswap32(st->rx_dropped);
2342 st->tx_dropped = tswap32(st->tx_dropped);
2343 st->multicast = tswap32(st->multicast);
2344 st->collisions = tswap32(st->collisions);
2345
2346 /* detailed rx_errors: */
2347 st->rx_length_errors = tswap32(st->rx_length_errors);
2348 st->rx_over_errors = tswap32(st->rx_over_errors);
2349 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2350 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2351 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2352 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2353
2354 /* detailed tx_errors */
2355 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2356 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2357 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2358 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2359 st->tx_window_errors = tswap32(st->tx_window_errors);
2360
2361 /* for cslip etc */
2362 st->rx_compressed = tswap32(st->rx_compressed);
2363 st->tx_compressed = tswap32(st->tx_compressed);
2364 break;
2365 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002366 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002367 st64 = RTA_DATA(rtattr);
2368 st64->rx_packets = tswap64(st64->rx_packets);
2369 st64->tx_packets = tswap64(st64->tx_packets);
2370 st64->rx_bytes = tswap64(st64->rx_bytes);
2371 st64->tx_bytes = tswap64(st64->tx_bytes);
2372 st64->rx_errors = tswap64(st64->rx_errors);
2373 st64->tx_errors = tswap64(st64->tx_errors);
2374 st64->rx_dropped = tswap64(st64->rx_dropped);
2375 st64->tx_dropped = tswap64(st64->tx_dropped);
2376 st64->multicast = tswap64(st64->multicast);
2377 st64->collisions = tswap64(st64->collisions);
2378
2379 /* detailed rx_errors: */
2380 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2381 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2382 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2383 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2384 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2385 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2386
2387 /* detailed tx_errors */
2388 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2389 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2390 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2391 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2392 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2393
2394 /* for cslip etc */
2395 st64->rx_compressed = tswap64(st64->rx_compressed);
2396 st64->tx_compressed = tswap64(st64->tx_compressed);
2397 break;
2398 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002399 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002400 map = RTA_DATA(rtattr);
2401 map->mem_start = tswap64(map->mem_start);
2402 map->mem_end = tswap64(map->mem_end);
2403 map->base_addr = tswap64(map->base_addr);
2404 map->irq = tswap16(map->irq);
2405 break;
2406 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002407 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002408 memset(&li_context, 0, sizeof(li_context));
2409 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2410 &li_context,
2411 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002412 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002413 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2414 NULL,
2415 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002416 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002417 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002418 break;
2419 }
2420 return 0;
2421}
2422
2423static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2424{
2425 uint32_t *u32;
2426 struct ifa_cacheinfo *ci;
2427
2428 switch (rtattr->rta_type) {
2429 /* binary: depends on family type */
2430 case IFA_ADDRESS:
2431 case IFA_LOCAL:
2432 break;
2433 /* string */
2434 case IFA_LABEL:
2435 break;
2436 /* u32 */
2437 case IFA_FLAGS:
2438 case IFA_BROADCAST:
2439 u32 = RTA_DATA(rtattr);
2440 *u32 = tswap32(*u32);
2441 break;
2442 /* struct ifa_cacheinfo */
2443 case IFA_CACHEINFO:
2444 ci = RTA_DATA(rtattr);
2445 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2446 ci->ifa_valid = tswap32(ci->ifa_valid);
2447 ci->cstamp = tswap32(ci->cstamp);
2448 ci->tstamp = tswap32(ci->tstamp);
2449 break;
2450 default:
2451 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2452 break;
2453 }
2454 return 0;
2455}
2456
2457static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2458{
2459 uint32_t *u32;
2460 switch (rtattr->rta_type) {
2461 /* binary: depends on family type */
2462 case RTA_GATEWAY:
2463 case RTA_DST:
2464 case RTA_PREFSRC:
2465 break;
2466 /* u32 */
2467 case RTA_PRIORITY:
2468 case RTA_TABLE:
2469 case RTA_OIF:
2470 u32 = RTA_DATA(rtattr);
2471 *u32 = tswap32(*u32);
2472 break;
2473 default:
2474 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2475 break;
2476 }
2477 return 0;
2478}
2479
2480static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2481 uint32_t rtattr_len)
2482{
2483 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2484 host_to_target_data_link_rtattr);
2485}
2486
2487static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2488 uint32_t rtattr_len)
2489{
2490 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2491 host_to_target_data_addr_rtattr);
2492}
2493
2494static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2495 uint32_t rtattr_len)
2496{
2497 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2498 host_to_target_data_route_rtattr);
2499}
2500
2501static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2502{
2503 uint32_t nlmsg_len;
2504 struct ifinfomsg *ifi;
2505 struct ifaddrmsg *ifa;
2506 struct rtmsg *rtm;
2507
2508 nlmsg_len = nlh->nlmsg_len;
2509 switch (nlh->nlmsg_type) {
2510 case RTM_NEWLINK:
2511 case RTM_DELLINK:
2512 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002513 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2514 ifi = NLMSG_DATA(nlh);
2515 ifi->ifi_type = tswap16(ifi->ifi_type);
2516 ifi->ifi_index = tswap32(ifi->ifi_index);
2517 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2518 ifi->ifi_change = tswap32(ifi->ifi_change);
2519 host_to_target_link_rtattr(IFLA_RTA(ifi),
2520 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2521 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002522 break;
2523 case RTM_NEWADDR:
2524 case RTM_DELADDR:
2525 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002526 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2527 ifa = NLMSG_DATA(nlh);
2528 ifa->ifa_index = tswap32(ifa->ifa_index);
2529 host_to_target_addr_rtattr(IFA_RTA(ifa),
2530 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2531 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002532 break;
2533 case RTM_NEWROUTE:
2534 case RTM_DELROUTE:
2535 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002536 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2537 rtm = NLMSG_DATA(nlh);
2538 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2539 host_to_target_route_rtattr(RTM_RTA(rtm),
2540 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2541 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002542 break;
2543 default:
2544 return -TARGET_EINVAL;
2545 }
2546 return 0;
2547}
2548
2549static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2550 size_t len)
2551{
2552 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2553}
2554
2555static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2556 size_t len,
2557 abi_long (*target_to_host_rtattr)
2558 (struct rtattr *))
2559{
2560 abi_long ret;
2561
2562 while (len >= sizeof(struct rtattr)) {
2563 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2564 tswap16(rtattr->rta_len) > len) {
2565 break;
2566 }
2567 rtattr->rta_len = tswap16(rtattr->rta_len);
2568 rtattr->rta_type = tswap16(rtattr->rta_type);
2569 ret = target_to_host_rtattr(rtattr);
2570 if (ret < 0) {
2571 return ret;
2572 }
2573 len -= RTA_ALIGN(rtattr->rta_len);
2574 rtattr = (struct rtattr *)(((char *)rtattr) +
2575 RTA_ALIGN(rtattr->rta_len));
2576 }
2577 return 0;
2578}
2579
2580static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2581{
2582 switch (rtattr->rta_type) {
2583 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002584 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002585 break;
2586 }
2587 return 0;
2588}
2589
2590static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2591{
2592 switch (rtattr->rta_type) {
2593 /* binary: depends on family type */
2594 case IFA_LOCAL:
2595 case IFA_ADDRESS:
2596 break;
2597 default:
2598 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2599 break;
2600 }
2601 return 0;
2602}
2603
2604static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2605{
2606 uint32_t *u32;
2607 switch (rtattr->rta_type) {
2608 /* binary: depends on family type */
2609 case RTA_DST:
2610 case RTA_SRC:
2611 case RTA_GATEWAY:
2612 break;
2613 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002614 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002615 case RTA_OIF:
2616 u32 = RTA_DATA(rtattr);
2617 *u32 = tswap32(*u32);
2618 break;
2619 default:
2620 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2621 break;
2622 }
2623 return 0;
2624}
2625
2626static void target_to_host_link_rtattr(struct rtattr *rtattr,
2627 uint32_t rtattr_len)
2628{
2629 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2630 target_to_host_data_link_rtattr);
2631}
2632
2633static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2634 uint32_t rtattr_len)
2635{
2636 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2637 target_to_host_data_addr_rtattr);
2638}
2639
2640static void target_to_host_route_rtattr(struct rtattr *rtattr,
2641 uint32_t rtattr_len)
2642{
2643 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2644 target_to_host_data_route_rtattr);
2645}
2646
2647static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2648{
2649 struct ifinfomsg *ifi;
2650 struct ifaddrmsg *ifa;
2651 struct rtmsg *rtm;
2652
2653 switch (nlh->nlmsg_type) {
2654 case RTM_GETLINK:
2655 break;
2656 case RTM_NEWLINK:
2657 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002658 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2659 ifi = NLMSG_DATA(nlh);
2660 ifi->ifi_type = tswap16(ifi->ifi_type);
2661 ifi->ifi_index = tswap32(ifi->ifi_index);
2662 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2663 ifi->ifi_change = tswap32(ifi->ifi_change);
2664 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2665 NLMSG_LENGTH(sizeof(*ifi)));
2666 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002667 break;
2668 case RTM_GETADDR:
2669 case RTM_NEWADDR:
2670 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002671 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2672 ifa = NLMSG_DATA(nlh);
2673 ifa->ifa_index = tswap32(ifa->ifa_index);
2674 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2675 NLMSG_LENGTH(sizeof(*ifa)));
2676 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002677 break;
2678 case RTM_GETROUTE:
2679 break;
2680 case RTM_NEWROUTE:
2681 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002682 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2683 rtm = NLMSG_DATA(nlh);
2684 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2685 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2686 NLMSG_LENGTH(sizeof(*rtm)));
2687 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002688 break;
2689 default:
2690 return -TARGET_EOPNOTSUPP;
2691 }
2692 return 0;
2693}
2694
2695static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2696{
2697 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2698}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002699#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002700
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002701static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2702{
2703 switch (nlh->nlmsg_type) {
2704 default:
2705 gemu_log("Unknown host audit message type %d\n",
2706 nlh->nlmsg_type);
2707 return -TARGET_EINVAL;
2708 }
2709 return 0;
2710}
2711
2712static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2713 size_t len)
2714{
2715 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2716}
2717
2718static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2719{
2720 switch (nlh->nlmsg_type) {
2721 case AUDIT_USER:
2722 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2723 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2724 break;
2725 default:
2726 gemu_log("Unknown target audit message type %d\n",
2727 nlh->nlmsg_type);
2728 return -TARGET_EINVAL;
2729 }
2730
2731 return 0;
2732}
2733
2734static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2735{
2736 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2737}
2738
ths0da46a62007-10-20 20:23:07 +00002739/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002740static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002741 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002742{
blueswir1992f48a2007-10-14 16:27:31 +00002743 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002744 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002745 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002746 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002747
bellard8853f862004-02-22 14:57:26 +00002748 switch(level) {
2749 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002750 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002751 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002752 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002753
bellard2f619692007-11-16 10:46:05 +00002754 if (get_user_u32(val, optval_addr))
2755 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002756 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2757 break;
2758 case SOL_IP:
2759 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002760 case IP_TOS:
2761 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002762 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002763 case IP_ROUTER_ALERT:
2764 case IP_RECVOPTS:
2765 case IP_RETOPTS:
2766 case IP_PKTINFO:
2767 case IP_MTU_DISCOVER:
2768 case IP_RECVERR:
2769 case IP_RECVTOS:
2770#ifdef IP_FREEBIND
2771 case IP_FREEBIND:
2772#endif
2773 case IP_MULTICAST_TTL:
2774 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002775 val = 0;
2776 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002777 if (get_user_u32(val, optval_addr))
2778 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002779 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002780 if (get_user_u8(val, optval_addr))
2781 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002782 }
2783 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2784 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002785 case IP_ADD_MEMBERSHIP:
2786 case IP_DROP_MEMBERSHIP:
2787 if (optlen < sizeof (struct target_ip_mreq) ||
2788 optlen > sizeof (struct target_ip_mreqn))
2789 return -TARGET_EINVAL;
2790
2791 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2792 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2793 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2794 break;
2795
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002796 case IP_BLOCK_SOURCE:
2797 case IP_UNBLOCK_SOURCE:
2798 case IP_ADD_SOURCE_MEMBERSHIP:
2799 case IP_DROP_SOURCE_MEMBERSHIP:
2800 if (optlen != sizeof (struct target_ip_mreq_source))
2801 return -TARGET_EINVAL;
2802
2803 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2804 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2805 unlock_user (ip_mreq_source, optval_addr, 0);
2806 break;
2807
bellard8853f862004-02-22 14:57:26 +00002808 default:
2809 goto unimplemented;
2810 }
2811 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002812 case SOL_IPV6:
2813 switch (optname) {
2814 case IPV6_MTU_DISCOVER:
2815 case IPV6_MTU:
2816 case IPV6_V6ONLY:
2817 case IPV6_RECVPKTINFO:
2818 val = 0;
2819 if (optlen < sizeof(uint32_t)) {
2820 return -TARGET_EINVAL;
2821 }
2822 if (get_user_u32(val, optval_addr)) {
2823 return -TARGET_EFAULT;
2824 }
2825 ret = get_errno(setsockopt(sockfd, level, optname,
2826 &val, sizeof(val)));
2827 break;
2828 default:
2829 goto unimplemented;
2830 }
2831 break;
Jing Huang920394d2012-07-24 13:59:23 +00002832 case SOL_RAW:
2833 switch (optname) {
2834 case ICMP_FILTER:
2835 /* struct icmp_filter takes an u32 value */
2836 if (optlen < sizeof(uint32_t)) {
2837 return -TARGET_EINVAL;
2838 }
2839
2840 if (get_user_u32(val, optval_addr)) {
2841 return -TARGET_EFAULT;
2842 }
2843 ret = get_errno(setsockopt(sockfd, level, optname,
2844 &val, sizeof(val)));
2845 break;
2846
2847 default:
2848 goto unimplemented;
2849 }
2850 break;
bellard3532fa72006-06-24 15:06:03 +00002851 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002852 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002853 case TARGET_SO_RCVTIMEO:
2854 {
2855 struct timeval tv;
2856
2857 optname = SO_RCVTIMEO;
2858
2859set_timeout:
2860 if (optlen != sizeof(struct target_timeval)) {
2861 return -TARGET_EINVAL;
2862 }
2863
2864 if (copy_from_user_timeval(&tv, optval_addr)) {
2865 return -TARGET_EFAULT;
2866 }
2867
2868 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2869 &tv, sizeof(tv)));
2870 return ret;
2871 }
2872 case TARGET_SO_SNDTIMEO:
2873 optname = SO_SNDTIMEO;
2874 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002875 case TARGET_SO_ATTACH_FILTER:
2876 {
2877 struct target_sock_fprog *tfprog;
2878 struct target_sock_filter *tfilter;
2879 struct sock_fprog fprog;
2880 struct sock_filter *filter;
2881 int i;
2882
2883 if (optlen != sizeof(*tfprog)) {
2884 return -TARGET_EINVAL;
2885 }
2886 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2887 return -TARGET_EFAULT;
2888 }
2889 if (!lock_user_struct(VERIFY_READ, tfilter,
2890 tswapal(tfprog->filter), 0)) {
2891 unlock_user_struct(tfprog, optval_addr, 1);
2892 return -TARGET_EFAULT;
2893 }
2894
2895 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302896 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002897 if (filter == NULL) {
2898 unlock_user_struct(tfilter, tfprog->filter, 1);
2899 unlock_user_struct(tfprog, optval_addr, 1);
2900 return -TARGET_ENOMEM;
2901 }
2902 for (i = 0; i < fprog.len; i++) {
2903 filter[i].code = tswap16(tfilter[i].code);
2904 filter[i].jt = tfilter[i].jt;
2905 filter[i].jf = tfilter[i].jf;
2906 filter[i].k = tswap32(tfilter[i].k);
2907 }
2908 fprog.filter = filter;
2909
2910 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2911 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302912 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002913
2914 unlock_user_struct(tfilter, tfprog->filter, 1);
2915 unlock_user_struct(tfprog, optval_addr, 1);
2916 return ret;
2917 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002918 case TARGET_SO_BINDTODEVICE:
2919 {
2920 char *dev_ifname, *addr_ifname;
2921
2922 if (optlen > IFNAMSIZ - 1) {
2923 optlen = IFNAMSIZ - 1;
2924 }
2925 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2926 if (!dev_ifname) {
2927 return -TARGET_EFAULT;
2928 }
2929 optname = SO_BINDTODEVICE;
2930 addr_ifname = alloca(IFNAMSIZ);
2931 memcpy(addr_ifname, dev_ifname, optlen);
2932 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002933 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2934 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002935 unlock_user (dev_ifname, optval_addr, 0);
2936 return ret;
2937 }
bellard8853f862004-02-22 14:57:26 +00002938 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002939 case TARGET_SO_DEBUG:
2940 optname = SO_DEBUG;
2941 break;
2942 case TARGET_SO_REUSEADDR:
2943 optname = SO_REUSEADDR;
2944 break;
2945 case TARGET_SO_TYPE:
2946 optname = SO_TYPE;
2947 break;
2948 case TARGET_SO_ERROR:
2949 optname = SO_ERROR;
2950 break;
2951 case TARGET_SO_DONTROUTE:
2952 optname = SO_DONTROUTE;
2953 break;
2954 case TARGET_SO_BROADCAST:
2955 optname = SO_BROADCAST;
2956 break;
2957 case TARGET_SO_SNDBUF:
2958 optname = SO_SNDBUF;
2959 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002960 case TARGET_SO_SNDBUFFORCE:
2961 optname = SO_SNDBUFFORCE;
2962 break;
bellard3532fa72006-06-24 15:06:03 +00002963 case TARGET_SO_RCVBUF:
2964 optname = SO_RCVBUF;
2965 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002966 case TARGET_SO_RCVBUFFORCE:
2967 optname = SO_RCVBUFFORCE;
2968 break;
bellard3532fa72006-06-24 15:06:03 +00002969 case TARGET_SO_KEEPALIVE:
2970 optname = SO_KEEPALIVE;
2971 break;
2972 case TARGET_SO_OOBINLINE:
2973 optname = SO_OOBINLINE;
2974 break;
2975 case TARGET_SO_NO_CHECK:
2976 optname = SO_NO_CHECK;
2977 break;
2978 case TARGET_SO_PRIORITY:
2979 optname = SO_PRIORITY;
2980 break;
bellard5e83e8e2005-03-01 22:32:06 +00002981#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002982 case TARGET_SO_BSDCOMPAT:
2983 optname = SO_BSDCOMPAT;
2984 break;
bellard5e83e8e2005-03-01 22:32:06 +00002985#endif
bellard3532fa72006-06-24 15:06:03 +00002986 case TARGET_SO_PASSCRED:
2987 optname = SO_PASSCRED;
2988 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002989 case TARGET_SO_PASSSEC:
2990 optname = SO_PASSSEC;
2991 break;
bellard3532fa72006-06-24 15:06:03 +00002992 case TARGET_SO_TIMESTAMP:
2993 optname = SO_TIMESTAMP;
2994 break;
2995 case TARGET_SO_RCVLOWAT:
2996 optname = SO_RCVLOWAT;
2997 break;
bellard8853f862004-02-22 14:57:26 +00002998 break;
2999 default:
3000 goto unimplemented;
3001 }
bellard3532fa72006-06-24 15:06:03 +00003002 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003003 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003004
bellard2f619692007-11-16 10:46:05 +00003005 if (get_user_u32(val, optval_addr))
3006 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003007 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003008 break;
bellard7854b052003-03-29 17:22:23 +00003009 default:
bellard8853f862004-02-22 14:57:26 +00003010 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003011 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003012 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003013 }
bellard8853f862004-02-22 14:57:26 +00003014 return ret;
bellard7854b052003-03-29 17:22:23 +00003015}
3016
ths0da46a62007-10-20 20:23:07 +00003017/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003018static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003019 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003020{
blueswir1992f48a2007-10-14 16:27:31 +00003021 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003022 int len, val;
3023 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003024
3025 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003026 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003027 level = SOL_SOCKET;
3028 switch (optname) {
3029 /* These don't just return a single integer */
3030 case TARGET_SO_LINGER:
3031 case TARGET_SO_RCVTIMEO:
3032 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003033 case TARGET_SO_PEERNAME:
3034 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003035 case TARGET_SO_PEERCRED: {
3036 struct ucred cr;
3037 socklen_t crlen;
3038 struct target_ucred *tcr;
3039
3040 if (get_user_u32(len, optlen)) {
3041 return -TARGET_EFAULT;
3042 }
3043 if (len < 0) {
3044 return -TARGET_EINVAL;
3045 }
3046
3047 crlen = sizeof(cr);
3048 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3049 &cr, &crlen));
3050 if (ret < 0) {
3051 return ret;
3052 }
3053 if (len > crlen) {
3054 len = crlen;
3055 }
3056 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3057 return -TARGET_EFAULT;
3058 }
3059 __put_user(cr.pid, &tcr->pid);
3060 __put_user(cr.uid, &tcr->uid);
3061 __put_user(cr.gid, &tcr->gid);
3062 unlock_user_struct(tcr, optval_addr, 1);
3063 if (put_user_u32(len, optlen)) {
3064 return -TARGET_EFAULT;
3065 }
3066 break;
3067 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003068 /* Options with 'int' argument. */
3069 case TARGET_SO_DEBUG:
3070 optname = SO_DEBUG;
3071 goto int_case;
3072 case TARGET_SO_REUSEADDR:
3073 optname = SO_REUSEADDR;
3074 goto int_case;
3075 case TARGET_SO_TYPE:
3076 optname = SO_TYPE;
3077 goto int_case;
3078 case TARGET_SO_ERROR:
3079 optname = SO_ERROR;
3080 goto int_case;
3081 case TARGET_SO_DONTROUTE:
3082 optname = SO_DONTROUTE;
3083 goto int_case;
3084 case TARGET_SO_BROADCAST:
3085 optname = SO_BROADCAST;
3086 goto int_case;
3087 case TARGET_SO_SNDBUF:
3088 optname = SO_SNDBUF;
3089 goto int_case;
3090 case TARGET_SO_RCVBUF:
3091 optname = SO_RCVBUF;
3092 goto int_case;
3093 case TARGET_SO_KEEPALIVE:
3094 optname = SO_KEEPALIVE;
3095 goto int_case;
3096 case TARGET_SO_OOBINLINE:
3097 optname = SO_OOBINLINE;
3098 goto int_case;
3099 case TARGET_SO_NO_CHECK:
3100 optname = SO_NO_CHECK;
3101 goto int_case;
3102 case TARGET_SO_PRIORITY:
3103 optname = SO_PRIORITY;
3104 goto int_case;
3105#ifdef SO_BSDCOMPAT
3106 case TARGET_SO_BSDCOMPAT:
3107 optname = SO_BSDCOMPAT;
3108 goto int_case;
3109#endif
3110 case TARGET_SO_PASSCRED:
3111 optname = SO_PASSCRED;
3112 goto int_case;
3113 case TARGET_SO_TIMESTAMP:
3114 optname = SO_TIMESTAMP;
3115 goto int_case;
3116 case TARGET_SO_RCVLOWAT:
3117 optname = SO_RCVLOWAT;
3118 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003119 case TARGET_SO_ACCEPTCONN:
3120 optname = SO_ACCEPTCONN;
3121 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003122 default:
bellard2efbe912005-07-23 15:10:20 +00003123 goto int_case;
3124 }
3125 break;
3126 case SOL_TCP:
3127 /* TCP options all take an 'int' value. */
3128 int_case:
bellard2f619692007-11-16 10:46:05 +00003129 if (get_user_u32(len, optlen))
3130 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003131 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003132 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003133 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003134 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3135 if (ret < 0)
3136 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003137 if (optname == SO_TYPE) {
3138 val = host_to_target_sock_type(val);
3139 }
bellard2efbe912005-07-23 15:10:20 +00003140 if (len > lv)
3141 len = lv;
bellard2f619692007-11-16 10:46:05 +00003142 if (len == 4) {
3143 if (put_user_u32(val, optval_addr))
3144 return -TARGET_EFAULT;
3145 } else {
3146 if (put_user_u8(val, optval_addr))
3147 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003148 }
bellard2f619692007-11-16 10:46:05 +00003149 if (put_user_u32(len, optlen))
3150 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003151 break;
3152 case SOL_IP:
3153 switch(optname) {
3154 case IP_TOS:
3155 case IP_TTL:
3156 case IP_HDRINCL:
3157 case IP_ROUTER_ALERT:
3158 case IP_RECVOPTS:
3159 case IP_RETOPTS:
3160 case IP_PKTINFO:
3161 case IP_MTU_DISCOVER:
3162 case IP_RECVERR:
3163 case IP_RECVTOS:
3164#ifdef IP_FREEBIND
3165 case IP_FREEBIND:
3166#endif
3167 case IP_MULTICAST_TTL:
3168 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003169 if (get_user_u32(len, optlen))
3170 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003171 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003172 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003173 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003174 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3175 if (ret < 0)
3176 return ret;
bellard2efbe912005-07-23 15:10:20 +00003177 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003178 len = 1;
bellard2f619692007-11-16 10:46:05 +00003179 if (put_user_u32(len, optlen)
3180 || put_user_u8(val, optval_addr))
3181 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003182 } else {
bellard2efbe912005-07-23 15:10:20 +00003183 if (len > sizeof(int))
3184 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003185 if (put_user_u32(len, optlen)
3186 || put_user_u32(val, optval_addr))
3187 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003188 }
bellard8853f862004-02-22 14:57:26 +00003189 break;
bellard2efbe912005-07-23 15:10:20 +00003190 default:
thsc02f4992007-12-18 02:39:59 +00003191 ret = -TARGET_ENOPROTOOPT;
3192 break;
bellard8853f862004-02-22 14:57:26 +00003193 }
3194 break;
3195 default:
3196 unimplemented:
3197 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3198 level, optname);
thsc02f4992007-12-18 02:39:59 +00003199 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003200 break;
3201 }
3202 return ret;
bellard7854b052003-03-29 17:22:23 +00003203}
3204
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003205static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003206 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003207{
3208 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003209 struct iovec *vec;
3210 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003211 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003212 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003213 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003214
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003215 if (count == 0) {
3216 errno = 0;
3217 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003218 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003219 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003220 errno = EINVAL;
3221 return NULL;
3222 }
3223
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303224 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003225 if (vec == NULL) {
3226 errno = ENOMEM;
3227 return NULL;
3228 }
3229
3230 target_vec = lock_user(VERIFY_READ, target_addr,
3231 count * sizeof(struct target_iovec), 1);
3232 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003233 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003234 goto fail2;
3235 }
3236
3237 /* ??? If host page size > target page size, this will result in a
3238 value larger than what we can actually support. */
3239 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3240 total_len = 0;
3241
3242 for (i = 0; i < count; i++) {
3243 abi_ulong base = tswapal(target_vec[i].iov_base);
3244 abi_long len = tswapal(target_vec[i].iov_len);
3245
3246 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003247 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003248 goto fail;
3249 } else if (len == 0) {
3250 /* Zero length pointer is ignored. */
3251 vec[i].iov_base = 0;
3252 } else {
3253 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003254 /* If the first buffer pointer is bad, this is a fault. But
3255 * subsequent bad buffers will result in a partial write; this
3256 * is realized by filling the vector with null pointers and
3257 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003258 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003259 if (i == 0) {
3260 err = EFAULT;
3261 goto fail;
3262 } else {
3263 bad_address = true;
3264 }
3265 }
3266 if (bad_address) {
3267 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003268 }
3269 if (len > max_len - total_len) {
3270 len = max_len - total_len;
3271 }
3272 }
3273 vec[i].iov_len = len;
3274 total_len += len;
3275 }
3276
3277 unlock_user(target_vec, target_addr, 0);
3278 return vec;
3279
3280 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003281 while (--i >= 0) {
3282 if (tswapal(target_vec[i].iov_len) > 0) {
3283 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3284 }
3285 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003286 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003287 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303288 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003289 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003290 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003291}
3292
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003293static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003294 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003295{
3296 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003297 int i;
3298
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003299 target_vec = lock_user(VERIFY_READ, target_addr,
3300 count * sizeof(struct target_iovec), 1);
3301 if (target_vec) {
3302 for (i = 0; i < count; i++) {
3303 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003304 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003305 if (len < 0) {
3306 break;
3307 }
balrogd732dcb2008-10-28 10:21:03 +00003308 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3309 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003310 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003311 }
bellard579a97f2007-11-11 14:26:47 +00003312
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303313 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003314}
3315
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003316static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003317{
3318 int host_type = 0;
3319 int target_type = *type;
3320
3321 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3322 case TARGET_SOCK_DGRAM:
3323 host_type = SOCK_DGRAM;
3324 break;
3325 case TARGET_SOCK_STREAM:
3326 host_type = SOCK_STREAM;
3327 break;
3328 default:
3329 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3330 break;
3331 }
3332 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003333#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003334 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003335#else
3336 return -TARGET_EINVAL;
3337#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003338 }
3339 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003340#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003341 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003342#elif !defined(O_NONBLOCK)
3343 return -TARGET_EINVAL;
3344#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003345 }
3346 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003347 return 0;
3348}
3349
3350/* Try to emulate socket type flags after socket creation. */
3351static int sock_flags_fixup(int fd, int target_type)
3352{
3353#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3354 if (target_type & TARGET_SOCK_NONBLOCK) {
3355 int flags = fcntl(fd, F_GETFL);
3356 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3357 close(fd);
3358 return -TARGET_EINVAL;
3359 }
3360 }
3361#endif
3362 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003363}
3364
Laurent Vivier0cf22722015-10-28 21:40:45 +01003365static abi_long packet_target_to_host_sockaddr(void *host_addr,
3366 abi_ulong target_addr,
3367 socklen_t len)
3368{
3369 struct sockaddr *addr = host_addr;
3370 struct target_sockaddr *target_saddr;
3371
3372 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3373 if (!target_saddr) {
3374 return -TARGET_EFAULT;
3375 }
3376
3377 memcpy(addr, target_saddr, len);
3378 addr->sa_family = tswap16(target_saddr->sa_family);
3379 /* spkt_protocol is big-endian */
3380
3381 unlock_user(target_saddr, target_addr, 0);
3382 return 0;
3383}
3384
3385static TargetFdTrans target_packet_trans = {
3386 .target_to_host_addr = packet_target_to_host_sockaddr,
3387};
3388
Laurent Vivier575b22b2016-06-02 22:14:15 +02003389#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003390static abi_long netlink_route_target_to_host(void *buf, size_t len)
3391{
Laurent Vivieref759f62016-06-21 19:51:13 +02003392 abi_long ret;
3393
3394 ret = target_to_host_nlmsg_route(buf, len);
3395 if (ret < 0) {
3396 return ret;
3397 }
3398
3399 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003400}
3401
3402static abi_long netlink_route_host_to_target(void *buf, size_t len)
3403{
Laurent Vivieref759f62016-06-21 19:51:13 +02003404 abi_long ret;
3405
3406 ret = host_to_target_nlmsg_route(buf, len);
3407 if (ret < 0) {
3408 return ret;
3409 }
3410
3411 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003412}
3413
3414static TargetFdTrans target_netlink_route_trans = {
3415 .target_to_host_data = netlink_route_target_to_host,
3416 .host_to_target_data = netlink_route_host_to_target,
3417};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003418#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003419
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003420static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3421{
Laurent Vivieref759f62016-06-21 19:51:13 +02003422 abi_long ret;
3423
3424 ret = target_to_host_nlmsg_audit(buf, len);
3425 if (ret < 0) {
3426 return ret;
3427 }
3428
3429 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003430}
3431
3432static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3433{
Laurent Vivieref759f62016-06-21 19:51:13 +02003434 abi_long ret;
3435
3436 ret = host_to_target_nlmsg_audit(buf, len);
3437 if (ret < 0) {
3438 return ret;
3439 }
3440
3441 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003442}
3443
3444static TargetFdTrans target_netlink_audit_trans = {
3445 .target_to_host_data = netlink_audit_target_to_host,
3446 .host_to_target_data = netlink_audit_host_to_target,
3447};
3448
ths0da46a62007-10-20 20:23:07 +00003449/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003450static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003451{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003452 int target_type = type;
3453 int ret;
3454
3455 ret = target_to_host_sock_type(&type);
3456 if (ret) {
3457 return ret;
3458 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003459
Laurent Vivier575b22b2016-06-02 22:14:15 +02003460 if (domain == PF_NETLINK && !(
3461#ifdef CONFIG_RTNETLINK
3462 protocol == NETLINK_ROUTE ||
3463#endif
3464 protocol == NETLINK_KOBJECT_UEVENT ||
3465 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003466 return -EPFNOSUPPORT;
3467 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003468
3469 if (domain == AF_PACKET ||
3470 (domain == AF_INET && type == SOCK_PACKET)) {
3471 protocol = tswap16(protocol);
3472 }
3473
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003474 ret = get_errno(socket(domain, type, protocol));
3475 if (ret >= 0) {
3476 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003477 if (type == SOCK_PACKET) {
3478 /* Manage an obsolete case :
3479 * if socket type is SOCK_PACKET, bind by name
3480 */
3481 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003482 } else if (domain == PF_NETLINK) {
3483 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003484#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003485 case NETLINK_ROUTE:
3486 fd_trans_register(ret, &target_netlink_route_trans);
3487 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003488#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003489 case NETLINK_KOBJECT_UEVENT:
3490 /* nothing to do: messages are strings */
3491 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003492 case NETLINK_AUDIT:
3493 fd_trans_register(ret, &target_netlink_audit_trans);
3494 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003495 default:
3496 g_assert_not_reached();
3497 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003498 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003499 }
3500 return ret;
bellard3532fa72006-06-24 15:06:03 +00003501}
3502
ths0da46a62007-10-20 20:23:07 +00003503/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003504static abi_long do_bind(int sockfd, abi_ulong target_addr,
3505 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003506{
aurel328f7aeaf2009-01-30 19:47:57 +00003507 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003508 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003509
Blue Swirl38724252010-09-18 05:53:14 +00003510 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003511 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003512 }
aurel328f7aeaf2009-01-30 19:47:57 +00003513
aurel32607175e2009-04-15 16:11:59 +00003514 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003515
Laurent Vivier7b36f782015-10-28 21:40:44 +01003516 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003517 if (ret)
3518 return ret;
3519
bellard3532fa72006-06-24 15:06:03 +00003520 return get_errno(bind(sockfd, addr, addrlen));
3521}
3522
ths0da46a62007-10-20 20:23:07 +00003523/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003524static abi_long do_connect(int sockfd, abi_ulong target_addr,
3525 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003526{
aurel328f7aeaf2009-01-30 19:47:57 +00003527 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003528 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003529
Blue Swirl38724252010-09-18 05:53:14 +00003530 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003531 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003532 }
aurel328f7aeaf2009-01-30 19:47:57 +00003533
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003534 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003535
Laurent Vivier7b36f782015-10-28 21:40:44 +01003536 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003537 if (ret)
3538 return ret;
3539
Peter Maydell2a3c7612016-06-06 19:58:03 +01003540 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003541}
3542
Alexander Graff19e00d2014-03-02 19:36:42 +00003543/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3544static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3545 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003546{
balrog6de645c2008-10-28 10:26:29 +00003547 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003548 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003549 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003550 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003551 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003552
bellard3532fa72006-06-24 15:06:03 +00003553 if (msgp->msg_name) {
3554 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003555 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003556 ret = target_to_host_sockaddr(fd, msg.msg_name,
3557 tswapal(msgp->msg_name),
3558 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003559 if (ret == -TARGET_EFAULT) {
3560 /* For connected sockets msg_name and msg_namelen must
3561 * be ignored, so returning EFAULT immediately is wrong.
3562 * Instead, pass a bad msg_name to the host kernel, and
3563 * let it decide whether to return EFAULT or not.
3564 */
3565 msg.msg_name = (void *)-1;
3566 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003567 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003568 }
bellard3532fa72006-06-24 15:06:03 +00003569 } else {
3570 msg.msg_name = NULL;
3571 msg.msg_namelen = 0;
3572 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003573 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003574 msg.msg_control = alloca(msg.msg_controllen);
3575 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003576
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003577 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003578 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003579
3580 if (count > IOV_MAX) {
3581 /* sendrcvmsg returns a different errno for this condition than
3582 * readv/writev, so we must catch it here before lock_iovec() does.
3583 */
3584 ret = -TARGET_EMSGSIZE;
3585 goto out2;
3586 }
3587
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003588 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3589 target_vec, count, send);
3590 if (vec == NULL) {
3591 ret = -host_to_target_errno(errno);
3592 goto out2;
3593 }
bellard3532fa72006-06-24 15:06:03 +00003594 msg.msg_iovlen = count;
3595 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003596
bellard3532fa72006-06-24 15:06:03 +00003597 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003598 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003599 void *host_msg;
3600
3601 host_msg = g_malloc(msg.msg_iov->iov_len);
3602 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3603 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003604 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003605 if (ret >= 0) {
3606 msg.msg_iov->iov_base = host_msg;
3607 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3608 }
3609 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003610 } else {
3611 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003612 if (ret == 0) {
3613 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3614 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003615 }
bellard3532fa72006-06-24 15:06:03 +00003616 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003617 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003618 if (!is_error(ret)) {
3619 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003620 if (fd_trans_host_to_target_data(fd)) {
3621 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003622 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003623 } else {
3624 ret = host_to_target_cmsg(msgp, &msg);
3625 }
Jing Huangca619062012-07-24 13:58:02 +00003626 if (!is_error(ret)) {
3627 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003628 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003629 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3630 msg.msg_name, msg.msg_namelen);
3631 if (ret) {
3632 goto out;
3633 }
3634 }
3635
balrog6de645c2008-10-28 10:26:29 +00003636 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003637 }
balrog6de645c2008-10-28 10:26:29 +00003638 }
bellard3532fa72006-06-24 15:06:03 +00003639 }
Jing Huangca619062012-07-24 13:58:02 +00003640
3641out:
bellard3532fa72006-06-24 15:06:03 +00003642 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003643out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003644 return ret;
3645}
3646
3647static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3648 int flags, int send)
3649{
3650 abi_long ret;
3651 struct target_msghdr *msgp;
3652
3653 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3654 msgp,
3655 target_msg,
3656 send ? 1 : 0)) {
3657 return -TARGET_EFAULT;
3658 }
3659 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003660 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003661 return ret;
3662}
3663
Alexander Graff19e00d2014-03-02 19:36:42 +00003664/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3665 * so it might not have this *mmsg-specific flag either.
3666 */
3667#ifndef MSG_WAITFORONE
3668#define MSG_WAITFORONE 0x10000
3669#endif
3670
3671static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3672 unsigned int vlen, unsigned int flags,
3673 int send)
3674{
3675 struct target_mmsghdr *mmsgp;
3676 abi_long ret = 0;
3677 int i;
3678
3679 if (vlen > UIO_MAXIOV) {
3680 vlen = UIO_MAXIOV;
3681 }
3682
3683 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3684 if (!mmsgp) {
3685 return -TARGET_EFAULT;
3686 }
3687
3688 for (i = 0; i < vlen; i++) {
3689 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3690 if (is_error(ret)) {
3691 break;
3692 }
3693 mmsgp[i].msg_len = tswap32(ret);
3694 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3695 if (flags & MSG_WAITFORONE) {
3696 flags |= MSG_DONTWAIT;
3697 }
3698 }
3699
3700 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3701
3702 /* Return number of datagrams sent if we sent any at all;
3703 * otherwise return the error.
3704 */
3705 if (i) {
3706 return i;
3707 }
3708 return ret;
3709}
Alexander Graff19e00d2014-03-02 19:36:42 +00003710
Peter Maydella94b4982013-02-08 04:35:04 +00003711/* do_accept4() Must return target values and target errnos. */
3712static abi_long do_accept4(int fd, abi_ulong target_addr,
3713 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003714{
bellard2f619692007-11-16 10:46:05 +00003715 socklen_t addrlen;
3716 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003717 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003718 int host_flags;
3719
3720 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003721
Peter Maydella94b4982013-02-08 04:35:04 +00003722 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003723 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003724 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003725
3726 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003727 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003728 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003729
Blue Swirl38724252010-09-18 05:53:14 +00003730 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003731 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003732 }
aurel328f7aeaf2009-01-30 19:47:57 +00003733
Arnaud Patard917507b2009-06-19 10:44:45 +03003734 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3735 return -TARGET_EINVAL;
3736
bellard2f619692007-11-16 10:46:05 +00003737 addr = alloca(addrlen);
3738
Peter Maydellff6dc132016-06-06 19:58:13 +01003739 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003740 if (!is_error(ret)) {
3741 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003742 if (put_user_u32(addrlen, target_addrlen_addr))
3743 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003744 }
3745 return ret;
3746}
3747
ths0da46a62007-10-20 20:23:07 +00003748/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003749static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003750 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003751{
bellard2f619692007-11-16 10:46:05 +00003752 socklen_t addrlen;
3753 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003754 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003755
bellard2f619692007-11-16 10:46:05 +00003756 if (get_user_u32(addrlen, target_addrlen_addr))
3757 return -TARGET_EFAULT;
3758
Blue Swirl38724252010-09-18 05:53:14 +00003759 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003760 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003761 }
aurel328f7aeaf2009-01-30 19:47:57 +00003762
Arnaud Patard917507b2009-06-19 10:44:45 +03003763 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3764 return -TARGET_EFAULT;
3765
bellard2f619692007-11-16 10:46:05 +00003766 addr = alloca(addrlen);
3767
pbrook1be9e1d2006-11-19 15:26:04 +00003768 ret = get_errno(getpeername(fd, addr, &addrlen));
3769 if (!is_error(ret)) {
3770 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003771 if (put_user_u32(addrlen, target_addrlen_addr))
3772 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003773 }
3774 return ret;
3775}
3776
ths0da46a62007-10-20 20:23:07 +00003777/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003778static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003779 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003780{
bellard2f619692007-11-16 10:46:05 +00003781 socklen_t addrlen;
3782 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003783 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003784
bellard2f619692007-11-16 10:46:05 +00003785 if (get_user_u32(addrlen, target_addrlen_addr))
3786 return -TARGET_EFAULT;
3787
Blue Swirl38724252010-09-18 05:53:14 +00003788 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003789 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003790 }
aurel328f7aeaf2009-01-30 19:47:57 +00003791
Arnaud Patard917507b2009-06-19 10:44:45 +03003792 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3793 return -TARGET_EFAULT;
3794
bellard2f619692007-11-16 10:46:05 +00003795 addr = alloca(addrlen);
3796
pbrook1be9e1d2006-11-19 15:26:04 +00003797 ret = get_errno(getsockname(fd, addr, &addrlen));
3798 if (!is_error(ret)) {
3799 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003800 if (put_user_u32(addrlen, target_addrlen_addr))
3801 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003802 }
3803 return ret;
3804}
3805
ths0da46a62007-10-20 20:23:07 +00003806/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003807static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003808 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003809{
3810 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003811 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003812
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003813 target_to_host_sock_type(&type);
3814
pbrook1be9e1d2006-11-19 15:26:04 +00003815 ret = get_errno(socketpair(domain, type, protocol, tab));
3816 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003817 if (put_user_s32(tab[0], target_tab_addr)
3818 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3819 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003820 }
3821 return ret;
3822}
3823
ths0da46a62007-10-20 20:23:07 +00003824/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003825static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3826 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003827{
3828 void *addr;
3829 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003830 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003831 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003832
Blue Swirl38724252010-09-18 05:53:14 +00003833 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003834 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003835 }
aurel328f7aeaf2009-01-30 19:47:57 +00003836
bellard579a97f2007-11-11 14:26:47 +00003837 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3838 if (!host_msg)
3839 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003840 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003841 copy_msg = host_msg;
3842 host_msg = g_malloc(len);
3843 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003844 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3845 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003846 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003847 }
3848 }
pbrook1be9e1d2006-11-19 15:26:04 +00003849 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003850 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003851 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003852 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003853 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003854 }
Peter Maydell66687532016-06-06 19:58:04 +01003855 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003856 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003857 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003858 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003859fail:
3860 if (copy_msg) {
3861 g_free(host_msg);
3862 host_msg = copy_msg;
3863 }
pbrook1be9e1d2006-11-19 15:26:04 +00003864 unlock_user(host_msg, msg, 0);
3865 return ret;
3866}
3867
ths0da46a62007-10-20 20:23:07 +00003868/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003869static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3870 abi_ulong target_addr,
3871 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003872{
3873 socklen_t addrlen;
3874 void *addr;
3875 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003876 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003877
bellard579a97f2007-11-11 14:26:47 +00003878 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3879 if (!host_msg)
3880 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003881 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003882 if (get_user_u32(addrlen, target_addrlen)) {
3883 ret = -TARGET_EFAULT;
3884 goto fail;
3885 }
Blue Swirl38724252010-09-18 05:53:14 +00003886 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003887 ret = -TARGET_EINVAL;
3888 goto fail;
3889 }
pbrook1be9e1d2006-11-19 15:26:04 +00003890 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003891 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3892 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003893 } else {
3894 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003895 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003896 }
3897 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02003898 if (fd_trans_host_to_target_data(fd)) {
3899 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
3900 }
pbrook1be9e1d2006-11-19 15:26:04 +00003901 if (target_addr) {
3902 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003903 if (put_user_u32(addrlen, target_addrlen)) {
3904 ret = -TARGET_EFAULT;
3905 goto fail;
3906 }
pbrook1be9e1d2006-11-19 15:26:04 +00003907 }
3908 unlock_user(host_msg, msg, len);
3909 } else {
bellard2f619692007-11-16 10:46:05 +00003910fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003911 unlock_user(host_msg, msg, 0);
3912 }
3913 return ret;
3914}
3915
j_mayer32407102007-09-26 23:01:49 +00003916#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003917/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003918static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003919{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003920 static const unsigned nargs[] = { /* number of arguments per operation */
3921 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
3922 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
3923 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
3924 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
3925 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
3926 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
3927 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
3928 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
3929 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
3930 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
3931 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
3932 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
3933 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
3934 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3935 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
3936 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
3937 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
3938 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
3939 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
3940 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003941 };
3942 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003943 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00003944
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003945 /* check the range of the first argument num */
3946 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
3947 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
3948 return -TARGET_EINVAL;
3949 }
3950 /* ensure we have space for args */
3951 if (nargs[num] > ARRAY_SIZE(a)) {
3952 return -TARGET_EINVAL;
3953 }
3954 /* collect the arguments in a[] according to nargs[] */
3955 for (i = 0; i < nargs[num]; ++i) {
3956 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
3957 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01003958 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003959 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003960 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003961 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003962 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003963 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003964 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003965 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003966 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003967 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003968 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003969 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003970 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003971 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003972 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003973 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003974 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003975 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003976 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003977 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003978 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003979 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003980 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003981 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003982 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003983 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003984 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003985 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003986 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003987 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003988 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003989 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003990 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003991 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02003992 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
3993 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3994 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
3995 return do_sendrecvmsg(a[0], a[1], a[2], 0);
3996 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
3997 return do_accept4(a[0], a[1], a[2], a[3]);
3998 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
3999 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4000 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4001 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004002 default:
4003 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004004 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004005 }
bellard31e31b82003-02-18 22:55:36 +00004006}
j_mayer32407102007-09-26 23:01:49 +00004007#endif
bellard31e31b82003-02-18 22:55:36 +00004008
bellard8853f862004-02-22 14:57:26 +00004009#define N_SHM_REGIONS 32
4010
4011static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004012 abi_ulong start;
4013 abi_ulong size;
4014 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004015} shm_regions[N_SHM_REGIONS];
4016
Peter Maydell005eb2a2016-07-15 16:50:47 +01004017#ifndef TARGET_SEMID64_DS
4018/* asm-generic version of this struct */
4019struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004020{
4021 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004022 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004023#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004024 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004025#endif
blueswir1992f48a2007-10-14 16:27:31 +00004026 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004027#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004028 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004029#endif
blueswir1992f48a2007-10-14 16:27:31 +00004030 abi_ulong sem_nsems;
4031 abi_ulong __unused3;
4032 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004033};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004034#endif
ths3eb6b042007-06-03 14:26:27 +00004035
bellard579a97f2007-11-11 14:26:47 +00004036static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4037 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004038{
4039 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004040 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004041
bellard579a97f2007-11-11 14:26:47 +00004042 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4043 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004044 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004045 host_ip->__key = tswap32(target_ip->__key);
4046 host_ip->uid = tswap32(target_ip->uid);
4047 host_ip->gid = tswap32(target_ip->gid);
4048 host_ip->cuid = tswap32(target_ip->cuid);
4049 host_ip->cgid = tswap32(target_ip->cgid);
4050#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4051 host_ip->mode = tswap32(target_ip->mode);
4052#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004053 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004054#endif
4055#if defined(TARGET_PPC)
4056 host_ip->__seq = tswap32(target_ip->__seq);
4057#else
4058 host_ip->__seq = tswap16(target_ip->__seq);
4059#endif
ths3eb6b042007-06-03 14:26:27 +00004060 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004061 return 0;
ths3eb6b042007-06-03 14:26:27 +00004062}
4063
bellard579a97f2007-11-11 14:26:47 +00004064static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4065 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004066{
4067 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004068 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004069
bellard579a97f2007-11-11 14:26:47 +00004070 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4071 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004072 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004073 target_ip->__key = tswap32(host_ip->__key);
4074 target_ip->uid = tswap32(host_ip->uid);
4075 target_ip->gid = tswap32(host_ip->gid);
4076 target_ip->cuid = tswap32(host_ip->cuid);
4077 target_ip->cgid = tswap32(host_ip->cgid);
4078#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4079 target_ip->mode = tswap32(host_ip->mode);
4080#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004081 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004082#endif
4083#if defined(TARGET_PPC)
4084 target_ip->__seq = tswap32(host_ip->__seq);
4085#else
4086 target_ip->__seq = tswap16(host_ip->__seq);
4087#endif
ths3eb6b042007-06-03 14:26:27 +00004088 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004089 return 0;
ths3eb6b042007-06-03 14:26:27 +00004090}
4091
bellard579a97f2007-11-11 14:26:47 +00004092static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4093 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004094{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004095 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004096
bellard579a97f2007-11-11 14:26:47 +00004097 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4098 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004099 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4100 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004101 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4102 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4103 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004104 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004105 return 0;
ths3eb6b042007-06-03 14:26:27 +00004106}
4107
bellard579a97f2007-11-11 14:26:47 +00004108static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4109 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004110{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004111 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004112
bellard579a97f2007-11-11 14:26:47 +00004113 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4114 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004115 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004116 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004117 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4118 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4119 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004120 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004121 return 0;
ths3eb6b042007-06-03 14:26:27 +00004122}
4123
aurel32e5289082009-04-18 16:16:12 +00004124struct target_seminfo {
4125 int semmap;
4126 int semmni;
4127 int semmns;
4128 int semmnu;
4129 int semmsl;
4130 int semopm;
4131 int semume;
4132 int semusz;
4133 int semvmx;
4134 int semaem;
4135};
4136
4137static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4138 struct seminfo *host_seminfo)
4139{
4140 struct target_seminfo *target_seminfo;
4141 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4142 return -TARGET_EFAULT;
4143 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4144 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4145 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4146 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4147 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4148 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4149 __put_user(host_seminfo->semume, &target_seminfo->semume);
4150 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4151 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4152 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4153 unlock_user_struct(target_seminfo, target_addr, 1);
4154 return 0;
4155}
4156
thsfa294812007-02-02 22:05:00 +00004157union semun {
4158 int val;
ths3eb6b042007-06-03 14:26:27 +00004159 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004160 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004161 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004162};
4163
ths3eb6b042007-06-03 14:26:27 +00004164union target_semun {
4165 int val;
aurel32e5289082009-04-18 16:16:12 +00004166 abi_ulong buf;
4167 abi_ulong array;
4168 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004169};
4170
aurel32e5289082009-04-18 16:16:12 +00004171static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4172 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004173{
aurel32e5289082009-04-18 16:16:12 +00004174 int nsems;
4175 unsigned short *array;
4176 union semun semun;
4177 struct semid_ds semid_ds;
4178 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004179
aurel32e5289082009-04-18 16:16:12 +00004180 semun.buf = &semid_ds;
4181
4182 ret = semctl(semid, 0, IPC_STAT, semun);
4183 if (ret == -1)
4184 return get_errno(ret);
4185
4186 nsems = semid_ds.sem_nsems;
4187
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304188 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004189 if (!*host_array) {
4190 return -TARGET_ENOMEM;
4191 }
aurel32e5289082009-04-18 16:16:12 +00004192 array = lock_user(VERIFY_READ, target_addr,
4193 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004194 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304195 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004196 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004197 }
aurel32e5289082009-04-18 16:16:12 +00004198
4199 for(i=0; i<nsems; i++) {
4200 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004201 }
aurel32e5289082009-04-18 16:16:12 +00004202 unlock_user(array, target_addr, 0);
4203
bellard579a97f2007-11-11 14:26:47 +00004204 return 0;
ths3eb6b042007-06-03 14:26:27 +00004205}
4206
aurel32e5289082009-04-18 16:16:12 +00004207static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4208 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004209{
aurel32e5289082009-04-18 16:16:12 +00004210 int nsems;
4211 unsigned short *array;
4212 union semun semun;
4213 struct semid_ds semid_ds;
4214 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004215
aurel32e5289082009-04-18 16:16:12 +00004216 semun.buf = &semid_ds;
4217
4218 ret = semctl(semid, 0, IPC_STAT, semun);
4219 if (ret == -1)
4220 return get_errno(ret);
4221
4222 nsems = semid_ds.sem_nsems;
4223
4224 array = lock_user(VERIFY_WRITE, target_addr,
4225 nsems*sizeof(unsigned short), 0);
4226 if (!array)
4227 return -TARGET_EFAULT;
4228
4229 for(i=0; i<nsems; i++) {
4230 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004231 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304232 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004233 unlock_user(array, target_addr, 1);
4234
bellard579a97f2007-11-11 14:26:47 +00004235 return 0;
ths3eb6b042007-06-03 14:26:27 +00004236}
4237
aurel32e5289082009-04-18 16:16:12 +00004238static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004239 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004240{
Stefan Weild1c002b2015-02-08 15:40:58 +01004241 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004242 union semun arg;
4243 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304244 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004245 struct seminfo seminfo;
4246 abi_long ret = -TARGET_EINVAL;
4247 abi_long err;
4248 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004249
4250 switch( cmd ) {
4251 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004252 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004253 /* In 64 bit cross-endian situations, we will erroneously pick up
4254 * the wrong half of the union for the "val" element. To rectify
4255 * this, the entire 8-byte structure is byteswapped, followed by
4256 * a swap of the 4 byte val field. In other cases, the data is
4257 * already in proper host byte order. */
4258 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4259 target_su.buf = tswapal(target_su.buf);
4260 arg.val = tswap32(target_su.val);
4261 } else {
4262 arg.val = target_su.val;
4263 }
aurel32e5289082009-04-18 16:16:12 +00004264 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004265 break;
4266 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004267 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004268 err = target_to_host_semarray(semid, &array, target_su.array);
4269 if (err)
4270 return err;
4271 arg.array = array;
4272 ret = get_errno(semctl(semid, semnum, cmd, arg));
4273 err = host_to_target_semarray(semid, target_su.array, &array);
4274 if (err)
4275 return err;
ths3eb6b042007-06-03 14:26:27 +00004276 break;
4277 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004278 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004279 case SEM_STAT:
4280 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4281 if (err)
4282 return err;
4283 arg.buf = &dsarg;
4284 ret = get_errno(semctl(semid, semnum, cmd, arg));
4285 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4286 if (err)
4287 return err;
ths3eb6b042007-06-03 14:26:27 +00004288 break;
aurel32e5289082009-04-18 16:16:12 +00004289 case IPC_INFO:
4290 case SEM_INFO:
4291 arg.__buf = &seminfo;
4292 ret = get_errno(semctl(semid, semnum, cmd, arg));
4293 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4294 if (err)
4295 return err;
4296 break;
4297 case IPC_RMID:
4298 case GETPID:
4299 case GETNCNT:
4300 case GETZCNT:
4301 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4302 break;
ths3eb6b042007-06-03 14:26:27 +00004303 }
4304
4305 return ret;
4306}
4307
aurel32e5289082009-04-18 16:16:12 +00004308struct target_sembuf {
4309 unsigned short sem_num;
4310 short sem_op;
4311 short sem_flg;
4312};
4313
4314static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4315 abi_ulong target_addr,
4316 unsigned nsops)
4317{
4318 struct target_sembuf *target_sembuf;
4319 int i;
4320
4321 target_sembuf = lock_user(VERIFY_READ, target_addr,
4322 nsops*sizeof(struct target_sembuf), 1);
4323 if (!target_sembuf)
4324 return -TARGET_EFAULT;
4325
4326 for(i=0; i<nsops; i++) {
4327 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4328 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4329 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4330 }
4331
4332 unlock_user(target_sembuf, target_addr, 0);
4333
4334 return 0;
4335}
4336
4337static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4338{
4339 struct sembuf sops[nsops];
4340
4341 if (target_to_host_sembuf(sops, ptr, nsops))
4342 return -TARGET_EFAULT;
4343
Peter Maydellffb7ee72016-06-06 19:58:12 +01004344 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004345}
4346
ths1bc012f2007-06-03 14:27:49 +00004347struct target_msqid_ds
4348{
aurel321c54ff92008-10-13 21:08:44 +00004349 struct target_ipc_perm msg_perm;
4350 abi_ulong msg_stime;
4351#if TARGET_ABI_BITS == 32
4352 abi_ulong __unused1;
4353#endif
4354 abi_ulong msg_rtime;
4355#if TARGET_ABI_BITS == 32
4356 abi_ulong __unused2;
4357#endif
4358 abi_ulong msg_ctime;
4359#if TARGET_ABI_BITS == 32
4360 abi_ulong __unused3;
4361#endif
4362 abi_ulong __msg_cbytes;
4363 abi_ulong msg_qnum;
4364 abi_ulong msg_qbytes;
4365 abi_ulong msg_lspid;
4366 abi_ulong msg_lrpid;
4367 abi_ulong __unused4;
4368 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004369};
4370
bellard579a97f2007-11-11 14:26:47 +00004371static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4372 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004373{
4374 struct target_msqid_ds *target_md;
4375
bellard579a97f2007-11-11 14:26:47 +00004376 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4377 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004378 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4379 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004380 host_md->msg_stime = tswapal(target_md->msg_stime);
4381 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4382 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4383 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4384 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4385 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4386 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4387 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004388 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004389 return 0;
ths1bc012f2007-06-03 14:27:49 +00004390}
4391
bellard579a97f2007-11-11 14:26:47 +00004392static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4393 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004394{
4395 struct target_msqid_ds *target_md;
4396
bellard579a97f2007-11-11 14:26:47 +00004397 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4398 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004399 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4400 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004401 target_md->msg_stime = tswapal(host_md->msg_stime);
4402 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4403 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4404 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4405 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4406 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4407 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4408 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004409 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004410 return 0;
ths1bc012f2007-06-03 14:27:49 +00004411}
4412
aurel321c54ff92008-10-13 21:08:44 +00004413struct target_msginfo {
4414 int msgpool;
4415 int msgmap;
4416 int msgmax;
4417 int msgmnb;
4418 int msgmni;
4419 int msgssz;
4420 int msgtql;
4421 unsigned short int msgseg;
4422};
4423
4424static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4425 struct msginfo *host_msginfo)
4426{
4427 struct target_msginfo *target_msginfo;
4428 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4429 return -TARGET_EFAULT;
4430 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4431 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4432 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4433 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4434 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4435 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4436 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4437 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4438 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004439 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004440}
4441
4442static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004443{
4444 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004445 struct msginfo msginfo;
4446 abi_long ret = -TARGET_EINVAL;
4447
4448 cmd &= 0xff;
4449
4450 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004451 case IPC_STAT:
4452 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004453 case MSG_STAT:
4454 if (target_to_host_msqid_ds(&dsarg,ptr))
4455 return -TARGET_EFAULT;
4456 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4457 if (host_to_target_msqid_ds(ptr,&dsarg))
4458 return -TARGET_EFAULT;
4459 break;
4460 case IPC_RMID:
4461 ret = get_errno(msgctl(msgid, cmd, NULL));
4462 break;
4463 case IPC_INFO:
4464 case MSG_INFO:
4465 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4466 if (host_to_target_msginfo(ptr, &msginfo))
4467 return -TARGET_EFAULT;
4468 break;
ths1bc012f2007-06-03 14:27:49 +00004469 }
aurel321c54ff92008-10-13 21:08:44 +00004470
ths1bc012f2007-06-03 14:27:49 +00004471 return ret;
4472}
4473
4474struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004475 abi_long mtype;
4476 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004477};
4478
blueswir1992f48a2007-10-14 16:27:31 +00004479static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004480 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004481{
4482 struct target_msgbuf *target_mb;
4483 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004484 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004485
Tom Mustaedcc5f92014-08-12 13:53:37 -05004486 if (msgsz < 0) {
4487 return -TARGET_EINVAL;
4488 }
4489
bellard579a97f2007-11-11 14:26:47 +00004490 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4491 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304492 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004493 if (!host_mb) {
4494 unlock_user_struct(target_mb, msgp, 0);
4495 return -TARGET_ENOMEM;
4496 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004497 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004498 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004499 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304500 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004501 unlock_user_struct(target_mb, msgp, 0);
4502
4503 return ret;
4504}
4505
blueswir1992f48a2007-10-14 16:27:31 +00004506static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004507 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004508 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004509{
4510 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004511 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004512 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004513 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004514
Peter Maydell99874f62016-05-20 19:00:56 +01004515 if (msgsz < 0) {
4516 return -TARGET_EINVAL;
4517 }
4518
bellard579a97f2007-11-11 14:26:47 +00004519 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4520 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004521
Peter Maydell415d8472016-05-20 19:00:57 +01004522 host_mb = g_try_malloc(msgsz + sizeof(long));
4523 if (!host_mb) {
4524 ret = -TARGET_ENOMEM;
4525 goto end;
4526 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004527 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004528
bellard579a97f2007-11-11 14:26:47 +00004529 if (ret > 0) {
4530 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4531 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4532 if (!target_mtext) {
4533 ret = -TARGET_EFAULT;
4534 goto end;
4535 }
aurel321c54ff92008-10-13 21:08:44 +00004536 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004537 unlock_user(target_mtext, target_mtext_addr, ret);
4538 }
aurel321c54ff92008-10-13 21:08:44 +00004539
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004540 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004541
bellard579a97f2007-11-11 14:26:47 +00004542end:
4543 if (target_mb)
4544 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004545 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004546 return ret;
4547}
4548
Riku Voipio88a8c982009-04-03 10:42:00 +03004549static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4550 abi_ulong target_addr)
4551{
4552 struct target_shmid_ds *target_sd;
4553
4554 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4555 return -TARGET_EFAULT;
4556 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4557 return -TARGET_EFAULT;
4558 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4559 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4560 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4561 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4562 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4563 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4564 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4565 unlock_user_struct(target_sd, target_addr, 0);
4566 return 0;
4567}
4568
4569static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4570 struct shmid_ds *host_sd)
4571{
4572 struct target_shmid_ds *target_sd;
4573
4574 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4575 return -TARGET_EFAULT;
4576 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4577 return -TARGET_EFAULT;
4578 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4579 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4580 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4581 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4582 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4583 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4584 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4585 unlock_user_struct(target_sd, target_addr, 1);
4586 return 0;
4587}
4588
4589struct target_shminfo {
4590 abi_ulong shmmax;
4591 abi_ulong shmmin;
4592 abi_ulong shmmni;
4593 abi_ulong shmseg;
4594 abi_ulong shmall;
4595};
4596
4597static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4598 struct shminfo *host_shminfo)
4599{
4600 struct target_shminfo *target_shminfo;
4601 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4602 return -TARGET_EFAULT;
4603 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4604 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4605 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4606 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4607 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4608 unlock_user_struct(target_shminfo, target_addr, 1);
4609 return 0;
4610}
4611
4612struct target_shm_info {
4613 int used_ids;
4614 abi_ulong shm_tot;
4615 abi_ulong shm_rss;
4616 abi_ulong shm_swp;
4617 abi_ulong swap_attempts;
4618 abi_ulong swap_successes;
4619};
4620
4621static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4622 struct shm_info *host_shm_info)
4623{
4624 struct target_shm_info *target_shm_info;
4625 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4626 return -TARGET_EFAULT;
4627 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4628 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4629 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4630 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4631 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4632 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4633 unlock_user_struct(target_shm_info, target_addr, 1);
4634 return 0;
4635}
4636
4637static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4638{
4639 struct shmid_ds dsarg;
4640 struct shminfo shminfo;
4641 struct shm_info shm_info;
4642 abi_long ret = -TARGET_EINVAL;
4643
4644 cmd &= 0xff;
4645
4646 switch(cmd) {
4647 case IPC_STAT:
4648 case IPC_SET:
4649 case SHM_STAT:
4650 if (target_to_host_shmid_ds(&dsarg, buf))
4651 return -TARGET_EFAULT;
4652 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4653 if (host_to_target_shmid_ds(buf, &dsarg))
4654 return -TARGET_EFAULT;
4655 break;
4656 case IPC_INFO:
4657 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4658 if (host_to_target_shminfo(buf, &shminfo))
4659 return -TARGET_EFAULT;
4660 break;
4661 case SHM_INFO:
4662 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4663 if (host_to_target_shm_info(buf, &shm_info))
4664 return -TARGET_EFAULT;
4665 break;
4666 case IPC_RMID:
4667 case SHM_LOCK:
4668 case SHM_UNLOCK:
4669 ret = get_errno(shmctl(shmid, cmd, NULL));
4670 break;
4671 }
4672
4673 return ret;
4674}
4675
Peter Maydellee8e7612016-07-11 16:48:11 +01004676#ifndef TARGET_FORCE_SHMLBA
4677/* For most architectures, SHMLBA is the same as the page size;
4678 * some architectures have larger values, in which case they should
4679 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4680 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4681 * and defining its own value for SHMLBA.
4682 *
4683 * The kernel also permits SHMLBA to be set by the architecture to a
4684 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4685 * this means that addresses are rounded to the large size if
4686 * SHM_RND is set but addresses not aligned to that size are not rejected
4687 * as long as they are at least page-aligned. Since the only architecture
4688 * which uses this is ia64 this code doesn't provide for that oddity.
4689 */
4690static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4691{
4692 return TARGET_PAGE_SIZE;
4693}
4694#endif
4695
4696static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4697 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004698{
4699 abi_long raddr;
4700 void *host_raddr;
4701 struct shmid_ds shm_info;
4702 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004703 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004704
4705 /* find out the length of the shared memory segment */
4706 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4707 if (is_error(ret)) {
4708 /* can't get length, bail out */
4709 return ret;
4710 }
4711
Peter Maydellee8e7612016-07-11 16:48:11 +01004712 shmlba = target_shmlba(cpu_env);
4713
4714 if (shmaddr & (shmlba - 1)) {
4715 if (shmflg & SHM_RND) {
4716 shmaddr &= ~(shmlba - 1);
4717 } else {
4718 return -TARGET_EINVAL;
4719 }
4720 }
4721
Riku Voipio88a8c982009-04-03 10:42:00 +03004722 mmap_lock();
4723
4724 if (shmaddr)
4725 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4726 else {
4727 abi_ulong mmap_start;
4728
4729 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4730
4731 if (mmap_start == -1) {
4732 errno = ENOMEM;
4733 host_raddr = (void *)-1;
4734 } else
4735 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4736 }
4737
4738 if (host_raddr == (void *)-1) {
4739 mmap_unlock();
4740 return get_errno((long)host_raddr);
4741 }
4742 raddr=h2g((unsigned long)host_raddr);
4743
4744 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4745 PAGE_VALID | PAGE_READ |
4746 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4747
4748 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004749 if (!shm_regions[i].in_use) {
4750 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004751 shm_regions[i].start = raddr;
4752 shm_regions[i].size = shm_info.shm_segsz;
4753 break;
4754 }
4755 }
4756
4757 mmap_unlock();
4758 return raddr;
4759
4760}
4761
4762static inline abi_long do_shmdt(abi_ulong shmaddr)
4763{
4764 int i;
4765
4766 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004767 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4768 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004769 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004770 break;
4771 }
4772 }
4773
4774 return get_errno(shmdt(g2h(shmaddr)));
4775}
4776
aurel321c54ff92008-10-13 21:08:44 +00004777#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004778/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004779/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004780static abi_long do_ipc(CPUArchState *cpu_env,
4781 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004782 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004783 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004784{
4785 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004786 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004787
4788 version = call >> 16;
4789 call &= 0xffff;
4790
4791 switch (call) {
thsfa294812007-02-02 22:05:00 +00004792 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004793 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004794 break;
4795
4796 case IPCOP_semget:
4797 ret = get_errno(semget(first, second, third));
4798 break;
4799
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004800 case IPCOP_semctl: {
4801 /* The semun argument to semctl is passed by value, so dereference the
4802 * ptr argument. */
4803 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004804 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004805 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004806 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004807 }
thsd96372e2007-02-02 22:05:44 +00004808
aurel321c54ff92008-10-13 21:08:44 +00004809 case IPCOP_msgget:
4810 ret = get_errno(msgget(first, second));
4811 break;
thsd96372e2007-02-02 22:05:44 +00004812
aurel321c54ff92008-10-13 21:08:44 +00004813 case IPCOP_msgsnd:
4814 ret = do_msgsnd(first, ptr, second, third);
4815 break;
thsd96372e2007-02-02 22:05:44 +00004816
aurel321c54ff92008-10-13 21:08:44 +00004817 case IPCOP_msgctl:
4818 ret = do_msgctl(first, second, ptr);
4819 break;
thsd96372e2007-02-02 22:05:44 +00004820
aurel321c54ff92008-10-13 21:08:44 +00004821 case IPCOP_msgrcv:
4822 switch (version) {
4823 case 0:
4824 {
4825 struct target_ipc_kludge {
4826 abi_long msgp;
4827 abi_long msgtyp;
4828 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004829
aurel321c54ff92008-10-13 21:08:44 +00004830 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4831 ret = -TARGET_EFAULT;
4832 break;
ths1bc012f2007-06-03 14:27:49 +00004833 }
aurel321c54ff92008-10-13 21:08:44 +00004834
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004835 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004836
4837 unlock_user_struct(tmp, ptr, 0);
4838 break;
4839 }
4840 default:
4841 ret = do_msgrcv(first, ptr, second, fifth, third);
4842 }
4843 break;
thsd96372e2007-02-02 22:05:44 +00004844
bellard8853f862004-02-22 14:57:26 +00004845 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004846 switch (version) {
4847 default:
bellard5a4a8982007-11-11 17:39:18 +00004848 {
4849 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01004850 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03004851 if (is_error(raddr))
4852 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004853 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004854 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004855 break;
4856 }
4857 case 1:
4858 ret = -TARGET_EINVAL;
4859 break;
bellard5a4a8982007-11-11 17:39:18 +00004860 }
bellard8853f862004-02-22 14:57:26 +00004861 break;
4862 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004863 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004864 break;
4865
4866 case IPCOP_shmget:
4867 /* IPC_* flag values are the same on all linux platforms */
4868 ret = get_errno(shmget(first, second, third));
4869 break;
4870
4871 /* IPC_* and SHM_* command values are the same on all linux platforms */
4872 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004873 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004874 break;
4875 default:
j_mayer32407102007-09-26 23:01:49 +00004876 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004877 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004878 break;
4879 }
4880 return ret;
4881}
j_mayer32407102007-09-26 23:01:49 +00004882#endif
bellard8853f862004-02-22 14:57:26 +00004883
bellard31e31b82003-02-18 22:55:36 +00004884/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004885
Blue Swirl001faf32009-05-13 17:53:17 +00004886#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004887#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4888enum {
4889#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004890STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004891};
4892#undef STRUCT
4893#undef STRUCT_SPECIAL
4894
Blue Swirl001faf32009-05-13 17:53:17 +00004895#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004896#define STRUCT_SPECIAL(name)
4897#include "syscall_types.h"
4898#undef STRUCT
4899#undef STRUCT_SPECIAL
4900
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004901typedef struct IOCTLEntry IOCTLEntry;
4902
4903typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004904 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004905
4906struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004907 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004908 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004909 const char *name;
4910 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004911 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004912 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004913};
bellard31e31b82003-02-18 22:55:36 +00004914
4915#define IOC_R 0x0001
4916#define IOC_W 0x0002
4917#define IOC_RW (IOC_R | IOC_W)
4918
4919#define MAX_STRUCT_SIZE 4096
4920
Peter Maydelldace20d2011-01-10 13:11:24 +00004921#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004922/* So fiemap access checks don't overflow on 32 bit systems.
4923 * This is very slightly smaller than the limit imposed by
4924 * the underlying kernel.
4925 */
4926#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4927 / sizeof(struct fiemap_extent))
4928
4929static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004930 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004931{
4932 /* The parameter for this ioctl is a struct fiemap followed
4933 * by an array of struct fiemap_extent whose size is set
4934 * in fiemap->fm_extent_count. The array is filled in by the
4935 * ioctl.
4936 */
4937 int target_size_in, target_size_out;
4938 struct fiemap *fm;
4939 const argtype *arg_type = ie->arg_type;
4940 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4941 void *argptr, *p;
4942 abi_long ret;
4943 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4944 uint32_t outbufsz;
4945 int free_fm = 0;
4946
4947 assert(arg_type[0] == TYPE_PTR);
4948 assert(ie->access == IOC_RW);
4949 arg_type++;
4950 target_size_in = thunk_type_size(arg_type, 0);
4951 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4952 if (!argptr) {
4953 return -TARGET_EFAULT;
4954 }
4955 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4956 unlock_user(argptr, arg, 0);
4957 fm = (struct fiemap *)buf_temp;
4958 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4959 return -TARGET_EINVAL;
4960 }
4961
4962 outbufsz = sizeof (*fm) +
4963 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4964
4965 if (outbufsz > MAX_STRUCT_SIZE) {
4966 /* We can't fit all the extents into the fixed size buffer.
4967 * Allocate one that is large enough and use it instead.
4968 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304969 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004970 if (!fm) {
4971 return -TARGET_ENOMEM;
4972 }
4973 memcpy(fm, buf_temp, sizeof(struct fiemap));
4974 free_fm = 1;
4975 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01004976 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00004977 if (!is_error(ret)) {
4978 target_size_out = target_size_in;
4979 /* An extent_count of 0 means we were only counting the extents
4980 * so there are no structs to copy
4981 */
4982 if (fm->fm_extent_count != 0) {
4983 target_size_out += fm->fm_mapped_extents * extent_size;
4984 }
4985 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4986 if (!argptr) {
4987 ret = -TARGET_EFAULT;
4988 } else {
4989 /* Convert the struct fiemap */
4990 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4991 if (fm->fm_extent_count != 0) {
4992 p = argptr + target_size_in;
4993 /* ...and then all the struct fiemap_extents */
4994 for (i = 0; i < fm->fm_mapped_extents; i++) {
4995 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4996 THUNK_TARGET);
4997 p += extent_size;
4998 }
4999 }
5000 unlock_user(argptr, arg, target_size_out);
5001 }
5002 }
5003 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305004 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005005 }
5006 return ret;
5007}
Peter Maydelldace20d2011-01-10 13:11:24 +00005008#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005009
Laurent Vivier059c2f22011-03-30 00:12:12 +02005010static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005011 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005012{
5013 const argtype *arg_type = ie->arg_type;
5014 int target_size;
5015 void *argptr;
5016 int ret;
5017 struct ifconf *host_ifconf;
5018 uint32_t outbufsz;
5019 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5020 int target_ifreq_size;
5021 int nb_ifreq;
5022 int free_buf = 0;
5023 int i;
5024 int target_ifc_len;
5025 abi_long target_ifc_buf;
5026 int host_ifc_len;
5027 char *host_ifc_buf;
5028
5029 assert(arg_type[0] == TYPE_PTR);
5030 assert(ie->access == IOC_RW);
5031
5032 arg_type++;
5033 target_size = thunk_type_size(arg_type, 0);
5034
5035 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5036 if (!argptr)
5037 return -TARGET_EFAULT;
5038 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5039 unlock_user(argptr, arg, 0);
5040
5041 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5042 target_ifc_len = host_ifconf->ifc_len;
5043 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5044
5045 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5046 nb_ifreq = target_ifc_len / target_ifreq_size;
5047 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5048
5049 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5050 if (outbufsz > MAX_STRUCT_SIZE) {
5051 /* We can't fit all the extents into the fixed size buffer.
5052 * Allocate one that is large enough and use it instead.
5053 */
5054 host_ifconf = malloc(outbufsz);
5055 if (!host_ifconf) {
5056 return -TARGET_ENOMEM;
5057 }
5058 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5059 free_buf = 1;
5060 }
5061 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5062
5063 host_ifconf->ifc_len = host_ifc_len;
5064 host_ifconf->ifc_buf = host_ifc_buf;
5065
Peter Maydell49ca6f32016-06-06 19:58:14 +01005066 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005067 if (!is_error(ret)) {
5068 /* convert host ifc_len to target ifc_len */
5069
5070 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5071 target_ifc_len = nb_ifreq * target_ifreq_size;
5072 host_ifconf->ifc_len = target_ifc_len;
5073
5074 /* restore target ifc_buf */
5075
5076 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5077
5078 /* copy struct ifconf to target user */
5079
5080 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5081 if (!argptr)
5082 return -TARGET_EFAULT;
5083 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5084 unlock_user(argptr, arg, target_size);
5085
5086 /* copy ifreq[] to target user */
5087
5088 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5089 for (i = 0; i < nb_ifreq ; i++) {
5090 thunk_convert(argptr + i * target_ifreq_size,
5091 host_ifc_buf + i * sizeof(struct ifreq),
5092 ifreq_arg_type, THUNK_TARGET);
5093 }
5094 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5095 }
5096
5097 if (free_buf) {
5098 free(host_ifconf);
5099 }
5100
5101 return ret;
5102}
5103
Alexander Graf56e904e2012-01-31 18:42:06 +01005104static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005105 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005106{
5107 void *argptr;
5108 struct dm_ioctl *host_dm;
5109 abi_long guest_data;
5110 uint32_t guest_data_size;
5111 int target_size;
5112 const argtype *arg_type = ie->arg_type;
5113 abi_long ret;
5114 void *big_buf = NULL;
5115 char *host_data;
5116
5117 arg_type++;
5118 target_size = thunk_type_size(arg_type, 0);
5119 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5120 if (!argptr) {
5121 ret = -TARGET_EFAULT;
5122 goto out;
5123 }
5124 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5125 unlock_user(argptr, arg, 0);
5126
5127 /* buf_temp is too small, so fetch things into a bigger buffer */
5128 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5129 memcpy(big_buf, buf_temp, target_size);
5130 buf_temp = big_buf;
5131 host_dm = big_buf;
5132
5133 guest_data = arg + host_dm->data_start;
5134 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005135 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005136 goto out;
5137 }
5138 guest_data_size = host_dm->data_size - host_dm->data_start;
5139 host_data = (char*)host_dm + host_dm->data_start;
5140
5141 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005142 if (!argptr) {
5143 ret = -TARGET_EFAULT;
5144 goto out;
5145 }
5146
Alexander Graf56e904e2012-01-31 18:42:06 +01005147 switch (ie->host_cmd) {
5148 case DM_REMOVE_ALL:
5149 case DM_LIST_DEVICES:
5150 case DM_DEV_CREATE:
5151 case DM_DEV_REMOVE:
5152 case DM_DEV_SUSPEND:
5153 case DM_DEV_STATUS:
5154 case DM_DEV_WAIT:
5155 case DM_TABLE_STATUS:
5156 case DM_TABLE_CLEAR:
5157 case DM_TABLE_DEPS:
5158 case DM_LIST_VERSIONS:
5159 /* no input data */
5160 break;
5161 case DM_DEV_RENAME:
5162 case DM_DEV_SET_GEOMETRY:
5163 /* data contains only strings */
5164 memcpy(host_data, argptr, guest_data_size);
5165 break;
5166 case DM_TARGET_MSG:
5167 memcpy(host_data, argptr, guest_data_size);
5168 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5169 break;
5170 case DM_TABLE_LOAD:
5171 {
5172 void *gspec = argptr;
5173 void *cur_data = host_data;
5174 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5175 int spec_size = thunk_type_size(arg_type, 0);
5176 int i;
5177
5178 for (i = 0; i < host_dm->target_count; i++) {
5179 struct dm_target_spec *spec = cur_data;
5180 uint32_t next;
5181 int slen;
5182
5183 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5184 slen = strlen((char*)gspec + spec_size) + 1;
5185 next = spec->next;
5186 spec->next = sizeof(*spec) + slen;
5187 strcpy((char*)&spec[1], gspec + spec_size);
5188 gspec += next;
5189 cur_data += spec->next;
5190 }
5191 break;
5192 }
5193 default:
5194 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005195 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005196 goto out;
5197 }
5198 unlock_user(argptr, guest_data, 0);
5199
Peter Maydell49ca6f32016-06-06 19:58:14 +01005200 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005201 if (!is_error(ret)) {
5202 guest_data = arg + host_dm->data_start;
5203 guest_data_size = host_dm->data_size - host_dm->data_start;
5204 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5205 switch (ie->host_cmd) {
5206 case DM_REMOVE_ALL:
5207 case DM_DEV_CREATE:
5208 case DM_DEV_REMOVE:
5209 case DM_DEV_RENAME:
5210 case DM_DEV_SUSPEND:
5211 case DM_DEV_STATUS:
5212 case DM_TABLE_LOAD:
5213 case DM_TABLE_CLEAR:
5214 case DM_TARGET_MSG:
5215 case DM_DEV_SET_GEOMETRY:
5216 /* no return data */
5217 break;
5218 case DM_LIST_DEVICES:
5219 {
5220 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5221 uint32_t remaining_data = guest_data_size;
5222 void *cur_data = argptr;
5223 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5224 int nl_size = 12; /* can't use thunk_size due to alignment */
5225
5226 while (1) {
5227 uint32_t next = nl->next;
5228 if (next) {
5229 nl->next = nl_size + (strlen(nl->name) + 1);
5230 }
5231 if (remaining_data < nl->next) {
5232 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5233 break;
5234 }
5235 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5236 strcpy(cur_data + nl_size, nl->name);
5237 cur_data += nl->next;
5238 remaining_data -= nl->next;
5239 if (!next) {
5240 break;
5241 }
5242 nl = (void*)nl + next;
5243 }
5244 break;
5245 }
5246 case DM_DEV_WAIT:
5247 case DM_TABLE_STATUS:
5248 {
5249 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5250 void *cur_data = argptr;
5251 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5252 int spec_size = thunk_type_size(arg_type, 0);
5253 int i;
5254
5255 for (i = 0; i < host_dm->target_count; i++) {
5256 uint32_t next = spec->next;
5257 int slen = strlen((char*)&spec[1]) + 1;
5258 spec->next = (cur_data - argptr) + spec_size + slen;
5259 if (guest_data_size < spec->next) {
5260 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5261 break;
5262 }
5263 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5264 strcpy(cur_data + spec_size, (char*)&spec[1]);
5265 cur_data = argptr + spec->next;
5266 spec = (void*)host_dm + host_dm->data_start + next;
5267 }
5268 break;
5269 }
5270 case DM_TABLE_DEPS:
5271 {
5272 void *hdata = (void*)host_dm + host_dm->data_start;
5273 int count = *(uint32_t*)hdata;
5274 uint64_t *hdev = hdata + 8;
5275 uint64_t *gdev = argptr + 8;
5276 int i;
5277
5278 *(uint32_t*)argptr = tswap32(count);
5279 for (i = 0; i < count; i++) {
5280 *gdev = tswap64(*hdev);
5281 gdev++;
5282 hdev++;
5283 }
5284 break;
5285 }
5286 case DM_LIST_VERSIONS:
5287 {
5288 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5289 uint32_t remaining_data = guest_data_size;
5290 void *cur_data = argptr;
5291 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5292 int vers_size = thunk_type_size(arg_type, 0);
5293
5294 while (1) {
5295 uint32_t next = vers->next;
5296 if (next) {
5297 vers->next = vers_size + (strlen(vers->name) + 1);
5298 }
5299 if (remaining_data < vers->next) {
5300 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5301 break;
5302 }
5303 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5304 strcpy(cur_data + vers_size, vers->name);
5305 cur_data += vers->next;
5306 remaining_data -= vers->next;
5307 if (!next) {
5308 break;
5309 }
5310 vers = (void*)vers + next;
5311 }
5312 break;
5313 }
5314 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005315 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005316 ret = -TARGET_EINVAL;
5317 goto out;
5318 }
5319 unlock_user(argptr, guest_data, guest_data_size);
5320
5321 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5322 if (!argptr) {
5323 ret = -TARGET_EFAULT;
5324 goto out;
5325 }
5326 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5327 unlock_user(argptr, arg, target_size);
5328 }
5329out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005330 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005331 return ret;
5332}
5333
Alexander Grafa59b5e32014-08-22 13:15:50 +02005334static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005335 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005336{
5337 void *argptr;
5338 int target_size;
5339 const argtype *arg_type = ie->arg_type;
5340 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5341 abi_long ret;
5342
5343 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5344 struct blkpg_partition host_part;
5345
5346 /* Read and convert blkpg */
5347 arg_type++;
5348 target_size = thunk_type_size(arg_type, 0);
5349 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5350 if (!argptr) {
5351 ret = -TARGET_EFAULT;
5352 goto out;
5353 }
5354 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5355 unlock_user(argptr, arg, 0);
5356
5357 switch (host_blkpg->op) {
5358 case BLKPG_ADD_PARTITION:
5359 case BLKPG_DEL_PARTITION:
5360 /* payload is struct blkpg_partition */
5361 break;
5362 default:
5363 /* Unknown opcode */
5364 ret = -TARGET_EINVAL;
5365 goto out;
5366 }
5367
5368 /* Read and convert blkpg->data */
5369 arg = (abi_long)(uintptr_t)host_blkpg->data;
5370 target_size = thunk_type_size(part_arg_type, 0);
5371 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5372 if (!argptr) {
5373 ret = -TARGET_EFAULT;
5374 goto out;
5375 }
5376 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5377 unlock_user(argptr, arg, 0);
5378
5379 /* Swizzle the data pointer to our local copy and call! */
5380 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005381 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005382
5383out:
5384 return ret;
5385}
5386
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005387static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005388 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005389{
5390 const argtype *arg_type = ie->arg_type;
5391 const StructEntry *se;
5392 const argtype *field_types;
5393 const int *dst_offsets, *src_offsets;
5394 int target_size;
5395 void *argptr;
5396 abi_ulong *target_rt_dev_ptr;
5397 unsigned long *host_rt_dev_ptr;
5398 abi_long ret;
5399 int i;
5400
5401 assert(ie->access == IOC_W);
5402 assert(*arg_type == TYPE_PTR);
5403 arg_type++;
5404 assert(*arg_type == TYPE_STRUCT);
5405 target_size = thunk_type_size(arg_type, 0);
5406 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5407 if (!argptr) {
5408 return -TARGET_EFAULT;
5409 }
5410 arg_type++;
5411 assert(*arg_type == (int)STRUCT_rtentry);
5412 se = struct_entries + *arg_type++;
5413 assert(se->convert[0] == NULL);
5414 /* convert struct here to be able to catch rt_dev string */
5415 field_types = se->field_types;
5416 dst_offsets = se->field_offsets[THUNK_HOST];
5417 src_offsets = se->field_offsets[THUNK_TARGET];
5418 for (i = 0; i < se->nb_fields; i++) {
5419 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5420 assert(*field_types == TYPE_PTRVOID);
5421 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5422 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5423 if (*target_rt_dev_ptr != 0) {
5424 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5425 tswapal(*target_rt_dev_ptr));
5426 if (!*host_rt_dev_ptr) {
5427 unlock_user(argptr, arg, 0);
5428 return -TARGET_EFAULT;
5429 }
5430 } else {
5431 *host_rt_dev_ptr = 0;
5432 }
5433 field_types++;
5434 continue;
5435 }
5436 field_types = thunk_convert(buf_temp + dst_offsets[i],
5437 argptr + src_offsets[i],
5438 field_types, THUNK_HOST);
5439 }
5440 unlock_user(argptr, arg, 0);
5441
Peter Maydell49ca6f32016-06-06 19:58:14 +01005442 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005443 if (*host_rt_dev_ptr != 0) {
5444 unlock_user((void *)*host_rt_dev_ptr,
5445 *target_rt_dev_ptr, 0);
5446 }
5447 return ret;
5448}
5449
Paul Burtonca56f5b2014-06-22 11:25:47 +01005450static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005451 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005452{
5453 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005454 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005455}
5456
blueswir19f106a72008-10-05 10:52:52 +00005457static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005458#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005459 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5460#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5461 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005462#define IOCTL_IGNORE(cmd) \
5463 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005464#include "ioctls.h"
5465 { 0, 0, },
5466};
5467
pbrook53a59602006-03-25 19:31:22 +00005468/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005469/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005470static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005471{
5472 const IOCTLEntry *ie;
5473 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005474 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005475 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005476 int target_size;
5477 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005478
5479 ie = ioctl_entries;
5480 for(;;) {
5481 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005482 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005483 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005484 }
5485 if (ie->target_cmd == cmd)
5486 break;
5487 ie++;
5488 }
5489 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005490#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005491 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005492#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005493 if (ie->do_ioctl) {
5494 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005495 } else if (!ie->host_cmd) {
5496 /* Some architectures define BSD ioctls in their headers
5497 that are not implemented in Linux. */
5498 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005499 }
5500
bellard31e31b82003-02-18 22:55:36 +00005501 switch(arg_type[0]) {
5502 case TYPE_NULL:
5503 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005504 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005505 break;
5506 case TYPE_PTRVOID:
5507 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005508 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005509 break;
5510 case TYPE_PTR:
5511 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005512 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005513 switch(ie->access) {
5514 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005515 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005516 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005517 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5518 if (!argptr)
5519 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005520 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5521 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005522 }
5523 break;
5524 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005525 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5526 if (!argptr)
5527 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005528 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5529 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005530 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005531 break;
5532 default:
5533 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005534 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5535 if (!argptr)
5536 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005537 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5538 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005539 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005540 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005541 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5542 if (!argptr)
5543 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005544 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5545 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005546 }
5547 break;
5548 }
5549 break;
5550 default:
j_mayer32407102007-09-26 23:01:49 +00005551 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5552 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005553 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005554 break;
5555 }
5556 return ret;
5557}
5558
blueswir1b39bc502008-10-05 10:51:10 +00005559static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005560 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5561 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5562 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5563 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5564 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5565 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5566 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5567 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5568 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5569 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5570 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5571 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5572 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5573 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5574 { 0, 0, 0, 0 }
5575};
5576
blueswir1b39bc502008-10-05 10:51:10 +00005577static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005578 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5579 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5580 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5581 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5582 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5583 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5584 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5585 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5586 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5587 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5588 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5589 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5590 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5591 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5592 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5593 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5594 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5595 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5596 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5597 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5598 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5599 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5600 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5601 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5602 { 0, 0, 0, 0 }
5603};
5604
blueswir1b39bc502008-10-05 10:51:10 +00005605static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005606 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5607 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5608 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5609 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5610 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5611 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5612 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5613 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5614 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5615 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5616 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5617 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5618 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5619 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5620 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5621 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5622 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5623 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5624 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5625 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5626 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5627 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5628 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5629 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5630 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5631 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5632 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5633 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5634 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5635 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5636 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5637 { 0, 0, 0, 0 }
5638};
5639
blueswir1b39bc502008-10-05 10:51:10 +00005640static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005641 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5642 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5643 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5644 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5645 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5646 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5647 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5648 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5649 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5650 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5651 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5652 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5653 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5654 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5655 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5656 { 0, 0, 0, 0 }
5657};
5658
5659static void target_to_host_termios (void *dst, const void *src)
5660{
5661 struct host_termios *host = dst;
5662 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005663
ths5fafdf22007-09-16 21:08:06 +00005664 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005665 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005666 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005667 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005668 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005669 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005670 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005671 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5672 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005673
Arnaud Patard44607122009-04-21 17:39:08 +03005674 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005675 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5676 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005677 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005678 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005679 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005680 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005681 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005682 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005683 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005684 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5685 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005686 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5687 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5688 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5689 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5690 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005691 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005692}
ths3b46e622007-09-17 08:09:54 +00005693
bellard31e31b82003-02-18 22:55:36 +00005694static void host_to_target_termios (void *dst, const void *src)
5695{
5696 struct target_termios *target = dst;
5697 const struct host_termios *host = src;
5698
ths5fafdf22007-09-16 21:08:06 +00005699 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005700 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005701 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005702 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005703 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005704 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005705 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005706 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5707 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005708
Arnaud Patard44607122009-04-21 17:39:08 +03005709 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005710 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5711 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5712 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5713 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5714 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5715 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5716 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5717 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5718 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5719 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5720 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5721 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5722 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5723 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5724 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5725 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5726 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5727}
5728
blueswir18e853dc2008-10-05 10:49:32 +00005729static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005730 .convert = { host_to_target_termios, target_to_host_termios },
5731 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5732 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5733};
5734
bellard5286db72003-06-05 00:57:30 +00005735static bitmask_transtbl mmap_flags_tbl[] = {
5736 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5737 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5738 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5739 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5740 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5741 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5742 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5743 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005744 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5745 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005746 { 0, 0, 0, 0 }
5747};
5748
bellard2ab83ea2003-06-15 19:56:46 +00005749#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005750
5751/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005752static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005753
bellard03acab62007-11-11 14:57:14 +00005754static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005755{
5756 int size;
pbrook53a59602006-03-25 19:31:22 +00005757 void *p;
bellard6dbad632003-03-16 18:05:05 +00005758
5759 if (!ldt_table)
5760 return 0;
5761 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5762 if (size > bytecount)
5763 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005764 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5765 if (!p)
bellard03acab62007-11-11 14:57:14 +00005766 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005767 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005768 memcpy(p, ldt_table, size);
5769 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005770 return size;
5771}
5772
5773/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005774static abi_long write_ldt(CPUX86State *env,
5775 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005776{
5777 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005778 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005779 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005780 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005781 uint32_t *lp, entry_1, entry_2;
5782
5783 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005784 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005785 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005786 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005787 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005788 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005789 ldt_info.limit = tswap32(target_ldt_info->limit);
5790 ldt_info.flags = tswap32(target_ldt_info->flags);
5791 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005792
bellard6dbad632003-03-16 18:05:05 +00005793 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005794 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005795 seg_32bit = ldt_info.flags & 1;
5796 contents = (ldt_info.flags >> 1) & 3;
5797 read_exec_only = (ldt_info.flags >> 3) & 1;
5798 limit_in_pages = (ldt_info.flags >> 4) & 1;
5799 seg_not_present = (ldt_info.flags >> 5) & 1;
5800 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005801#ifdef TARGET_ABI32
5802 lm = 0;
5803#else
5804 lm = (ldt_info.flags >> 7) & 1;
5805#endif
bellard6dbad632003-03-16 18:05:05 +00005806 if (contents == 3) {
5807 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005808 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005809 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005810 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005811 }
5812 /* allocate the LDT */
5813 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005814 env->ldt.base = target_mmap(0,
5815 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5816 PROT_READ|PROT_WRITE,
5817 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5818 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005819 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005820 memset(g2h(env->ldt.base), 0,
5821 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005822 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005823 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005824 }
5825
5826 /* NOTE: same code as Linux kernel */
5827 /* Allow LDTs to be cleared by the user. */
5828 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5829 if (oldmode ||
5830 (contents == 0 &&
5831 read_exec_only == 1 &&
5832 seg_32bit == 0 &&
5833 limit_in_pages == 0 &&
5834 seg_not_present == 1 &&
5835 useable == 0 )) {
5836 entry_1 = 0;
5837 entry_2 = 0;
5838 goto install;
5839 }
5840 }
ths3b46e622007-09-17 08:09:54 +00005841
bellard6dbad632003-03-16 18:05:05 +00005842 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5843 (ldt_info.limit & 0x0ffff);
5844 entry_2 = (ldt_info.base_addr & 0xff000000) |
5845 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5846 (ldt_info.limit & 0xf0000) |
5847 ((read_exec_only ^ 1) << 9) |
5848 (contents << 10) |
5849 ((seg_not_present ^ 1) << 15) |
5850 (seg_32bit << 22) |
5851 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005852 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005853 0x7000;
5854 if (!oldmode)
5855 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005856
bellard6dbad632003-03-16 18:05:05 +00005857 /* Install the new entry ... */
5858install:
5859 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5860 lp[0] = tswap32(entry_1);
5861 lp[1] = tswap32(entry_2);
5862 return 0;
5863}
5864
5865/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005866static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5867 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005868{
bellard03acab62007-11-11 14:57:14 +00005869 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005870
bellard6dbad632003-03-16 18:05:05 +00005871 switch (func) {
5872 case 0:
5873 ret = read_ldt(ptr, bytecount);
5874 break;
5875 case 1:
5876 ret = write_ldt(env, ptr, bytecount, 1);
5877 break;
5878 case 0x11:
5879 ret = write_ldt(env, ptr, bytecount, 0);
5880 break;
bellard03acab62007-11-11 14:57:14 +00005881 default:
5882 ret = -TARGET_ENOSYS;
5883 break;
bellard6dbad632003-03-16 18:05:05 +00005884 }
5885 return ret;
5886}
bellard1b6b0292003-03-22 17:31:38 +00005887
blueswir14583f582008-08-24 10:35:55 +00005888#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005889abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005890{
5891 uint64_t *gdt_table = g2h(env->gdt.base);
5892 struct target_modify_ldt_ldt_s ldt_info;
5893 struct target_modify_ldt_ldt_s *target_ldt_info;
5894 int seg_32bit, contents, read_exec_only, limit_in_pages;
5895 int seg_not_present, useable, lm;
5896 uint32_t *lp, entry_1, entry_2;
5897 int i;
5898
5899 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5900 if (!target_ldt_info)
5901 return -TARGET_EFAULT;
5902 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005903 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005904 ldt_info.limit = tswap32(target_ldt_info->limit);
5905 ldt_info.flags = tswap32(target_ldt_info->flags);
5906 if (ldt_info.entry_number == -1) {
5907 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5908 if (gdt_table[i] == 0) {
5909 ldt_info.entry_number = i;
5910 target_ldt_info->entry_number = tswap32(i);
5911 break;
5912 }
5913 }
5914 }
5915 unlock_user_struct(target_ldt_info, ptr, 1);
5916
5917 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5918 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5919 return -TARGET_EINVAL;
5920 seg_32bit = ldt_info.flags & 1;
5921 contents = (ldt_info.flags >> 1) & 3;
5922 read_exec_only = (ldt_info.flags >> 3) & 1;
5923 limit_in_pages = (ldt_info.flags >> 4) & 1;
5924 seg_not_present = (ldt_info.flags >> 5) & 1;
5925 useable = (ldt_info.flags >> 6) & 1;
5926#ifdef TARGET_ABI32
5927 lm = 0;
5928#else
5929 lm = (ldt_info.flags >> 7) & 1;
5930#endif
5931
5932 if (contents == 3) {
5933 if (seg_not_present == 0)
5934 return -TARGET_EINVAL;
5935 }
5936
5937 /* NOTE: same code as Linux kernel */
5938 /* Allow LDTs to be cleared by the user. */
5939 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5940 if ((contents == 0 &&
5941 read_exec_only == 1 &&
5942 seg_32bit == 0 &&
5943 limit_in_pages == 0 &&
5944 seg_not_present == 1 &&
5945 useable == 0 )) {
5946 entry_1 = 0;
5947 entry_2 = 0;
5948 goto install;
5949 }
5950 }
5951
5952 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5953 (ldt_info.limit & 0x0ffff);
5954 entry_2 = (ldt_info.base_addr & 0xff000000) |
5955 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5956 (ldt_info.limit & 0xf0000) |
5957 ((read_exec_only ^ 1) << 9) |
5958 (contents << 10) |
5959 ((seg_not_present ^ 1) << 15) |
5960 (seg_32bit << 22) |
5961 (limit_in_pages << 23) |
5962 (useable << 20) |
5963 (lm << 21) |
5964 0x7000;
5965
5966 /* Install the new entry ... */
5967install:
5968 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5969 lp[0] = tswap32(entry_1);
5970 lp[1] = tswap32(entry_2);
5971 return 0;
5972}
5973
blueswir18fcd3692008-08-17 20:26:25 +00005974static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005975{
5976 struct target_modify_ldt_ldt_s *target_ldt_info;
5977 uint64_t *gdt_table = g2h(env->gdt.base);
5978 uint32_t base_addr, limit, flags;
5979 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5980 int seg_not_present, useable, lm;
5981 uint32_t *lp, entry_1, entry_2;
5982
5983 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5984 if (!target_ldt_info)
5985 return -TARGET_EFAULT;
5986 idx = tswap32(target_ldt_info->entry_number);
5987 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5988 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5989 unlock_user_struct(target_ldt_info, ptr, 1);
5990 return -TARGET_EINVAL;
5991 }
5992 lp = (uint32_t *)(gdt_table + idx);
5993 entry_1 = tswap32(lp[0]);
5994 entry_2 = tswap32(lp[1]);
5995
5996 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5997 contents = (entry_2 >> 10) & 3;
5998 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5999 seg_32bit = (entry_2 >> 22) & 1;
6000 limit_in_pages = (entry_2 >> 23) & 1;
6001 useable = (entry_2 >> 20) & 1;
6002#ifdef TARGET_ABI32
6003 lm = 0;
6004#else
6005 lm = (entry_2 >> 21) & 1;
6006#endif
6007 flags = (seg_32bit << 0) | (contents << 1) |
6008 (read_exec_only << 3) | (limit_in_pages << 4) |
6009 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6010 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6011 base_addr = (entry_1 >> 16) |
6012 (entry_2 & 0xff000000) |
6013 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006014 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006015 target_ldt_info->limit = tswap32(limit);
6016 target_ldt_info->flags = tswap32(flags);
6017 unlock_user_struct(target_ldt_info, ptr, 1);
6018 return 0;
6019}
blueswir14583f582008-08-24 10:35:55 +00006020#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006021
bellardd2fd1af2007-11-14 18:08:56 +00006022#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006023abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006024{
Juan Quintela1add8692011-06-16 17:37:09 +01006025 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006026 abi_ulong val;
6027 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006028
bellardd2fd1af2007-11-14 18:08:56 +00006029 switch(code) {
6030 case TARGET_ARCH_SET_GS:
6031 case TARGET_ARCH_SET_FS:
6032 if (code == TARGET_ARCH_SET_GS)
6033 idx = R_GS;
6034 else
6035 idx = R_FS;
6036 cpu_x86_load_seg(env, idx, 0);
6037 env->segs[idx].base = addr;
6038 break;
6039 case TARGET_ARCH_GET_GS:
6040 case TARGET_ARCH_GET_FS:
6041 if (code == TARGET_ARCH_GET_GS)
6042 idx = R_GS;
6043 else
6044 idx = R_FS;
6045 val = env->segs[idx].base;
6046 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006047 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006048 break;
6049 default:
6050 ret = -TARGET_EINVAL;
6051 break;
6052 }
Juan Quintela1add8692011-06-16 17:37:09 +01006053 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006054}
6055#endif
6056
bellard2ab83ea2003-06-15 19:56:46 +00006057#endif /* defined(TARGET_I386) */
6058
Riku Voipio05098a92011-03-04 15:27:29 +02006059#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006060
pbrookd865bab2008-06-07 22:12:17 +00006061
6062static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6063typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006064 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006065 pthread_mutex_t mutex;
6066 pthread_cond_t cond;
6067 pthread_t thread;
6068 uint32_t tid;
6069 abi_ulong child_tidptr;
6070 abi_ulong parent_tidptr;
6071 sigset_t sigmask;
6072} new_thread_info;
6073
6074static void *clone_func(void *arg)
6075{
6076 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006077 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006078 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006079 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006080
Emilio G. Cota70903762015-08-23 20:23:41 -04006081 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006082 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006083 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006084 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006085 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006086 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01006087 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006088 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006089 if (info->child_tidptr)
6090 put_user_u32(info->tid, info->child_tidptr);
6091 if (info->parent_tidptr)
6092 put_user_u32(info->tid, info->parent_tidptr);
6093 /* Enable signals. */
6094 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6095 /* Signal to the parent that we're ready. */
6096 pthread_mutex_lock(&info->mutex);
6097 pthread_cond_broadcast(&info->cond);
6098 pthread_mutex_unlock(&info->mutex);
6099 /* Wait until the parent has finshed initializing the tls state. */
6100 pthread_mutex_lock(&clone_lock);
6101 pthread_mutex_unlock(&clone_lock);
6102 cpu_loop(env);
6103 /* never exits */
6104 return NULL;
6105}
bellard1b6b0292003-03-22 17:31:38 +00006106
ths0da46a62007-10-20 20:23:07 +00006107/* do_fork() Must return host values and target errnos (unlike most
6108 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006109static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006110 abi_ulong parent_tidptr, target_ulong newtls,
6111 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006112{
Andreas Färber0429a972013-08-26 18:14:44 +02006113 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006114 int ret;
bellard5cd43932003-03-29 16:54:36 +00006115 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006116 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006117 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006118 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006119
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006120 flags &= ~CLONE_IGNORED_FLAGS;
6121
balrog436d1242008-09-21 02:39:45 +00006122 /* Emulate vfork() with fork() */
6123 if (flags & CLONE_VFORK)
6124 flags &= ~(CLONE_VFORK | CLONE_VM);
6125
bellard1b6b0292003-03-22 17:31:38 +00006126 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006127 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006128 new_thread_info info;
6129 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006130
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006131 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6132 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6133 return -TARGET_EINVAL;
6134 }
6135
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006136 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006137 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00006138 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006139 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006140 /* Init regs that differ from the parent. */
6141 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006142 new_cpu = ENV_GET_CPU(new_env);
6143 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006144 ts->bprm = parent_ts->bprm;
6145 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006146 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006147
Peter Maydell7cfbd382016-08-02 18:41:26 +01006148 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006149 ts->child_tidptr = child_tidptr;
6150 }
6151
Peter Maydell7cfbd382016-08-02 18:41:26 +01006152 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006153 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006154 }
pbrookd865bab2008-06-07 22:12:17 +00006155
6156 /* Grab a mutex so that thread setup appears atomic. */
6157 pthread_mutex_lock(&clone_lock);
6158
6159 memset(&info, 0, sizeof(info));
6160 pthread_mutex_init(&info.mutex, NULL);
6161 pthread_mutex_lock(&info.mutex);
6162 pthread_cond_init(&info.cond, NULL);
6163 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006164 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006165 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006166 }
6167 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006168 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006169 }
pbrookd865bab2008-06-07 22:12:17 +00006170
6171 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006172 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6173 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006174 /* It is not safe to deliver signals until the child has finished
6175 initializing, so temporarily block all signals. */
6176 sigfillset(&sigmask);
6177 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6178
Alex Bennéeb67cb682016-10-05 11:13:04 -07006179 /* If this is our first additional thread, we need to ensure we
6180 * generate code for parallel execution and flush old translations.
6181 */
6182 if (!parallel_cpus) {
6183 parallel_cpus = true;
6184 tb_flush(cpu);
6185 }
6186
pbrookd865bab2008-06-07 22:12:17 +00006187 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006188 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006189
6190 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6191 pthread_attr_destroy(&attr);
6192 if (ret == 0) {
6193 /* Wait for the child to initialize. */
6194 pthread_cond_wait(&info.cond, &info.mutex);
6195 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006196 } else {
6197 ret = -1;
6198 }
6199 pthread_mutex_unlock(&info.mutex);
6200 pthread_cond_destroy(&info.cond);
6201 pthread_mutex_destroy(&info.mutex);
6202 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006203 } else {
6204 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006205 if (flags & CLONE_INVALID_FORK_FLAGS) {
6206 return -TARGET_EINVAL;
6207 }
6208
6209 /* We can't support custom termination signals */
6210 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006211 return -TARGET_EINVAL;
6212 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006213
6214 if (block_signals()) {
6215 return -TARGET_ERESTARTSYS;
6216 }
6217
pbrookd865bab2008-06-07 22:12:17 +00006218 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006219 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006220 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006221 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02006222 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00006223 cpu_clone_regs(env, newsp);
6224 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006225 /* There is a race condition here. The parent process could
6226 theoretically read the TID in the child process before the child
6227 tid is set. This would require using either ptrace
6228 (not implemented) or having *_tidptr to point at a shared memory
6229 mapping. We can't repeat the spinlock hack used above because
6230 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006231 if (flags & CLONE_CHILD_SETTID)
6232 put_user_u32(gettid(), child_tidptr);
6233 if (flags & CLONE_PARENT_SETTID)
6234 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006235 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006236 if (flags & CLONE_SETTLS)
6237 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006238 if (flags & CLONE_CHILD_CLEARTID)
6239 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006240 } else {
6241 fork_end(0);
6242 }
bellard1b6b0292003-03-22 17:31:38 +00006243 }
6244 return ret;
6245}
6246
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006247/* warning : doesn't handle linux specific flags... */
6248static int target_to_host_fcntl_cmd(int cmd)
6249{
6250 switch(cmd) {
6251 case TARGET_F_DUPFD:
6252 case TARGET_F_GETFD:
6253 case TARGET_F_SETFD:
6254 case TARGET_F_GETFL:
6255 case TARGET_F_SETFL:
6256 return cmd;
6257 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006258 return F_GETLK64;
6259 case TARGET_F_SETLK:
6260 return F_SETLK64;
6261 case TARGET_F_SETLKW:
6262 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006263 case TARGET_F_GETOWN:
6264 return F_GETOWN;
6265 case TARGET_F_SETOWN:
6266 return F_SETOWN;
6267 case TARGET_F_GETSIG:
6268 return F_GETSIG;
6269 case TARGET_F_SETSIG:
6270 return F_SETSIG;
6271#if TARGET_ABI_BITS == 32
6272 case TARGET_F_GETLK64:
6273 return F_GETLK64;
6274 case TARGET_F_SETLK64:
6275 return F_SETLK64;
6276 case TARGET_F_SETLKW64:
6277 return F_SETLKW64;
6278#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006279 case TARGET_F_SETLEASE:
6280 return F_SETLEASE;
6281 case TARGET_F_GETLEASE:
6282 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006283#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006284 case TARGET_F_DUPFD_CLOEXEC:
6285 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006286#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006287 case TARGET_F_NOTIFY:
6288 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006289#ifdef F_GETOWN_EX
6290 case TARGET_F_GETOWN_EX:
6291 return F_GETOWN_EX;
6292#endif
6293#ifdef F_SETOWN_EX
6294 case TARGET_F_SETOWN_EX:
6295 return F_SETOWN_EX;
6296#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006297#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006298 case TARGET_F_SETPIPE_SZ:
6299 return F_SETPIPE_SZ;
6300 case TARGET_F_GETPIPE_SZ:
6301 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006302#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006303 default:
6304 return -TARGET_EINVAL;
6305 }
6306 return -TARGET_EINVAL;
6307}
6308
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006309#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6310static const bitmask_transtbl flock_tbl[] = {
6311 TRANSTBL_CONVERT(F_RDLCK),
6312 TRANSTBL_CONVERT(F_WRLCK),
6313 TRANSTBL_CONVERT(F_UNLCK),
6314 TRANSTBL_CONVERT(F_EXLCK),
6315 TRANSTBL_CONVERT(F_SHLCK),
6316 { 0, 0, 0, 0 }
6317};
6318
Peter Maydell213d3e92016-06-13 11:22:05 +01006319static inline abi_long copy_from_user_flock(struct flock64 *fl,
6320 abi_ulong target_flock_addr)
6321{
6322 struct target_flock *target_fl;
6323 short l_type;
6324
6325 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6326 return -TARGET_EFAULT;
6327 }
6328
6329 __get_user(l_type, &target_fl->l_type);
6330 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6331 __get_user(fl->l_whence, &target_fl->l_whence);
6332 __get_user(fl->l_start, &target_fl->l_start);
6333 __get_user(fl->l_len, &target_fl->l_len);
6334 __get_user(fl->l_pid, &target_fl->l_pid);
6335 unlock_user_struct(target_fl, target_flock_addr, 0);
6336 return 0;
6337}
6338
6339static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6340 const struct flock64 *fl)
6341{
6342 struct target_flock *target_fl;
6343 short l_type;
6344
6345 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6346 return -TARGET_EFAULT;
6347 }
6348
6349 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6350 __put_user(l_type, &target_fl->l_type);
6351 __put_user(fl->l_whence, &target_fl->l_whence);
6352 __put_user(fl->l_start, &target_fl->l_start);
6353 __put_user(fl->l_len, &target_fl->l_len);
6354 __put_user(fl->l_pid, &target_fl->l_pid);
6355 unlock_user_struct(target_fl, target_flock_addr, 1);
6356 return 0;
6357}
6358
6359typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6360typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6361
6362#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6363static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6364 abi_ulong target_flock_addr)
6365{
6366 struct target_eabi_flock64 *target_fl;
6367 short l_type;
6368
6369 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6370 return -TARGET_EFAULT;
6371 }
6372
6373 __get_user(l_type, &target_fl->l_type);
6374 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6375 __get_user(fl->l_whence, &target_fl->l_whence);
6376 __get_user(fl->l_start, &target_fl->l_start);
6377 __get_user(fl->l_len, &target_fl->l_len);
6378 __get_user(fl->l_pid, &target_fl->l_pid);
6379 unlock_user_struct(target_fl, target_flock_addr, 0);
6380 return 0;
6381}
6382
6383static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6384 const struct flock64 *fl)
6385{
6386 struct target_eabi_flock64 *target_fl;
6387 short l_type;
6388
6389 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6390 return -TARGET_EFAULT;
6391 }
6392
6393 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6394 __put_user(l_type, &target_fl->l_type);
6395 __put_user(fl->l_whence, &target_fl->l_whence);
6396 __put_user(fl->l_start, &target_fl->l_start);
6397 __put_user(fl->l_len, &target_fl->l_len);
6398 __put_user(fl->l_pid, &target_fl->l_pid);
6399 unlock_user_struct(target_fl, target_flock_addr, 1);
6400 return 0;
6401}
6402#endif
6403
6404static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6405 abi_ulong target_flock_addr)
6406{
6407 struct target_flock64 *target_fl;
6408 short l_type;
6409
6410 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6411 return -TARGET_EFAULT;
6412 }
6413
6414 __get_user(l_type, &target_fl->l_type);
6415 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6416 __get_user(fl->l_whence, &target_fl->l_whence);
6417 __get_user(fl->l_start, &target_fl->l_start);
6418 __get_user(fl->l_len, &target_fl->l_len);
6419 __get_user(fl->l_pid, &target_fl->l_pid);
6420 unlock_user_struct(target_fl, target_flock_addr, 0);
6421 return 0;
6422}
6423
6424static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6425 const struct flock64 *fl)
6426{
6427 struct target_flock64 *target_fl;
6428 short l_type;
6429
6430 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6431 return -TARGET_EFAULT;
6432 }
6433
6434 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6435 __put_user(l_type, &target_fl->l_type);
6436 __put_user(fl->l_whence, &target_fl->l_whence);
6437 __put_user(fl->l_start, &target_fl->l_start);
6438 __put_user(fl->l_len, &target_fl->l_len);
6439 __put_user(fl->l_pid, &target_fl->l_pid);
6440 unlock_user_struct(target_fl, target_flock_addr, 1);
6441 return 0;
6442}
6443
blueswir1992f48a2007-10-14 16:27:31 +00006444static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006445{
ths43f238d2007-01-05 20:55:49 +00006446 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006447#ifdef F_GETOWN_EX
6448 struct f_owner_ex fox;
6449 struct target_f_owner_ex *target_fox;
6450#endif
blueswir1992f48a2007-10-14 16:27:31 +00006451 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006452 int host_cmd = target_to_host_fcntl_cmd(cmd);
6453
6454 if (host_cmd == -TARGET_EINVAL)
6455 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006456
bellard7775e9e2003-05-14 22:46:48 +00006457 switch(cmd) {
6458 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006459 ret = copy_from_user_flock(&fl64, arg);
6460 if (ret) {
6461 return ret;
6462 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006463 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006464 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006465 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006466 }
6467 break;
ths3b46e622007-09-17 08:09:54 +00006468
bellard7775e9e2003-05-14 22:46:48 +00006469 case TARGET_F_SETLK:
6470 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006471 ret = copy_from_user_flock(&fl64, arg);
6472 if (ret) {
6473 return ret;
6474 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006475 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006476 break;
ths3b46e622007-09-17 08:09:54 +00006477
bellard7775e9e2003-05-14 22:46:48 +00006478 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006479 ret = copy_from_user_flock64(&fl64, arg);
6480 if (ret) {
6481 return ret;
6482 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006483 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006484 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006485 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006486 }
bellard9ee1fa22007-11-11 15:11:19 +00006487 break;
bellard7775e9e2003-05-14 22:46:48 +00006488 case TARGET_F_SETLK64:
6489 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006490 ret = copy_from_user_flock64(&fl64, arg);
6491 if (ret) {
6492 return ret;
6493 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006494 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006495 break;
6496
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006497 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006498 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006499 if (ret >= 0) {
6500 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6501 }
bellardffa65c32004-01-04 23:57:22 +00006502 break;
6503
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006504 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006505 ret = get_errno(safe_fcntl(fd, host_cmd,
6506 target_to_host_bitmask(arg,
6507 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006508 break;
6509
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006510#ifdef F_GETOWN_EX
6511 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006512 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006513 if (ret >= 0) {
6514 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6515 return -TARGET_EFAULT;
6516 target_fox->type = tswap32(fox.type);
6517 target_fox->pid = tswap32(fox.pid);
6518 unlock_user_struct(target_fox, arg, 1);
6519 }
6520 break;
6521#endif
6522
6523#ifdef F_SETOWN_EX
6524 case TARGET_F_SETOWN_EX:
6525 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6526 return -TARGET_EFAULT;
6527 fox.type = tswap32(target_fox->type);
6528 fox.pid = tswap32(target_fox->pid);
6529 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006530 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006531 break;
6532#endif
6533
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006534 case TARGET_F_SETOWN:
6535 case TARGET_F_GETOWN:
6536 case TARGET_F_SETSIG:
6537 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006538 case TARGET_F_SETLEASE:
6539 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006540 case TARGET_F_SETPIPE_SZ:
6541 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006542 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006543 break;
6544
bellard7775e9e2003-05-14 22:46:48 +00006545 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006546 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006547 break;
6548 }
6549 return ret;
6550}
6551
bellard67867302003-11-23 17:05:30 +00006552#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006553
bellard67867302003-11-23 17:05:30 +00006554static inline int high2lowuid(int uid)
6555{
6556 if (uid > 65535)
6557 return 65534;
6558 else
6559 return uid;
6560}
6561
6562static inline int high2lowgid(int gid)
6563{
6564 if (gid > 65535)
6565 return 65534;
6566 else
6567 return gid;
6568}
6569
6570static inline int low2highuid(int uid)
6571{
6572 if ((int16_t)uid == -1)
6573 return -1;
6574 else
6575 return uid;
6576}
6577
6578static inline int low2highgid(int gid)
6579{
6580 if ((int16_t)gid == -1)
6581 return -1;
6582 else
6583 return gid;
6584}
Riku Voipio0c866a72011-04-18 15:23:06 +03006585static inline int tswapid(int id)
6586{
6587 return tswap16(id);
6588}
Peter Maydell76ca3102014-03-02 19:36:41 +00006589
6590#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6591
Riku Voipio0c866a72011-04-18 15:23:06 +03006592#else /* !USE_UID16 */
6593static inline int high2lowuid(int uid)
6594{
6595 return uid;
6596}
6597static inline int high2lowgid(int gid)
6598{
6599 return gid;
6600}
6601static inline int low2highuid(int uid)
6602{
6603 return uid;
6604}
6605static inline int low2highgid(int gid)
6606{
6607 return gid;
6608}
6609static inline int tswapid(int id)
6610{
6611 return tswap32(id);
6612}
Peter Maydell76ca3102014-03-02 19:36:41 +00006613
6614#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6615
bellard67867302003-11-23 17:05:30 +00006616#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006617
Peter Maydellfd6f7792016-03-01 16:33:02 +00006618/* We must do direct syscalls for setting UID/GID, because we want to
6619 * implement the Linux system call semantics of "change only for this thread",
6620 * not the libc/POSIX semantics of "change for all threads in process".
6621 * (See http://ewontfix.com/17/ for more details.)
6622 * We use the 32-bit version of the syscalls if present; if it is not
6623 * then either the host architecture supports 32-bit UIDs natively with
6624 * the standard syscall, or the 16-bit UID is the best we can do.
6625 */
6626#ifdef __NR_setuid32
6627#define __NR_sys_setuid __NR_setuid32
6628#else
6629#define __NR_sys_setuid __NR_setuid
6630#endif
6631#ifdef __NR_setgid32
6632#define __NR_sys_setgid __NR_setgid32
6633#else
6634#define __NR_sys_setgid __NR_setgid
6635#endif
6636#ifdef __NR_setresuid32
6637#define __NR_sys_setresuid __NR_setresuid32
6638#else
6639#define __NR_sys_setresuid __NR_setresuid
6640#endif
6641#ifdef __NR_setresgid32
6642#define __NR_sys_setresgid __NR_setresgid32
6643#else
6644#define __NR_sys_setresgid __NR_setresgid
6645#endif
6646
6647_syscall1(int, sys_setuid, uid_t, uid)
6648_syscall1(int, sys_setgid, gid_t, gid)
6649_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6650_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6651
bellard31e31b82003-02-18 22:55:36 +00006652void syscall_init(void)
6653{
bellard2ab83ea2003-06-15 19:56:46 +00006654 IOCTLEntry *ie;
6655 const argtype *arg_type;
6656 int size;
thsb92c47c2007-11-01 00:07:38 +00006657 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006658
Alexander Graf8be656b2015-05-06 23:47:32 +02006659 thunk_init(STRUCT_MAX);
6660
Blue Swirl001faf32009-05-13 17:53:17 +00006661#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006662#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006663#include "syscall_types.h"
6664#undef STRUCT
6665#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006666
Peter Maydelldd6e9572012-07-23 08:07:22 +00006667 /* Build target_to_host_errno_table[] table from
6668 * host_to_target_errno_table[]. */
6669 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6670 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6671 }
6672
bellard2ab83ea2003-06-15 19:56:46 +00006673 /* we patch the ioctl size if necessary. We rely on the fact that
6674 no ioctl has all the bits at '1' in the size field */
6675 ie = ioctl_entries;
6676 while (ie->target_cmd != 0) {
6677 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6678 TARGET_IOC_SIZEMASK) {
6679 arg_type = ie->arg_type;
6680 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006681 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006682 ie->target_cmd);
6683 exit(1);
6684 }
6685 arg_type++;
6686 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006687 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006688 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6689 (size << TARGET_IOC_SIZESHIFT);
6690 }
thsb92c47c2007-11-01 00:07:38 +00006691
bellard2ab83ea2003-06-15 19:56:46 +00006692 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006693#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6694 (defined(__x86_64__) && defined(TARGET_X86_64))
6695 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6696 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6697 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006698 }
6699#endif
6700 ie++;
6701 }
bellard31e31b82003-02-18 22:55:36 +00006702}
bellardc573ff62004-01-04 15:51:36 +00006703
blueswir1992f48a2007-10-14 16:27:31 +00006704#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006705static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6706{
thsaf325d32008-06-10 15:29:15 +00006707#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006708 return ((uint64_t)word0 << 32) | word1;
6709#else
6710 return ((uint64_t)word1 << 32) | word0;
6711#endif
6712}
blueswir1992f48a2007-10-14 16:27:31 +00006713#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006714static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6715{
6716 return word0;
6717}
blueswir1992f48a2007-10-14 16:27:31 +00006718#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006719
6720#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006721static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6722 abi_long arg2,
6723 abi_long arg3,
6724 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006725{
Riku Voipio48e515d2011-07-12 15:40:51 +03006726 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006727 arg2 = arg3;
6728 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006729 }
pbrookce4defa2006-02-09 16:49:55 +00006730 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6731}
6732#endif
6733
6734#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006735static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6736 abi_long arg2,
6737 abi_long arg3,
6738 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006739{
Riku Voipio48e515d2011-07-12 15:40:51 +03006740 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006741 arg2 = arg3;
6742 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006743 }
pbrookce4defa2006-02-09 16:49:55 +00006744 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6745}
6746#endif
6747
bellard579a97f2007-11-11 14:26:47 +00006748static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6749 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006750{
6751 struct target_timespec *target_ts;
6752
bellard579a97f2007-11-11 14:26:47 +00006753 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6754 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006755 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6756 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006757 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006758 return 0;
pbrook53a59602006-03-25 19:31:22 +00006759}
6760
bellard579a97f2007-11-11 14:26:47 +00006761static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6762 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006763{
6764 struct target_timespec *target_ts;
6765
bellard579a97f2007-11-11 14:26:47 +00006766 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6767 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006768 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6769 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006770 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006771 return 0;
pbrook53a59602006-03-25 19:31:22 +00006772}
6773
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006774static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6775 abi_ulong target_addr)
6776{
6777 struct target_itimerspec *target_itspec;
6778
6779 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6780 return -TARGET_EFAULT;
6781 }
6782
6783 host_itspec->it_interval.tv_sec =
6784 tswapal(target_itspec->it_interval.tv_sec);
6785 host_itspec->it_interval.tv_nsec =
6786 tswapal(target_itspec->it_interval.tv_nsec);
6787 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6788 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6789
6790 unlock_user_struct(target_itspec, target_addr, 1);
6791 return 0;
6792}
6793
6794static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6795 struct itimerspec *host_its)
6796{
6797 struct target_itimerspec *target_itspec;
6798
6799 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6800 return -TARGET_EFAULT;
6801 }
6802
6803 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6804 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6805
6806 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6807 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6808
6809 unlock_user_struct(target_itspec, target_addr, 0);
6810 return 0;
6811}
6812
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02006813static inline abi_long target_to_host_timex(struct timex *host_tx,
6814 abi_long target_addr)
6815{
6816 struct target_timex *target_tx;
6817
6818 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
6819 return -TARGET_EFAULT;
6820 }
6821
6822 __get_user(host_tx->modes, &target_tx->modes);
6823 __get_user(host_tx->offset, &target_tx->offset);
6824 __get_user(host_tx->freq, &target_tx->freq);
6825 __get_user(host_tx->maxerror, &target_tx->maxerror);
6826 __get_user(host_tx->esterror, &target_tx->esterror);
6827 __get_user(host_tx->status, &target_tx->status);
6828 __get_user(host_tx->constant, &target_tx->constant);
6829 __get_user(host_tx->precision, &target_tx->precision);
6830 __get_user(host_tx->tolerance, &target_tx->tolerance);
6831 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6832 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
6833 __get_user(host_tx->tick, &target_tx->tick);
6834 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
6835 __get_user(host_tx->jitter, &target_tx->jitter);
6836 __get_user(host_tx->shift, &target_tx->shift);
6837 __get_user(host_tx->stabil, &target_tx->stabil);
6838 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
6839 __get_user(host_tx->calcnt, &target_tx->calcnt);
6840 __get_user(host_tx->errcnt, &target_tx->errcnt);
6841 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
6842 __get_user(host_tx->tai, &target_tx->tai);
6843
6844 unlock_user_struct(target_tx, target_addr, 0);
6845 return 0;
6846}
6847
6848static inline abi_long host_to_target_timex(abi_long target_addr,
6849 struct timex *host_tx)
6850{
6851 struct target_timex *target_tx;
6852
6853 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
6854 return -TARGET_EFAULT;
6855 }
6856
6857 __put_user(host_tx->modes, &target_tx->modes);
6858 __put_user(host_tx->offset, &target_tx->offset);
6859 __put_user(host_tx->freq, &target_tx->freq);
6860 __put_user(host_tx->maxerror, &target_tx->maxerror);
6861 __put_user(host_tx->esterror, &target_tx->esterror);
6862 __put_user(host_tx->status, &target_tx->status);
6863 __put_user(host_tx->constant, &target_tx->constant);
6864 __put_user(host_tx->precision, &target_tx->precision);
6865 __put_user(host_tx->tolerance, &target_tx->tolerance);
6866 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6867 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
6868 __put_user(host_tx->tick, &target_tx->tick);
6869 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
6870 __put_user(host_tx->jitter, &target_tx->jitter);
6871 __put_user(host_tx->shift, &target_tx->shift);
6872 __put_user(host_tx->stabil, &target_tx->stabil);
6873 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
6874 __put_user(host_tx->calcnt, &target_tx->calcnt);
6875 __put_user(host_tx->errcnt, &target_tx->errcnt);
6876 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
6877 __put_user(host_tx->tai, &target_tx->tai);
6878
6879 unlock_user_struct(target_tx, target_addr, 1);
6880 return 0;
6881}
6882
6883
Peter Maydellc0659762014-08-09 15:42:32 +01006884static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
6885 abi_ulong target_addr)
6886{
6887 struct target_sigevent *target_sevp;
6888
6889 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6890 return -TARGET_EFAULT;
6891 }
6892
6893 /* This union is awkward on 64 bit systems because it has a 32 bit
6894 * integer and a pointer in it; we follow the conversion approach
6895 * used for handling sigval types in signal.c so the guest should get
6896 * the correct value back even if we did a 64 bit byteswap and it's
6897 * using the 32 bit integer.
6898 */
6899 host_sevp->sigev_value.sival_ptr =
6900 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6901 host_sevp->sigev_signo =
6902 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6903 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6904 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6905
6906 unlock_user_struct(target_sevp, target_addr, 1);
6907 return 0;
6908}
6909
Tom Musta6f6a4032014-08-12 13:53:42 -05006910#if defined(TARGET_NR_mlockall)
6911static inline int target_to_host_mlockall_arg(int arg)
6912{
6913 int result = 0;
6914
6915 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6916 result |= MCL_CURRENT;
6917 }
6918 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6919 result |= MCL_FUTURE;
6920 }
6921 return result;
6922}
6923#endif
6924
balrog6a24a772008-09-20 02:23:36 +00006925static inline abi_long host_to_target_stat64(void *cpu_env,
6926 abi_ulong target_addr,
6927 struct stat *host_st)
6928{
Alexander Graf09701192013-09-03 20:12:15 +01006929#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006930 if (((CPUARMState *)cpu_env)->eabi) {
6931 struct target_eabi_stat64 *target_st;
6932
6933 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6934 return -TARGET_EFAULT;
6935 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6936 __put_user(host_st->st_dev, &target_st->st_dev);
6937 __put_user(host_st->st_ino, &target_st->st_ino);
6938#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6939 __put_user(host_st->st_ino, &target_st->__st_ino);
6940#endif
6941 __put_user(host_st->st_mode, &target_st->st_mode);
6942 __put_user(host_st->st_nlink, &target_st->st_nlink);
6943 __put_user(host_st->st_uid, &target_st->st_uid);
6944 __put_user(host_st->st_gid, &target_st->st_gid);
6945 __put_user(host_st->st_rdev, &target_st->st_rdev);
6946 __put_user(host_st->st_size, &target_st->st_size);
6947 __put_user(host_st->st_blksize, &target_st->st_blksize);
6948 __put_user(host_st->st_blocks, &target_st->st_blocks);
6949 __put_user(host_st->st_atime, &target_st->target_st_atime);
6950 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6951 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6952 unlock_user_struct(target_st, target_addr, 1);
6953 } else
6954#endif
6955 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006956#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006957 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006958#else
6959 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006960#endif
balrog6a24a772008-09-20 02:23:36 +00006961
6962 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6963 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006964 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006965 __put_user(host_st->st_dev, &target_st->st_dev);
6966 __put_user(host_st->st_ino, &target_st->st_ino);
6967#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6968 __put_user(host_st->st_ino, &target_st->__st_ino);
6969#endif
6970 __put_user(host_st->st_mode, &target_st->st_mode);
6971 __put_user(host_st->st_nlink, &target_st->st_nlink);
6972 __put_user(host_st->st_uid, &target_st->st_uid);
6973 __put_user(host_st->st_gid, &target_st->st_gid);
6974 __put_user(host_st->st_rdev, &target_st->st_rdev);
6975 /* XXX: better use of kernel struct */
6976 __put_user(host_st->st_size, &target_st->st_size);
6977 __put_user(host_st->st_blksize, &target_st->st_blksize);
6978 __put_user(host_st->st_blocks, &target_st->st_blocks);
6979 __put_user(host_st->st_atime, &target_st->target_st_atime);
6980 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6981 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6982 unlock_user_struct(target_st, target_addr, 1);
6983 }
6984
6985 return 0;
6986}
balrog6a24a772008-09-20 02:23:36 +00006987
pbrookbd0c5662008-05-29 14:34:11 +00006988/* ??? Using host futex calls even when target atomic operations
6989 are not really atomic probably breaks things. However implementing
6990 futexes locally would make futexes shared between multiple processes
6991 tricky. However they're probably useless because guest atomic
6992 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006993static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6994 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006995{
6996 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006997 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006998
6999 /* ??? We assume FUTEX_* constants are the same on both host
7000 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007001#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007002 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007003#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007004 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007005#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007006 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007007 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007008 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007009 if (timeout) {
7010 pts = &ts;
7011 target_to_host_timespec(pts, timeout);
7012 } else {
7013 pts = NULL;
7014 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007015 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007016 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007017 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007018 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007019 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007020 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007021 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007022 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007023 case FUTEX_WAKE_OP:
7024 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7025 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7026 But the prototype takes a `struct timespec *'; insert casts
7027 to satisfy the compiler. We do not need to tswap TIMEOUT
7028 since it's not compared to guest memory. */
7029 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007030 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7031 g2h(uaddr2),
7032 (base_op == FUTEX_CMP_REQUEUE
7033 ? tswap32(val3)
7034 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007035 default:
7036 return -TARGET_ENOSYS;
7037 }
7038}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007039#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7040static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7041 abi_long handle, abi_long mount_id,
7042 abi_long flags)
7043{
7044 struct file_handle *target_fh;
7045 struct file_handle *fh;
7046 int mid = 0;
7047 abi_long ret;
7048 char *name;
7049 unsigned int size, total_size;
7050
7051 if (get_user_s32(size, handle)) {
7052 return -TARGET_EFAULT;
7053 }
7054
7055 name = lock_user_string(pathname);
7056 if (!name) {
7057 return -TARGET_EFAULT;
7058 }
7059
7060 total_size = sizeof(struct file_handle) + size;
7061 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7062 if (!target_fh) {
7063 unlock_user(name, pathname, 0);
7064 return -TARGET_EFAULT;
7065 }
7066
7067 fh = g_malloc0(total_size);
7068 fh->handle_bytes = size;
7069
7070 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7071 unlock_user(name, pathname, 0);
7072
7073 /* man name_to_handle_at(2):
7074 * Other than the use of the handle_bytes field, the caller should treat
7075 * the file_handle structure as an opaque data type
7076 */
7077
7078 memcpy(target_fh, fh, total_size);
7079 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7080 target_fh->handle_type = tswap32(fh->handle_type);
7081 g_free(fh);
7082 unlock_user(target_fh, handle, total_size);
7083
7084 if (put_user_s32(mid, mount_id)) {
7085 return -TARGET_EFAULT;
7086 }
7087
7088 return ret;
7089
7090}
7091#endif
7092
7093#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7094static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7095 abi_long flags)
7096{
7097 struct file_handle *target_fh;
7098 struct file_handle *fh;
7099 unsigned int size, total_size;
7100 abi_long ret;
7101
7102 if (get_user_s32(size, handle)) {
7103 return -TARGET_EFAULT;
7104 }
7105
7106 total_size = sizeof(struct file_handle) + size;
7107 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7108 if (!target_fh) {
7109 return -TARGET_EFAULT;
7110 }
7111
Thomas Huthe9d49d52015-10-09 17:56:38 +02007112 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007113 fh->handle_bytes = size;
7114 fh->handle_type = tswap32(target_fh->handle_type);
7115
7116 ret = get_errno(open_by_handle_at(mount_fd, fh,
7117 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7118
7119 g_free(fh);
7120
7121 unlock_user(target_fh, handle, total_size);
7122
7123 return ret;
7124}
7125#endif
pbrookbd0c5662008-05-29 14:34:11 +00007126
Laurent Viviere36800c2015-10-02 14:48:09 +02007127#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7128
7129/* signalfd siginfo conversion */
7130
7131static void
7132host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7133 const struct signalfd_siginfo *info)
7134{
7135 int sig = host_to_target_signal(info->ssi_signo);
7136
7137 /* linux/signalfd.h defines a ssi_addr_lsb
7138 * not defined in sys/signalfd.h but used by some kernels
7139 */
7140
7141#ifdef BUS_MCEERR_AO
7142 if (tinfo->ssi_signo == SIGBUS &&
7143 (tinfo->ssi_code == BUS_MCEERR_AR ||
7144 tinfo->ssi_code == BUS_MCEERR_AO)) {
7145 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7146 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7147 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7148 }
7149#endif
7150
7151 tinfo->ssi_signo = tswap32(sig);
7152 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7153 tinfo->ssi_code = tswap32(info->ssi_code);
7154 tinfo->ssi_pid = tswap32(info->ssi_pid);
7155 tinfo->ssi_uid = tswap32(info->ssi_uid);
7156 tinfo->ssi_fd = tswap32(info->ssi_fd);
7157 tinfo->ssi_tid = tswap32(info->ssi_tid);
7158 tinfo->ssi_band = tswap32(info->ssi_band);
7159 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7160 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7161 tinfo->ssi_status = tswap32(info->ssi_status);
7162 tinfo->ssi_int = tswap32(info->ssi_int);
7163 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7164 tinfo->ssi_utime = tswap64(info->ssi_utime);
7165 tinfo->ssi_stime = tswap64(info->ssi_stime);
7166 tinfo->ssi_addr = tswap64(info->ssi_addr);
7167}
7168
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007169static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007170{
7171 int i;
7172
7173 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7174 host_to_target_signalfd_siginfo(buf + i, buf + i);
7175 }
7176
7177 return len;
7178}
7179
7180static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007181 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007182};
7183
7184static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7185{
7186 int host_flags;
7187 target_sigset_t *target_mask;
7188 sigset_t host_mask;
7189 abi_long ret;
7190
7191 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7192 return -TARGET_EINVAL;
7193 }
7194 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7195 return -TARGET_EFAULT;
7196 }
7197
7198 target_to_host_sigset(&host_mask, target_mask);
7199
7200 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7201
7202 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7203 if (ret >= 0) {
7204 fd_trans_register(ret, &target_signalfd_trans);
7205 }
7206
7207 unlock_user_struct(target_mask, mask, 0);
7208
7209 return ret;
7210}
7211#endif
7212
pbrook1d9d8b52009-04-16 15:17:02 +00007213/* Map host to target signal numbers for the wait family of syscalls.
7214 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007215int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007216{
7217 if (WIFSIGNALED(status)) {
7218 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7219 }
7220 if (WIFSTOPPED(status)) {
7221 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7222 | (status & 0xff);
7223 }
7224 return status;
7225}
7226
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007227static int open_self_cmdline(void *cpu_env, int fd)
7228{
7229 int fd_orig = -1;
7230 bool word_skipped = false;
7231
7232 fd_orig = open("/proc/self/cmdline", O_RDONLY);
7233 if (fd_orig < 0) {
7234 return fd_orig;
7235 }
7236
7237 while (true) {
7238 ssize_t nb_read;
7239 char buf[128];
7240 char *cp_buf = buf;
7241
7242 nb_read = read(fd_orig, buf, sizeof(buf));
7243 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007244 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007245 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007246 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007247 return -1;
7248 } else if (nb_read == 0) {
7249 break;
7250 }
7251
7252 if (!word_skipped) {
7253 /* Skip the first string, which is the path to qemu-*-static
7254 instead of the actual command. */
Peter Maydellba4b3f62016-07-12 13:02:19 +01007255 cp_buf = memchr(buf, 0, nb_read);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007256 if (cp_buf) {
7257 /* Null byte found, skip one string */
7258 cp_buf++;
7259 nb_read -= cp_buf - buf;
7260 word_skipped = true;
7261 }
7262 }
7263
7264 if (word_skipped) {
7265 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007266 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08007267 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007268 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007269 return -1;
7270 }
7271 }
7272 }
7273
7274 return close(fd_orig);
7275}
7276
Alexander Graf36c08d42011-11-02 20:23:24 +01007277static int open_self_maps(void *cpu_env, int fd)
7278{
Andreas Färber0429a972013-08-26 18:14:44 +02007279 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7280 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007281 FILE *fp;
7282 char *line = NULL;
7283 size_t len = 0;
7284 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007285
Alexander Graf1a49ef22012-05-01 16:30:28 +01007286 fp = fopen("/proc/self/maps", "r");
7287 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007288 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007289 }
7290
7291 while ((read = getline(&line, &len, fp)) != -1) {
7292 int fields, dev_maj, dev_min, inode;
7293 uint64_t min, max, offset;
7294 char flag_r, flag_w, flag_x, flag_p;
7295 char path[512] = "";
7296 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7297 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7298 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7299
7300 if ((fields < 10) || (fields > 11)) {
7301 continue;
7302 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007303 if (h2g_valid(min)) {
7304 int flags = page_get_flags(h2g(min));
7305 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
7306 if (page_check_range(h2g(min), max - min, flags) == -1) {
7307 continue;
7308 }
7309 if (h2g(min) == ts->info->stack_limit) {
7310 pstrcpy(path, sizeof(path), " [stack]");
7311 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007312 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007313 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007314 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007315 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007316 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007317 }
7318 }
7319
7320 free(line);
7321 fclose(fp);
7322
Alexander Graf36c08d42011-11-02 20:23:24 +01007323 return 0;
7324}
7325
Alexander Graf480b8e72011-11-02 20:23:25 +01007326static int open_self_stat(void *cpu_env, int fd)
7327{
Andreas Färber0429a972013-08-26 18:14:44 +02007328 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7329 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007330 abi_ulong start_stack = ts->info->start_stack;
7331 int i;
7332
7333 for (i = 0; i < 44; i++) {
7334 char buf[128];
7335 int len;
7336 uint64_t val = 0;
7337
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007338 if (i == 0) {
7339 /* pid */
7340 val = getpid();
7341 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7342 } else if (i == 1) {
7343 /* app name */
7344 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7345 } else if (i == 27) {
7346 /* stack bottom */
7347 val = start_stack;
7348 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7349 } else {
7350 /* for the rest, there is MasterCard */
7351 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007352 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007353
Alexander Graf480b8e72011-11-02 20:23:25 +01007354 len = strlen(buf);
7355 if (write(fd, buf, len) != len) {
7356 return -1;
7357 }
7358 }
7359
7360 return 0;
7361}
7362
Alexander Graf257450e2011-11-02 20:23:26 +01007363static int open_self_auxv(void *cpu_env, int fd)
7364{
Andreas Färber0429a972013-08-26 18:14:44 +02007365 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7366 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007367 abi_ulong auxv = ts->info->saved_auxv;
7368 abi_ulong len = ts->info->auxv_len;
7369 char *ptr;
7370
7371 /*
7372 * Auxiliary vector is stored in target process stack.
7373 * read in whole auxv vector and copy it to file
7374 */
7375 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7376 if (ptr != NULL) {
7377 while (len > 0) {
7378 ssize_t r;
7379 r = write(fd, ptr, len);
7380 if (r <= 0) {
7381 break;
7382 }
7383 len -= r;
7384 ptr += r;
7385 }
7386 lseek(fd, 0, SEEK_SET);
7387 unlock_user(ptr, auxv, len);
7388 }
7389
7390 return 0;
7391}
7392
Andreas Schwab463d8e72013-07-02 14:04:12 +01007393static int is_proc_myself(const char *filename, const char *entry)
7394{
7395 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7396 filename += strlen("/proc/");
7397 if (!strncmp(filename, "self/", strlen("self/"))) {
7398 filename += strlen("self/");
7399 } else if (*filename >= '1' && *filename <= '9') {
7400 char myself[80];
7401 snprintf(myself, sizeof(myself), "%d/", getpid());
7402 if (!strncmp(filename, myself, strlen(myself))) {
7403 filename += strlen(myself);
7404 } else {
7405 return 0;
7406 }
7407 } else {
7408 return 0;
7409 }
7410 if (!strcmp(filename, entry)) {
7411 return 1;
7412 }
7413 }
7414 return 0;
7415}
7416
Laurent Vivierde6b9932013-08-30 01:46:40 +02007417#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7418static int is_proc(const char *filename, const char *entry)
7419{
7420 return strcmp(filename, entry) == 0;
7421}
7422
7423static int open_net_route(void *cpu_env, int fd)
7424{
7425 FILE *fp;
7426 char *line = NULL;
7427 size_t len = 0;
7428 ssize_t read;
7429
7430 fp = fopen("/proc/net/route", "r");
7431 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007432 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007433 }
7434
7435 /* read header */
7436
7437 read = getline(&line, &len, fp);
7438 dprintf(fd, "%s", line);
7439
7440 /* read routes */
7441
7442 while ((read = getline(&line, &len, fp)) != -1) {
7443 char iface[16];
7444 uint32_t dest, gw, mask;
7445 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7446 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7447 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7448 &mask, &mtu, &window, &irtt);
7449 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7450 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7451 metric, tswap32(mask), mtu, window, irtt);
7452 }
7453
7454 free(line);
7455 fclose(fp);
7456
7457 return 0;
7458}
7459#endif
7460
Riku Voipio0b2effd2014-08-06 10:36:37 +03007461static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007462{
7463 struct fake_open {
7464 const char *filename;
7465 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007466 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007467 };
7468 const struct fake_open *fake_open;
7469 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007470 { "maps", open_self_maps, is_proc_myself },
7471 { "stat", open_self_stat, is_proc_myself },
7472 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007473 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007474#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7475 { "/proc/net/route", open_net_route, is_proc },
7476#endif
7477 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007478 };
7479
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007480 if (is_proc_myself(pathname, "exe")) {
7481 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007482 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007483 }
7484
Alexander Graf3be14d02011-11-02 20:23:23 +01007485 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007486 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007487 break;
7488 }
7489 }
7490
7491 if (fake_open->filename) {
7492 const char *tmpdir;
7493 char filename[PATH_MAX];
7494 int fd, r;
7495
7496 /* create temporary file to map stat to */
7497 tmpdir = getenv("TMPDIR");
7498 if (!tmpdir)
7499 tmpdir = "/tmp";
7500 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7501 fd = mkstemp(filename);
7502 if (fd < 0) {
7503 return fd;
7504 }
7505 unlink(filename);
7506
7507 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007508 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007509 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007510 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007511 return r;
7512 }
7513 lseek(fd, 0, SEEK_SET);
7514
7515 return fd;
7516 }
7517
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007518 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007519}
7520
Alexander Grafaecc8862014-11-10 21:33:03 +01007521#define TIMER_MAGIC 0x0caf0000
7522#define TIMER_MAGIC_MASK 0xffff0000
7523
7524/* Convert QEMU provided timer ID back to internal 16bit index format */
7525static target_timer_t get_timer_id(abi_long arg)
7526{
7527 target_timer_t timerid = arg;
7528
7529 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7530 return -TARGET_EINVAL;
7531 }
7532
7533 timerid &= 0xffff;
7534
7535 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7536 return -TARGET_EINVAL;
7537 }
7538
7539 return timerid;
7540}
7541
ths0da46a62007-10-20 20:23:07 +00007542/* do_syscall() should always have a single exit point at the end so
7543 that actions, such as logging of syscall results, can be performed.
7544 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007545abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7546 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007547 abi_long arg5, abi_long arg6, abi_long arg7,
7548 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007549{
Andreas Färber182735e2013-05-29 22:29:20 +02007550 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007551 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007552 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007553 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007554 void *p;
ths3b46e622007-09-17 08:09:54 +00007555
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007556#if defined(DEBUG_ERESTARTSYS)
7557 /* Debug-only code for exercising the syscall-restart code paths
7558 * in the per-architecture cpu main loops: restart every syscall
7559 * the guest makes once before letting it through.
7560 */
7561 {
7562 static int flag;
7563
7564 flag = !flag;
7565 if (flag) {
7566 return -TARGET_ERESTARTSYS;
7567 }
7568 }
7569#endif
7570
bellard72f03902003-02-18 23:33:18 +00007571#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007572 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007573#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007574 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007575 if(do_strace)
7576 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7577
bellard31e31b82003-02-18 22:55:36 +00007578 switch(num) {
7579 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007580 /* In old applications this may be used to implement _exit(2).
7581 However in threaded applictions it is used for thread termination,
7582 and _exit_group is used for application termination.
7583 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007584
7585 if (block_signals()) {
7586 ret = -TARGET_ERESTARTSYS;
7587 break;
7588 }
7589
Alex Bennéedd1f6342016-09-30 22:31:01 +01007590 cpu_list_lock();
7591
Andreas Färberbdc44642013-06-24 23:50:24 +02007592 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007593 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007594
Andreas Färber9b056fc2013-06-24 23:53:10 +02007595 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007596 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007597
Andreas Färber9b056fc2013-06-24 23:53:10 +02007598 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007599
Andreas Färber0429a972013-08-26 18:14:44 +02007600 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007601 if (ts->child_tidptr) {
7602 put_user_u32(0, ts->child_tidptr);
7603 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7604 NULL, NULL, 0);
7605 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007606 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007607 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007608 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007609 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007610 pthread_exit(NULL);
7611 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007612
7613 cpu_list_unlock();
Juan Quintela9788c9c2009-07-27 16:13:02 +02007614#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007615 _mcleanup();
7616#endif
bellarde9009672005-04-26 20:42:36 +00007617 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007618 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007619 ret = 0; /* avoid warning */
7620 break;
7621 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007622 if (arg3 == 0)
7623 ret = 0;
7624 else {
7625 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7626 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007627 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007628 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007629 fd_trans_host_to_target_data(arg1)) {
7630 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007631 }
aurel3238d840e2009-01-30 19:48:17 +00007632 unlock_user(p, arg2, ret);
7633 }
bellard31e31b82003-02-18 22:55:36 +00007634 break;
7635 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007636 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7637 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007638 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00007639 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007640 break;
Chen Gang704eff62015-08-21 05:37:33 +08007641#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007642 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007643 if (!(p = lock_user_string(arg1)))
7644 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007645 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7646 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7647 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007648 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007649 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007650 break;
Chen Gang704eff62015-08-21 05:37:33 +08007651#endif
ths82424832007-09-24 09:21:55 +00007652 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007653 if (!(p = lock_user_string(arg2)))
7654 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007655 ret = get_errno(do_openat(cpu_env, arg1, p,
7656 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7657 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007658 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007659 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007660 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007661#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7662 case TARGET_NR_name_to_handle_at:
7663 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7664 break;
7665#endif
7666#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7667 case TARGET_NR_open_by_handle_at:
7668 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007669 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007670 break;
7671#endif
bellard31e31b82003-02-18 22:55:36 +00007672 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007673 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007674 ret = get_errno(close(arg1));
7675 break;
7676 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007677 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007678 break;
Chen Gang704eff62015-08-21 05:37:33 +08007679#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007680 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00007681 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007682 break;
Chen Gang704eff62015-08-21 05:37:33 +08007683#endif
thse5febef2007-04-01 18:31:35 +00007684#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007685 case TARGET_NR_waitpid:
7686 {
pbrook53a59602006-03-25 19:31:22 +00007687 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007688 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007689 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007690 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007691 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007692 }
7693 break;
thse5febef2007-04-01 18:31:35 +00007694#endif
pbrookf0cbb612008-05-30 18:20:05 +00007695#ifdef TARGET_NR_waitid
7696 case TARGET_NR_waitid:
7697 {
7698 siginfo_t info;
7699 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007700 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007701 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007702 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00007703 goto efault;
7704 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007705 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007706 }
7707 }
7708 break;
7709#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007710#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007711 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007712 if (!(p = lock_user_string(arg1)))
7713 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007714 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007715 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007716 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007717 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007718#endif
Chen Gang704eff62015-08-21 05:37:33 +08007719#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007720 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007721 {
7722 void * p2;
7723 p = lock_user_string(arg1);
7724 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007725 if (!p || !p2)
7726 ret = -TARGET_EFAULT;
7727 else
7728 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007729 unlock_user(p2, arg2, 0);
7730 unlock_user(p, arg1, 0);
7731 }
bellard31e31b82003-02-18 22:55:36 +00007732 break;
Chen Gang704eff62015-08-21 05:37:33 +08007733#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007734#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007735 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007736 {
7737 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007738 if (!arg2 || !arg4)
7739 goto efault;
ths64f0ce42007-09-24 09:25:06 +00007740 p = lock_user_string(arg2);
7741 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007742 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007743 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007744 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007745 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007746 unlock_user(p, arg2, 0);
7747 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007748 }
7749 break;
7750#endif
Chen Gang704eff62015-08-21 05:37:33 +08007751#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007752 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007753 if (!(p = lock_user_string(arg1)))
7754 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007755 ret = get_errno(unlink(p));
7756 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007757 break;
Chen Gang704eff62015-08-21 05:37:33 +08007758#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007759#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007760 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007761 if (!(p = lock_user_string(arg2)))
7762 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007763 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007764 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007765 break;
balrogb7d35e62007-12-12 00:40:24 +00007766#endif
bellard31e31b82003-02-18 22:55:36 +00007767 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007768 {
7769 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007770 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007771 abi_ulong gp;
7772 abi_ulong guest_argp;
7773 abi_ulong guest_envp;
7774 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007775 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007776 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007777
bellardf7341ff2003-03-30 21:00:25 +00007778 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007779 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007780 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007781 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007782 goto efault;
ths03aa1972007-12-02 06:28:08 +00007783 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007784 break;
bellard7854b052003-03-29 17:22:23 +00007785 argc++;
bellard2f619692007-11-16 10:46:05 +00007786 }
bellardf7341ff2003-03-30 21:00:25 +00007787 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007788 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007789 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007790 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007791 goto efault;
ths03aa1972007-12-02 06:28:08 +00007792 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007793 break;
bellard7854b052003-03-29 17:22:23 +00007794 envc++;
bellard2f619692007-11-16 10:46:05 +00007795 }
bellard7854b052003-03-29 17:22:23 +00007796
bellardf7341ff2003-03-30 21:00:25 +00007797 argp = alloca((argc + 1) * sizeof(void *));
7798 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00007799
pbrookda94d262008-05-30 18:24:00 +00007800 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007801 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007802 if (get_user_ual(addr, gp))
7803 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007804 if (!addr)
7805 break;
bellard2f619692007-11-16 10:46:05 +00007806 if (!(*q = lock_user_string(addr)))
7807 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007808 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007809 }
bellardf7341ff2003-03-30 21:00:25 +00007810 *q = NULL;
7811
pbrookda94d262008-05-30 18:24:00 +00007812 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007813 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007814 if (get_user_ual(addr, gp))
7815 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007816 if (!addr)
7817 break;
bellard2f619692007-11-16 10:46:05 +00007818 if (!(*q = lock_user_string(addr)))
7819 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007820 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007821 }
bellardf7341ff2003-03-30 21:00:25 +00007822 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007823
bellard2f619692007-11-16 10:46:05 +00007824 if (!(p = lock_user_string(arg1)))
7825 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007826 /* Although execve() is not an interruptible syscall it is
7827 * a special case where we must use the safe_syscall wrapper:
7828 * if we allow a signal to happen before we make the host
7829 * syscall then we will 'lose' it, because at the point of
7830 * execve the process leaves QEMU's control. So we use the
7831 * safe syscall wrapper to ensure that we either take the
7832 * signal as a guest signal, or else it does not happen
7833 * before the execve completes and makes it the other
7834 * program's problem.
7835 */
7836 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007837 unlock_user(p, arg1, 0);
7838
bellard2f619692007-11-16 10:46:05 +00007839 goto execve_end;
7840
7841 execve_efault:
7842 ret = -TARGET_EFAULT;
7843
7844 execve_end:
pbrook53a59602006-03-25 19:31:22 +00007845 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007846 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007847 if (get_user_ual(addr, gp)
7848 || !addr)
7849 break;
pbrook53a59602006-03-25 19:31:22 +00007850 unlock_user(*q, addr, 0);
7851 }
7852 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00007853 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007854 if (get_user_ual(addr, gp)
7855 || !addr)
7856 break;
pbrook53a59602006-03-25 19:31:22 +00007857 unlock_user(*q, addr, 0);
7858 }
bellard7854b052003-03-29 17:22:23 +00007859 }
bellard31e31b82003-02-18 22:55:36 +00007860 break;
7861 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00007862 if (!(p = lock_user_string(arg1)))
7863 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007864 ret = get_errno(chdir(p));
7865 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007866 break;
bellarda315a142005-01-30 22:59:18 +00007867#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00007868 case TARGET_NR_time:
7869 {
pbrook53a59602006-03-25 19:31:22 +00007870 time_t host_time;
7871 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00007872 if (!is_error(ret)
7873 && arg1
7874 && put_user_sal(host_time, arg1))
7875 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007876 }
7877 break;
bellarda315a142005-01-30 22:59:18 +00007878#endif
Chen Gang704eff62015-08-21 05:37:33 +08007879#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00007880 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00007881 if (!(p = lock_user_string(arg1)))
7882 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007883 ret = get_errno(mknod(p, arg2, arg3));
7884 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007885 break;
Chen Gang704eff62015-08-21 05:37:33 +08007886#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007887#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00007888 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00007889 if (!(p = lock_user_string(arg2)))
7890 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007891 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007892 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007893 break;
7894#endif
Chen Gang704eff62015-08-21 05:37:33 +08007895#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007896 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007897 if (!(p = lock_user_string(arg1)))
7898 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007899 ret = get_errno(chmod(p, arg2));
7900 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007901 break;
Chen Gang704eff62015-08-21 05:37:33 +08007902#endif
bellardebc05482003-09-30 21:08:41 +00007903#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007904 case TARGET_NR_break:
7905 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007906#endif
7907#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007908 case TARGET_NR_oldstat:
7909 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007910#endif
bellard31e31b82003-02-18 22:55:36 +00007911 case TARGET_NR_lseek:
7912 ret = get_errno(lseek(arg1, arg2, arg3));
7913 break;
Richard Henderson92317332010-05-03 10:07:53 -07007914#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7915 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007916 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007917 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007918 ret = get_errno(getpid());
7919 break;
Richard Henderson92317332010-05-03 10:07:53 -07007920#endif
7921#ifdef TARGET_NR_getpid
7922 case TARGET_NR_getpid:
7923 ret = get_errno(getpid());
7924 break;
7925#endif
bellard31e31b82003-02-18 22:55:36 +00007926 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007927 {
7928 /* need to look at the data field */
7929 void *p2, *p3;
7930
7931 if (arg1) {
7932 p = lock_user_string(arg1);
7933 if (!p) {
7934 goto efault;
7935 }
7936 } else {
7937 p = NULL;
7938 }
7939
7940 p2 = lock_user_string(arg2);
7941 if (!p2) {
7942 if (arg1) {
7943 unlock_user(p, arg1, 0);
7944 }
7945 goto efault;
7946 }
7947
7948 if (arg3) {
7949 p3 = lock_user_string(arg3);
7950 if (!p3) {
7951 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007952 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007953 }
7954 unlock_user(p2, arg2, 0);
7955 goto efault;
7956 }
7957 } else {
7958 p3 = NULL;
7959 }
7960
7961 /* FIXME - arg5 should be locked, but it isn't clear how to
7962 * do that since it's not guaranteed to be a NULL-terminated
7963 * string.
7964 */
7965 if (!arg5) {
7966 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7967 } else {
7968 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7969 }
7970 ret = get_errno(ret);
7971
7972 if (arg1) {
7973 unlock_user(p, arg1, 0);
7974 }
7975 unlock_user(p2, arg2, 0);
7976 if (arg3) {
7977 unlock_user(p3, arg3, 0);
7978 }
7979 }
7980 break;
thse5febef2007-04-01 18:31:35 +00007981#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007982 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007983 if (!(p = lock_user_string(arg1)))
7984 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007985 ret = get_errno(umount(p));
7986 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007987 break;
thse5febef2007-04-01 18:31:35 +00007988#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007989#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007990 case TARGET_NR_stime:
7991 {
pbrook53a59602006-03-25 19:31:22 +00007992 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007993 if (get_user_sal(host_time, arg1))
7994 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007995 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007996 }
7997 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007998#endif
bellard31e31b82003-02-18 22:55:36 +00007999 case TARGET_NR_ptrace:
8000 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008001#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008002 case TARGET_NR_alarm:
8003 ret = alarm(arg1);
8004 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008005#endif
bellardebc05482003-09-30 21:08:41 +00008006#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008007 case TARGET_NR_oldfstat:
8008 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008009#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008010#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008011 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008012 if (!block_signals()) {
8013 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8014 }
8015 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008016 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008017#endif
thse5febef2007-04-01 18:31:35 +00008018#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008019 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008020 {
pbrook53a59602006-03-25 19:31:22 +00008021 struct utimbuf tbuf, *host_tbuf;
8022 struct target_utimbuf *target_tbuf;
8023 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008024 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8025 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008026 tbuf.actime = tswapal(target_tbuf->actime);
8027 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008028 unlock_user_struct(target_tbuf, arg2, 0);
8029 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008030 } else {
pbrook53a59602006-03-25 19:31:22 +00008031 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008032 }
bellard579a97f2007-11-11 14:26:47 +00008033 if (!(p = lock_user_string(arg1)))
8034 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008035 ret = get_errno(utime(p, host_tbuf));
8036 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008037 }
8038 break;
thse5febef2007-04-01 18:31:35 +00008039#endif
Chen Gang704eff62015-08-21 05:37:33 +08008040#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008041 case TARGET_NR_utimes:
8042 {
bellard978a66f2004-12-06 22:58:05 +00008043 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008044 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008045 if (copy_from_user_timeval(&tv[0], arg2)
8046 || copy_from_user_timeval(&tv[1],
8047 arg2 + sizeof(struct target_timeval)))
8048 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008049 tvp = tv;
8050 } else {
8051 tvp = NULL;
8052 }
bellard579a97f2007-11-11 14:26:47 +00008053 if (!(p = lock_user_string(arg1)))
8054 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008055 ret = get_errno(utimes(p, tvp));
8056 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008057 }
8058 break;
Chen Gang704eff62015-08-21 05:37:33 +08008059#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008060#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008061 case TARGET_NR_futimesat:
8062 {
8063 struct timeval *tvp, tv[2];
8064 if (arg3) {
8065 if (copy_from_user_timeval(&tv[0], arg3)
8066 || copy_from_user_timeval(&tv[1],
8067 arg3 + sizeof(struct target_timeval)))
8068 goto efault;
8069 tvp = tv;
8070 } else {
8071 tvp = NULL;
8072 }
8073 if (!(p = lock_user_string(arg2)))
8074 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008075 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008076 unlock_user(p, arg2, 0);
8077 }
8078 break;
8079#endif
bellardebc05482003-09-30 21:08:41 +00008080#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008081 case TARGET_NR_stty:
8082 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008083#endif
8084#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008085 case TARGET_NR_gtty:
8086 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008087#endif
Chen Gang704eff62015-08-21 05:37:33 +08008088#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008089 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008090 if (!(p = lock_user_string(arg1)))
8091 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008092 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008093 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008094 break;
Chen Gang704eff62015-08-21 05:37:33 +08008095#endif
ths92a34c12007-09-24 09:27:49 +00008096#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8097 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008098 if (!(p = lock_user_string(arg2)))
8099 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008100 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008101 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008102 break;
8103#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008104#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008105 case TARGET_NR_nice:
8106 ret = get_errno(nice(arg1));
8107 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008108#endif
bellardebc05482003-09-30 21:08:41 +00008109#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008110 case TARGET_NR_ftime:
8111 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008112#endif
bellard31e31b82003-02-18 22:55:36 +00008113 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008114 sync();
8115 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008116 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008117#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8118 case TARGET_NR_syncfs:
8119 ret = get_errno(syncfs(arg1));
8120 break;
8121#endif
bellard31e31b82003-02-18 22:55:36 +00008122 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008123 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008124 break;
Chen Gang704eff62015-08-21 05:37:33 +08008125#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008126 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008127 {
8128 void *p2;
8129 p = lock_user_string(arg1);
8130 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008131 if (!p || !p2)
8132 ret = -TARGET_EFAULT;
8133 else
8134 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008135 unlock_user(p2, arg2, 0);
8136 unlock_user(p, arg1, 0);
8137 }
bellard31e31b82003-02-18 22:55:36 +00008138 break;
Chen Gang704eff62015-08-21 05:37:33 +08008139#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008140#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008141 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008142 {
bellard579a97f2007-11-11 14:26:47 +00008143 void *p2;
ths722183f2007-09-24 09:24:37 +00008144 p = lock_user_string(arg2);
8145 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008146 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008147 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008148 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008149 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008150 unlock_user(p2, arg4, 0);
8151 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008152 }
8153 break;
8154#endif
Chen Gang704eff62015-08-21 05:37:33 +08008155#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008156 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008157 if (!(p = lock_user_string(arg1)))
8158 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008159 ret = get_errno(mkdir(p, arg2));
8160 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008161 break;
Chen Gang704eff62015-08-21 05:37:33 +08008162#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008163#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008164 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008165 if (!(p = lock_user_string(arg2)))
8166 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008167 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008168 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008169 break;
8170#endif
Chen Gang704eff62015-08-21 05:37:33 +08008171#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008172 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008173 if (!(p = lock_user_string(arg1)))
8174 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008175 ret = get_errno(rmdir(p));
8176 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008177 break;
Chen Gang704eff62015-08-21 05:37:33 +08008178#endif
bellard31e31b82003-02-18 22:55:36 +00008179 case TARGET_NR_dup:
8180 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008181 if (ret >= 0) {
8182 fd_trans_dup(arg1, ret);
8183 }
bellard31e31b82003-02-18 22:55:36 +00008184 break;
Chen Gang704eff62015-08-21 05:37:33 +08008185#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008186 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008187 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008188 break;
Chen Gang704eff62015-08-21 05:37:33 +08008189#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008190#ifdef TARGET_NR_pipe2
8191 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008192 ret = do_pipe(cpu_env, arg1,
8193 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008194 break;
8195#endif
bellard31e31b82003-02-18 22:55:36 +00008196 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008197 {
pbrook53a59602006-03-25 19:31:22 +00008198 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008199 struct tms tms;
8200 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008201 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008202 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8203 if (!tmsp)
8204 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008205 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8206 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8207 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8208 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008209 }
bellardc596ed12003-07-13 17:32:31 +00008210 if (!is_error(ret))
8211 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008212 }
8213 break;
bellardebc05482003-09-30 21:08:41 +00008214#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008215 case TARGET_NR_prof:
8216 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008217#endif
thse5febef2007-04-01 18:31:35 +00008218#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008219 case TARGET_NR_signal:
8220 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008221#endif
bellard31e31b82003-02-18 22:55:36 +00008222 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008223 if (arg1 == 0) {
8224 ret = get_errno(acct(NULL));
8225 } else {
8226 if (!(p = lock_user_string(arg1)))
8227 goto efault;
8228 ret = get_errno(acct(path(p)));
8229 unlock_user(p, arg1, 0);
8230 }
pbrook24836682006-04-16 14:14:53 +00008231 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008232#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008233 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008234 if (!(p = lock_user_string(arg1)))
8235 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008236 ret = get_errno(umount2(p, arg2));
8237 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008238 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008239#endif
bellardebc05482003-09-30 21:08:41 +00008240#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008241 case TARGET_NR_lock:
8242 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008243#endif
bellard31e31b82003-02-18 22:55:36 +00008244 case TARGET_NR_ioctl:
8245 ret = do_ioctl(arg1, arg2, arg3);
8246 break;
8247 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008248 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008249 break;
bellardebc05482003-09-30 21:08:41 +00008250#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008251 case TARGET_NR_mpx:
8252 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008253#endif
bellard31e31b82003-02-18 22:55:36 +00008254 case TARGET_NR_setpgid:
8255 ret = get_errno(setpgid(arg1, arg2));
8256 break;
bellardebc05482003-09-30 21:08:41 +00008257#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008258 case TARGET_NR_ulimit:
8259 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008260#endif
8261#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008262 case TARGET_NR_oldolduname:
8263 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008264#endif
bellard31e31b82003-02-18 22:55:36 +00008265 case TARGET_NR_umask:
8266 ret = get_errno(umask(arg1));
8267 break;
8268 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008269 if (!(p = lock_user_string(arg1)))
8270 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008271 ret = get_errno(chroot(p));
8272 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008273 break;
Chen Gang704eff62015-08-21 05:37:33 +08008274#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008275 case TARGET_NR_ustat:
8276 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008277#endif
8278#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008279 case TARGET_NR_dup2:
8280 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008281 if (ret >= 0) {
8282 fd_trans_dup(arg1, arg2);
8283 }
bellard31e31b82003-02-18 22:55:36 +00008284 break;
Chen Gang704eff62015-08-21 05:37:33 +08008285#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008286#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8287 case TARGET_NR_dup3:
8288 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008289 if (ret >= 0) {
8290 fd_trans_dup(arg1, arg2);
8291 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008292 break;
8293#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008294#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008295 case TARGET_NR_getppid:
8296 ret = get_errno(getppid());
8297 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008298#endif
Chen Gang704eff62015-08-21 05:37:33 +08008299#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008300 case TARGET_NR_getpgrp:
8301 ret = get_errno(getpgrp());
8302 break;
Chen Gang704eff62015-08-21 05:37:33 +08008303#endif
bellard31e31b82003-02-18 22:55:36 +00008304 case TARGET_NR_setsid:
8305 ret = get_errno(setsid());
8306 break;
thse5febef2007-04-01 18:31:35 +00008307#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008308 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008309 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008310#if defined(TARGET_ALPHA)
8311 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008312 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008313 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008314 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8315 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008316 act._sa_handler = old_act->_sa_handler;
8317 target_siginitset(&act.sa_mask, old_act->sa_mask);
8318 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008319 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008320 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008321 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008322 }
8323 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008324 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008325 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8326 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008327 old_act->_sa_handler = oact._sa_handler;
8328 old_act->sa_mask = oact.sa_mask.sig[0];
8329 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008330 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008331 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008332#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008333 struct target_sigaction act, oact, *pact, *old_act;
8334
8335 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008336 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8337 goto efault;
bellard106ec872006-06-27 21:08:10 +00008338 act._sa_handler = old_act->_sa_handler;
8339 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8340 act.sa_flags = old_act->sa_flags;
8341 unlock_user_struct(old_act, arg2, 0);
8342 pact = &act;
8343 } else {
8344 pact = NULL;
8345 }
8346
8347 ret = get_errno(do_sigaction(arg1, pact, &oact));
8348
8349 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008350 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8351 goto efault;
bellard106ec872006-06-27 21:08:10 +00008352 old_act->_sa_handler = oact._sa_handler;
8353 old_act->sa_flags = oact.sa_flags;
8354 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8355 old_act->sa_mask.sig[1] = 0;
8356 old_act->sa_mask.sig[2] = 0;
8357 old_act->sa_mask.sig[3] = 0;
8358 unlock_user_struct(old_act, arg3, 1);
8359 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008360#else
8361 struct target_old_sigaction *old_act;
8362 struct target_sigaction act, oact, *pact;
8363 if (arg2) {
8364 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8365 goto efault;
8366 act._sa_handler = old_act->_sa_handler;
8367 target_siginitset(&act.sa_mask, old_act->sa_mask);
8368 act.sa_flags = old_act->sa_flags;
8369 act.sa_restorer = old_act->sa_restorer;
8370 unlock_user_struct(old_act, arg2, 0);
8371 pact = &act;
8372 } else {
8373 pact = NULL;
8374 }
8375 ret = get_errno(do_sigaction(arg1, pact, &oact));
8376 if (!is_error(ret) && arg3) {
8377 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8378 goto efault;
8379 old_act->_sa_handler = oact._sa_handler;
8380 old_act->sa_mask = oact.sa_mask.sig[0];
8381 old_act->sa_flags = oact.sa_flags;
8382 old_act->sa_restorer = oact.sa_restorer;
8383 unlock_user_struct(old_act, arg3, 1);
8384 }
ths388bb212007-05-13 13:58:00 +00008385#endif
bellard31e31b82003-02-18 22:55:36 +00008386 }
8387 break;
thse5febef2007-04-01 18:31:35 +00008388#endif
bellard66fb9762003-03-23 01:06:05 +00008389 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008390 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008391#if defined(TARGET_ALPHA)
8392 struct target_sigaction act, oact, *pact = 0;
8393 struct target_rt_sigaction *rt_act;
Peter Maydellc8157012016-06-30 14:23:24 +01008394
8395 if (arg4 != sizeof(target_sigset_t)) {
8396 ret = -TARGET_EINVAL;
8397 break;
8398 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008399 if (arg2) {
8400 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8401 goto efault;
8402 act._sa_handler = rt_act->_sa_handler;
8403 act.sa_mask = rt_act->sa_mask;
8404 act.sa_flags = rt_act->sa_flags;
8405 act.sa_restorer = arg5;
8406 unlock_user_struct(rt_act, arg2, 0);
8407 pact = &act;
8408 }
8409 ret = get_errno(do_sigaction(arg1, pact, &oact));
8410 if (!is_error(ret) && arg3) {
8411 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8412 goto efault;
8413 rt_act->_sa_handler = oact._sa_handler;
8414 rt_act->sa_mask = oact.sa_mask;
8415 rt_act->sa_flags = oact.sa_flags;
8416 unlock_user_struct(rt_act, arg3, 1);
8417 }
8418#else
pbrook53a59602006-03-25 19:31:22 +00008419 struct target_sigaction *act;
8420 struct target_sigaction *oact;
8421
Peter Maydellc8157012016-06-30 14:23:24 +01008422 if (arg4 != sizeof(target_sigset_t)) {
8423 ret = -TARGET_EINVAL;
8424 break;
8425 }
bellard579a97f2007-11-11 14:26:47 +00008426 if (arg2) {
8427 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
8428 goto efault;
8429 } else
pbrook53a59602006-03-25 19:31:22 +00008430 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00008431 if (arg3) {
8432 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8433 ret = -TARGET_EFAULT;
8434 goto rt_sigaction_fail;
8435 }
8436 } else
pbrook53a59602006-03-25 19:31:22 +00008437 oact = NULL;
8438 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008439 rt_sigaction_fail:
8440 if (act)
pbrook53a59602006-03-25 19:31:22 +00008441 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008442 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008443 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008444#endif
pbrook53a59602006-03-25 19:31:22 +00008445 }
bellard66fb9762003-03-23 01:06:05 +00008446 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008447#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008448 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008449 {
8450 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008451 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008452 ret = do_sigprocmask(0, NULL, &cur_set);
8453 if (!ret) {
8454 host_to_target_old_sigset(&target_set, &cur_set);
8455 ret = target_set;
8456 }
bellard66fb9762003-03-23 01:06:05 +00008457 }
8458 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008459#endif
8460#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008461 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008462 {
8463 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008464 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008465 /* We only have one word of the new mask so we must read
8466 * the rest of it with do_sigprocmask() and OR in this word.
8467 * We are guaranteed that a do_sigprocmask() that only queries
8468 * the signal mask will not fail.
8469 */
8470 ret = do_sigprocmask(0, NULL, &cur_set);
8471 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00008472 target_to_host_old_sigset(&set, &target_set);
8473 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008474 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8475 if (!ret) {
8476 host_to_target_old_sigset(&target_set, &oset);
8477 ret = target_set;
8478 }
bellard66fb9762003-03-23 01:06:05 +00008479 }
8480 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008481#endif
thse5febef2007-04-01 18:31:35 +00008482#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008483 case TARGET_NR_sigprocmask:
8484 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008485#if defined(TARGET_ALPHA)
8486 sigset_t set, oldset;
8487 abi_ulong mask;
8488 int how;
8489
8490 switch (arg1) {
8491 case TARGET_SIG_BLOCK:
8492 how = SIG_BLOCK;
8493 break;
8494 case TARGET_SIG_UNBLOCK:
8495 how = SIG_UNBLOCK;
8496 break;
8497 case TARGET_SIG_SETMASK:
8498 how = SIG_SETMASK;
8499 break;
8500 default:
8501 ret = -TARGET_EINVAL;
8502 goto fail;
8503 }
8504 mask = arg2;
8505 target_to_host_old_sigset(&set, &mask);
8506
Peter Maydell3d3efba2016-05-27 15:51:49 +01008507 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008508 if (!is_error(ret)) {
8509 host_to_target_old_sigset(&mask, &oldset);
8510 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008511 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008512 }
8513#else
bellard66fb9762003-03-23 01:06:05 +00008514 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008515 int how;
ths3b46e622007-09-17 08:09:54 +00008516
pbrook53a59602006-03-25 19:31:22 +00008517 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008518 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008519 case TARGET_SIG_BLOCK:
8520 how = SIG_BLOCK;
8521 break;
8522 case TARGET_SIG_UNBLOCK:
8523 how = SIG_UNBLOCK;
8524 break;
8525 case TARGET_SIG_SETMASK:
8526 how = SIG_SETMASK;
8527 break;
8528 default:
ths0da46a62007-10-20 20:23:07 +00008529 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008530 goto fail;
8531 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008532 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008533 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008534 target_to_host_old_sigset(&set, p);
8535 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008536 set_ptr = &set;
8537 } else {
8538 how = 0;
8539 set_ptr = NULL;
8540 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008541 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008542 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008543 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008544 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008545 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008546 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008547 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008548#endif
bellard66fb9762003-03-23 01:06:05 +00008549 }
8550 break;
thse5febef2007-04-01 18:31:35 +00008551#endif
bellard66fb9762003-03-23 01:06:05 +00008552 case TARGET_NR_rt_sigprocmask:
8553 {
8554 int how = arg1;
8555 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008556
Peter Maydellc8157012016-06-30 14:23:24 +01008557 if (arg4 != sizeof(target_sigset_t)) {
8558 ret = -TARGET_EINVAL;
8559 break;
8560 }
8561
pbrook53a59602006-03-25 19:31:22 +00008562 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008563 switch(how) {
8564 case TARGET_SIG_BLOCK:
8565 how = SIG_BLOCK;
8566 break;
8567 case TARGET_SIG_UNBLOCK:
8568 how = SIG_UNBLOCK;
8569 break;
8570 case TARGET_SIG_SETMASK:
8571 how = SIG_SETMASK;
8572 break;
8573 default:
ths0da46a62007-10-20 20:23:07 +00008574 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008575 goto fail;
8576 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008577 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008578 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008579 target_to_host_sigset(&set, p);
8580 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008581 set_ptr = &set;
8582 } else {
8583 how = 0;
8584 set_ptr = NULL;
8585 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008586 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008587 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008588 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008589 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008590 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008591 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008592 }
8593 }
8594 break;
thse5febef2007-04-01 18:31:35 +00008595#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008596 case TARGET_NR_sigpending:
8597 {
8598 sigset_t set;
8599 ret = get_errno(sigpending(&set));
8600 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008601 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008602 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008603 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008604 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008605 }
8606 }
8607 break;
thse5febef2007-04-01 18:31:35 +00008608#endif
bellard66fb9762003-03-23 01:06:05 +00008609 case TARGET_NR_rt_sigpending:
8610 {
8611 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008612
8613 /* Yes, this check is >, not != like most. We follow the kernel's
8614 * logic and it does it like this because it implements
8615 * NR_sigpending through the same code path, and in that case
8616 * the old_sigset_t is smaller in size.
8617 */
8618 if (arg2 > sizeof(target_sigset_t)) {
8619 ret = -TARGET_EINVAL;
8620 break;
8621 }
8622
bellard66fb9762003-03-23 01:06:05 +00008623 ret = get_errno(sigpending(&set));
8624 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008625 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008626 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008627 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008628 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008629 }
8630 }
8631 break;
thse5febef2007-04-01 18:31:35 +00008632#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008633 case TARGET_NR_sigsuspend:
8634 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008635 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008636#if defined(TARGET_ALPHA)
8637 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008638 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008639#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008640 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008641 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008642 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008643 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008644#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008645 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8646 SIGSET_T_SIZE));
8647 if (ret != -TARGET_ERESTARTSYS) {
8648 ts->in_sigsuspend = 1;
8649 }
bellard66fb9762003-03-23 01:06:05 +00008650 }
8651 break;
thse5febef2007-04-01 18:31:35 +00008652#endif
bellard66fb9762003-03-23 01:06:05 +00008653 case TARGET_NR_rt_sigsuspend:
8654 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008655 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008656
8657 if (arg2 != sizeof(target_sigset_t)) {
8658 ret = -TARGET_EINVAL;
8659 break;
8660 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008661 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008662 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008663 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008664 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008665 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8666 SIGSET_T_SIZE));
8667 if (ret != -TARGET_ERESTARTSYS) {
8668 ts->in_sigsuspend = 1;
8669 }
bellard66fb9762003-03-23 01:06:05 +00008670 }
8671 break;
8672 case TARGET_NR_rt_sigtimedwait:
8673 {
bellard66fb9762003-03-23 01:06:05 +00008674 sigset_t set;
8675 struct timespec uts, *puts;
8676 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008677
Peter Maydellc8157012016-06-30 14:23:24 +01008678 if (arg4 != sizeof(target_sigset_t)) {
8679 ret = -TARGET_EINVAL;
8680 break;
8681 }
8682
Anthony Liguoric227f092009-10-01 16:12:16 -05008683 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008684 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008685 target_to_host_sigset(&set, p);
8686 unlock_user(p, arg1, 0);
8687 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008688 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008689 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008690 } else {
8691 puts = NULL;
8692 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008693 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8694 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008695 if (!is_error(ret)) {
8696 if (arg2) {
8697 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8698 0);
8699 if (!p) {
8700 goto efault;
8701 }
8702 host_to_target_siginfo(p, &uinfo);
8703 unlock_user(p, arg2, sizeof(target_siginfo_t));
8704 }
8705 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008706 }
8707 }
8708 break;
8709 case TARGET_NR_rt_sigqueueinfo:
8710 {
8711 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01008712
8713 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
8714 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00008715 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01008716 }
pbrook53a59602006-03-25 19:31:22 +00008717 target_to_host_siginfo(&uinfo, p);
8718 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00008719 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
8720 }
8721 break;
thse5febef2007-04-01 18:31:35 +00008722#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00008723 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008724 if (block_signals()) {
8725 ret = -TARGET_ERESTARTSYS;
8726 } else {
8727 ret = do_sigreturn(cpu_env);
8728 }
bellard66fb9762003-03-23 01:06:05 +00008729 break;
thse5febef2007-04-01 18:31:35 +00008730#endif
bellard66fb9762003-03-23 01:06:05 +00008731 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008732 if (block_signals()) {
8733 ret = -TARGET_ERESTARTSYS;
8734 } else {
8735 ret = do_rt_sigreturn(cpu_env);
8736 }
bellard66fb9762003-03-23 01:06:05 +00008737 break;
bellard31e31b82003-02-18 22:55:36 +00008738 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00008739 if (!(p = lock_user_string(arg1)))
8740 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008741 ret = get_errno(sethostname(p, arg2));
8742 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008743 break;
8744 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00008745 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008746 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008747 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008748 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00008749 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
8750 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008751 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
8752 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008753 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00008754 ret = get_errno(setrlimit(resource, &rlim));
8755 }
8756 break;
bellard31e31b82003-02-18 22:55:36 +00008757 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00008758 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008759 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008760 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008761 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008762
bellard9de5e442003-03-23 16:49:39 +00008763 ret = get_errno(getrlimit(resource, &rlim));
8764 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008765 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8766 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008767 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8768 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008769 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008770 }
8771 }
8772 break;
bellard31e31b82003-02-18 22:55:36 +00008773 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008774 {
8775 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008776 ret = get_errno(getrusage(arg1, &rusage));
8777 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008778 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008779 }
8780 }
8781 break;
bellard31e31b82003-02-18 22:55:36 +00008782 case TARGET_NR_gettimeofday:
8783 {
bellard31e31b82003-02-18 22:55:36 +00008784 struct timeval tv;
8785 ret = get_errno(gettimeofday(&tv, NULL));
8786 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008787 if (copy_to_user_timeval(arg1, &tv))
8788 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008789 }
8790 }
8791 break;
8792 case TARGET_NR_settimeofday:
8793 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008794 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008795 struct timezone tz, *ptz = NULL;
8796
Paul Burtonb67d8032014-06-22 11:25:41 +01008797 if (arg1) {
8798 if (copy_from_user_timeval(&tv, arg1)) {
8799 goto efault;
8800 }
8801 ptv = &tv;
8802 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008803
8804 if (arg2) {
8805 if (copy_from_user_timezone(&tz, arg2)) {
8806 goto efault;
8807 }
8808 ptz = &tz;
8809 }
8810
Paul Burtonb67d8032014-06-22 11:25:41 +01008811 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008812 }
8813 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008814#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008815 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02008816#if defined(TARGET_WANT_NI_OLD_SELECT)
8817 /* some architectures used to have old_select here
8818 * but now ENOSYS it.
8819 */
8820 ret = -TARGET_ENOSYS;
8821#elif defined(TARGET_WANT_OLD_SYS_SELECT)
8822 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008823#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02008824 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008825#endif
bellardf2674e32003-07-09 12:26:09 +00008826 break;
bellard048f6b42005-11-26 18:47:20 +00008827#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008828#ifdef TARGET_NR_pselect6
8829 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008830 {
8831 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8832 fd_set rfds, wfds, efds;
8833 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8834 struct timespec ts, *ts_ptr;
8835
8836 /*
8837 * The 6th arg is actually two args smashed together,
8838 * so we cannot use the C library.
8839 */
8840 sigset_t set;
8841 struct {
8842 sigset_t *set;
8843 size_t size;
8844 } sig, *sig_ptr;
8845
8846 abi_ulong arg_sigset, arg_sigsize, *arg7;
8847 target_sigset_t *target_sigset;
8848
8849 n = arg1;
8850 rfd_addr = arg2;
8851 wfd_addr = arg3;
8852 efd_addr = arg4;
8853 ts_addr = arg5;
8854
8855 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
8856 if (ret) {
8857 goto fail;
8858 }
8859 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
8860 if (ret) {
8861 goto fail;
8862 }
8863 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
8864 if (ret) {
8865 goto fail;
8866 }
8867
8868 /*
8869 * This takes a timespec, and not a timeval, so we cannot
8870 * use the do_select() helper ...
8871 */
8872 if (ts_addr) {
8873 if (target_to_host_timespec(&ts, ts_addr)) {
8874 goto efault;
8875 }
8876 ts_ptr = &ts;
8877 } else {
8878 ts_ptr = NULL;
8879 }
8880
8881 /* Extract the two packed args for the sigset */
8882 if (arg6) {
8883 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01008884 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04008885
8886 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
8887 if (!arg7) {
8888 goto efault;
8889 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008890 arg_sigset = tswapal(arg7[0]);
8891 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04008892 unlock_user(arg7, arg6, 0);
8893
8894 if (arg_sigset) {
8895 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01008896 if (arg_sigsize != sizeof(*target_sigset)) {
8897 /* Like the kernel, we enforce correct size sigsets */
8898 ret = -TARGET_EINVAL;
8899 goto fail;
8900 }
Mike Frysinger055e0902011-06-03 17:01:49 -04008901 target_sigset = lock_user(VERIFY_READ, arg_sigset,
8902 sizeof(*target_sigset), 1);
8903 if (!target_sigset) {
8904 goto efault;
8905 }
8906 target_to_host_sigset(&set, target_sigset);
8907 unlock_user(target_sigset, arg_sigset, 0);
8908 } else {
8909 sig.set = NULL;
8910 }
8911 } else {
8912 sig_ptr = NULL;
8913 }
8914
Peter Maydell6df9d382016-05-12 18:47:51 +01008915 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
8916 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04008917
8918 if (!is_error(ret)) {
8919 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
8920 goto efault;
8921 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
8922 goto efault;
8923 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
8924 goto efault;
8925
8926 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8927 goto efault;
8928 }
8929 }
8930 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008931#endif
Chen Gang704eff62015-08-21 05:37:33 +08008932#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008933 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008934 {
8935 void *p2;
8936 p = lock_user_string(arg1);
8937 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008938 if (!p || !p2)
8939 ret = -TARGET_EFAULT;
8940 else
8941 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008942 unlock_user(p2, arg2, 0);
8943 unlock_user(p, arg1, 0);
8944 }
bellard31e31b82003-02-18 22:55:36 +00008945 break;
Chen Gang704eff62015-08-21 05:37:33 +08008946#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008947#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008948 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008949 {
bellard579a97f2007-11-11 14:26:47 +00008950 void *p2;
thsf0b62432007-09-24 09:25:40 +00008951 p = lock_user_string(arg1);
8952 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008953 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008954 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008955 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008956 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008957 unlock_user(p2, arg3, 0);
8958 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008959 }
8960 break;
8961#endif
bellardebc05482003-09-30 21:08:41 +00008962#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008963 case TARGET_NR_oldlstat:
8964 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008965#endif
Chen Gang704eff62015-08-21 05:37:33 +08008966#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008967 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008968 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008969 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008970 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008971 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008972 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008973 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008974 } else if (!arg3) {
8975 /* Short circuit this for the magic exe check. */
8976 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008977 } else if (is_proc_myself((const char *)p, "exe")) {
8978 char real[PATH_MAX], *temp;
8979 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008980 /* Return value is # of bytes that we wrote to the buffer. */
8981 if (temp == NULL) {
8982 ret = get_errno(-1);
8983 } else {
8984 /* Don't worry about sign mismatch as earlier mapping
8985 * logic would have thrown a bad address error. */
8986 ret = MIN(strlen(real), arg3);
8987 /* We cannot NUL terminate the string. */
8988 memcpy(p2, real, ret);
8989 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008990 } else {
8991 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008992 }
pbrook53a59602006-03-25 19:31:22 +00008993 unlock_user(p2, arg2, ret);
8994 unlock_user(p, arg1, 0);
8995 }
bellard31e31b82003-02-18 22:55:36 +00008996 break;
Chen Gang704eff62015-08-21 05:37:33 +08008997#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008998#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008999 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009000 {
bellard579a97f2007-11-11 14:26:47 +00009001 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009002 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009003 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009004 if (!p || !p2) {
9005 ret = -TARGET_EFAULT;
9006 } else if (is_proc_myself((const char *)p, "exe")) {
9007 char real[PATH_MAX], *temp;
9008 temp = realpath(exec_path, real);
9009 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9010 snprintf((char *)p2, arg4, "%s", real);
9011 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009012 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009013 }
bellard579a97f2007-11-11 14:26:47 +00009014 unlock_user(p2, arg3, ret);
9015 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009016 }
9017 break;
9018#endif
thse5febef2007-04-01 18:31:35 +00009019#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009020 case TARGET_NR_uselib:
9021 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009022#endif
9023#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009024 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009025 if (!(p = lock_user_string(arg1)))
9026 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009027 ret = get_errno(swapon(p, arg2));
9028 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009029 break;
thse5febef2007-04-01 18:31:35 +00009030#endif
bellard31e31b82003-02-18 22:55:36 +00009031 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009032 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9033 /* arg4 must be ignored in all other cases */
9034 p = lock_user_string(arg4);
9035 if (!p) {
9036 goto efault;
9037 }
9038 ret = get_errno(reboot(arg1, arg2, arg3, p));
9039 unlock_user(p, arg4, 0);
9040 } else {
9041 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9042 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009043 break;
thse5febef2007-04-01 18:31:35 +00009044#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009045 case TARGET_NR_readdir:
9046 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009047#endif
9048#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009049 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009050#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9051 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009052 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9053 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009054 {
blueswir1992f48a2007-10-14 16:27:31 +00009055 abi_ulong *v;
9056 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009057 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9058 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009059 v1 = tswapal(v[0]);
9060 v2 = tswapal(v[1]);
9061 v3 = tswapal(v[2]);
9062 v4 = tswapal(v[3]);
9063 v5 = tswapal(v[4]);
9064 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009065 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009066 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009067 target_to_host_bitmask(v4, mmap_flags_tbl),
9068 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009069 }
bellard31e31b82003-02-18 22:55:36 +00009070#else
ths5fafdf22007-09-16 21:08:06 +00009071 ret = get_errno(target_mmap(arg1, arg2, arg3,
9072 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009073 arg5,
9074 arg6));
bellard31e31b82003-02-18 22:55:36 +00009075#endif
bellard6fb883e2003-07-09 17:12:39 +00009076 break;
thse5febef2007-04-01 18:31:35 +00009077#endif
bellarda315a142005-01-30 22:59:18 +00009078#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009079 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009080#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009081#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009082#endif
ths5fafdf22007-09-16 21:08:06 +00009083 ret = get_errno(target_mmap(arg1, arg2, arg3,
9084 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009085 arg5,
bellardc573ff62004-01-04 15:51:36 +00009086 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009087 break;
bellarda315a142005-01-30 22:59:18 +00009088#endif
bellard31e31b82003-02-18 22:55:36 +00009089 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009090 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009091 break;
bellard9de5e442003-03-23 16:49:39 +00009092 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009093 {
Andreas Färber0429a972013-08-26 18:14:44 +02009094 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009095 /* Special hack to detect libc making the stack executable. */
9096 if ((arg3 & PROT_GROWSDOWN)
9097 && arg1 >= ts->info->stack_limit
9098 && arg1 <= ts->info->start_stack) {
9099 arg3 &= ~PROT_GROWSDOWN;
9100 arg2 = arg2 + arg1 - ts->info->stack_limit;
9101 arg1 = ts->info->stack_limit;
9102 }
9103 }
bellard54936002003-05-13 00:25:15 +00009104 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009105 break;
thse5febef2007-04-01 18:31:35 +00009106#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009107 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009108 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009109 break;
thse5febef2007-04-01 18:31:35 +00009110#endif
pbrook53a59602006-03-25 19:31:22 +00009111 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009112#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009113 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009114 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009115 break;
thse5febef2007-04-01 18:31:35 +00009116#endif
9117#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009118 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009119 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009120 break;
thse5febef2007-04-01 18:31:35 +00009121#endif
9122#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009123 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009124 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009125 break;
thse5febef2007-04-01 18:31:35 +00009126#endif
9127#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009128 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009129 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009130 break;
thse5febef2007-04-01 18:31:35 +00009131#endif
9132#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009133 case TARGET_NR_munlockall:
9134 ret = get_errno(munlockall());
9135 break;
thse5febef2007-04-01 18:31:35 +00009136#endif
bellard31e31b82003-02-18 22:55:36 +00009137 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009138 if (!(p = lock_user_string(arg1)))
9139 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009140 ret = get_errno(truncate(p, arg2));
9141 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009142 break;
9143 case TARGET_NR_ftruncate:
9144 ret = get_errno(ftruncate(arg1, arg2));
9145 break;
9146 case TARGET_NR_fchmod:
9147 ret = get_errno(fchmod(arg1, arg2));
9148 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009149#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009150 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009151 if (!(p = lock_user_string(arg2)))
9152 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009153 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009154 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009155 break;
9156#endif
bellard31e31b82003-02-18 22:55:36 +00009157 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009158 /* Note that negative values are valid for getpriority, so we must
9159 differentiate based on errno settings. */
9160 errno = 0;
9161 ret = getpriority(arg1, arg2);
9162 if (ret == -1 && errno != 0) {
9163 ret = -host_to_target_errno(errno);
9164 break;
9165 }
9166#ifdef TARGET_ALPHA
9167 /* Return value is the unbiased priority. Signal no error. */
9168 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9169#else
9170 /* Return value is a biased priority to avoid negative numbers. */
9171 ret = 20 - ret;
9172#endif
bellard31e31b82003-02-18 22:55:36 +00009173 break;
9174 case TARGET_NR_setpriority:
9175 ret = get_errno(setpriority(arg1, arg2, arg3));
9176 break;
bellardebc05482003-09-30 21:08:41 +00009177#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009178 case TARGET_NR_profil:
9179 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009180#endif
bellard31e31b82003-02-18 22:55:36 +00009181 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009182 if (!(p = lock_user_string(arg1)))
9183 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009184 ret = get_errno(statfs(path(p), &stfs));
9185 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009186 convert_statfs:
9187 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009188 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009189
bellard579a97f2007-11-11 14:26:47 +00009190 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9191 goto efault;
9192 __put_user(stfs.f_type, &target_stfs->f_type);
9193 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9194 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9195 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9196 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9197 __put_user(stfs.f_files, &target_stfs->f_files);
9198 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9199 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9200 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9201 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009202 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9203 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009204 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009205 }
9206 break;
9207 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009208 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009209 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009210#ifdef TARGET_NR_statfs64
9211 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009212 if (!(p = lock_user_string(arg1)))
9213 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009214 ret = get_errno(statfs(path(p), &stfs));
9215 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009216 convert_statfs64:
9217 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009218 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009219
bellard579a97f2007-11-11 14:26:47 +00009220 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9221 goto efault;
9222 __put_user(stfs.f_type, &target_stfs->f_type);
9223 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9224 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9225 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9226 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9227 __put_user(stfs.f_files, &target_stfs->f_files);
9228 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9229 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9230 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9231 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009232 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9233 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009234 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009235 }
9236 break;
9237 case TARGET_NR_fstatfs64:
9238 ret = get_errno(fstatfs(arg1, &stfs));
9239 goto convert_statfs64;
9240#endif
bellardebc05482003-09-30 21:08:41 +00009241#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009242 case TARGET_NR_ioperm:
9243 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009244#endif
thse5febef2007-04-01 18:31:35 +00009245#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009246 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009247 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009248 break;
thse5febef2007-04-01 18:31:35 +00009249#endif
bellard3532fa72006-06-24 15:06:03 +00009250#ifdef TARGET_NR_accept
9251 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009252 ret = do_accept4(arg1, arg2, arg3, 0);
9253 break;
9254#endif
9255#ifdef TARGET_NR_accept4
9256 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009257 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009258 break;
9259#endif
9260#ifdef TARGET_NR_bind
9261 case TARGET_NR_bind:
9262 ret = do_bind(arg1, arg2, arg3);
9263 break;
9264#endif
9265#ifdef TARGET_NR_connect
9266 case TARGET_NR_connect:
9267 ret = do_connect(arg1, arg2, arg3);
9268 break;
9269#endif
9270#ifdef TARGET_NR_getpeername
9271 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009272 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009273 break;
9274#endif
9275#ifdef TARGET_NR_getsockname
9276 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009277 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009278 break;
9279#endif
9280#ifdef TARGET_NR_getsockopt
9281 case TARGET_NR_getsockopt:
9282 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9283 break;
9284#endif
9285#ifdef TARGET_NR_listen
9286 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009287 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009288 break;
9289#endif
9290#ifdef TARGET_NR_recv
9291 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009292 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009293 break;
9294#endif
9295#ifdef TARGET_NR_recvfrom
9296 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009297 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009298 break;
9299#endif
9300#ifdef TARGET_NR_recvmsg
9301 case TARGET_NR_recvmsg:
9302 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9303 break;
9304#endif
9305#ifdef TARGET_NR_send
9306 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009307 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009308 break;
9309#endif
9310#ifdef TARGET_NR_sendmsg
9311 case TARGET_NR_sendmsg:
9312 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9313 break;
9314#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009315#ifdef TARGET_NR_sendmmsg
9316 case TARGET_NR_sendmmsg:
9317 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9318 break;
9319 case TARGET_NR_recvmmsg:
9320 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9321 break;
9322#endif
bellard3532fa72006-06-24 15:06:03 +00009323#ifdef TARGET_NR_sendto
9324 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009325 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009326 break;
9327#endif
9328#ifdef TARGET_NR_shutdown
9329 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009330 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009331 break;
9332#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009333#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9334 case TARGET_NR_getrandom:
9335 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9336 if (!p) {
9337 goto efault;
9338 }
9339 ret = get_errno(getrandom(p, arg2, arg3));
9340 unlock_user(p, arg1, ret);
9341 break;
9342#endif
bellard3532fa72006-06-24 15:06:03 +00009343#ifdef TARGET_NR_socket
9344 case TARGET_NR_socket:
9345 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02009346 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00009347 break;
9348#endif
9349#ifdef TARGET_NR_socketpair
9350 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009351 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009352 break;
9353#endif
9354#ifdef TARGET_NR_setsockopt
9355 case TARGET_NR_setsockopt:
9356 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9357 break;
9358#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009359#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009360 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009361 {
9362 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009363
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009364 switch (arg1) {
9365 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9366 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9367 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9368 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9369 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9370 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9371 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9372 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9373 {
9374 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9375 }
9376 break;
9377 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9378 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9379 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9380 {
9381 ret = -TARGET_EINVAL;
9382 if (len < 0) {
9383 goto fail;
9384 }
9385 ret = 0;
9386 if (len == 0) {
9387 break;
9388 }
9389 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9390 if (!p) {
9391 ret = -TARGET_EFAULT;
9392 goto fail;
9393 }
9394 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9395 unlock_user(p, arg2, arg3);
9396 }
9397 break;
9398 default:
9399 ret = -EINVAL;
9400 break;
9401 }
9402 }
9403 break;
9404#endif
bellard31e31b82003-02-18 22:55:36 +00009405 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009406 {
bellard66fb9762003-03-23 01:06:05 +00009407 struct itimerval value, ovalue, *pvalue;
9408
pbrook53a59602006-03-25 19:31:22 +00009409 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009410 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009411 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9412 || copy_from_user_timeval(&pvalue->it_value,
9413 arg2 + sizeof(struct target_timeval)))
9414 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009415 } else {
9416 pvalue = NULL;
9417 }
9418 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009419 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009420 if (copy_to_user_timeval(arg3,
9421 &ovalue.it_interval)
9422 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9423 &ovalue.it_value))
9424 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009425 }
9426 }
9427 break;
bellard31e31b82003-02-18 22:55:36 +00009428 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009429 {
bellard66fb9762003-03-23 01:06:05 +00009430 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009431
bellard66fb9762003-03-23 01:06:05 +00009432 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009433 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009434 if (copy_to_user_timeval(arg2,
9435 &value.it_interval)
9436 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9437 &value.it_value))
9438 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009439 }
9440 }
9441 break;
Chen Gang704eff62015-08-21 05:37:33 +08009442#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009443 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009444 if (!(p = lock_user_string(arg1)))
9445 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009446 ret = get_errno(stat(path(p), &st));
9447 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009448 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009449#endif
9450#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009451 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009452 if (!(p = lock_user_string(arg1)))
9453 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009454 ret = get_errno(lstat(path(p), &st));
9455 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009456 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009457#endif
bellard31e31b82003-02-18 22:55:36 +00009458 case TARGET_NR_fstat:
9459 {
9460 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009461#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009462 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009463#endif
bellard31e31b82003-02-18 22:55:36 +00009464 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009465 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009466
bellard579a97f2007-11-11 14:26:47 +00009467 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9468 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009469 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009470 __put_user(st.st_dev, &target_st->st_dev);
9471 __put_user(st.st_ino, &target_st->st_ino);
9472 __put_user(st.st_mode, &target_st->st_mode);
9473 __put_user(st.st_uid, &target_st->st_uid);
9474 __put_user(st.st_gid, &target_st->st_gid);
9475 __put_user(st.st_nlink, &target_st->st_nlink);
9476 __put_user(st.st_rdev, &target_st->st_rdev);
9477 __put_user(st.st_size, &target_st->st_size);
9478 __put_user(st.st_blksize, &target_st->st_blksize);
9479 __put_user(st.st_blocks, &target_st->st_blocks);
9480 __put_user(st.st_atime, &target_st->target_st_atime);
9481 __put_user(st.st_mtime, &target_st->target_st_mtime);
9482 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009483 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009484 }
9485 }
9486 break;
bellardebc05482003-09-30 21:08:41 +00009487#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009488 case TARGET_NR_olduname:
9489 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009490#endif
9491#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009492 case TARGET_NR_iopl:
9493 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009494#endif
bellard31e31b82003-02-18 22:55:36 +00009495 case TARGET_NR_vhangup:
9496 ret = get_errno(vhangup());
9497 break;
bellardebc05482003-09-30 21:08:41 +00009498#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009499 case TARGET_NR_idle:
9500 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009501#endif
bellard42ad6ae2005-01-03 22:48:11 +00009502#ifdef TARGET_NR_syscall
9503 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009504 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9505 arg6, arg7, arg8, 0);
9506 break;
bellard42ad6ae2005-01-03 22:48:11 +00009507#endif
bellard31e31b82003-02-18 22:55:36 +00009508 case TARGET_NR_wait4:
9509 {
9510 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009511 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009512 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009513 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009514 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009515 if (target_rusage)
9516 rusage_ptr = &rusage;
9517 else
9518 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009519 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009520 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009521 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009522 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009523 if (put_user_s32(status, status_ptr))
9524 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009525 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009526 if (target_rusage) {
9527 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9528 if (rusage_err) {
9529 ret = rusage_err;
9530 }
9531 }
bellard31e31b82003-02-18 22:55:36 +00009532 }
9533 }
9534 break;
thse5febef2007-04-01 18:31:35 +00009535#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009536 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009537 if (!(p = lock_user_string(arg1)))
9538 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009539 ret = get_errno(swapoff(p));
9540 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009541 break;
thse5febef2007-04-01 18:31:35 +00009542#endif
bellard31e31b82003-02-18 22:55:36 +00009543 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009544 {
pbrook53a59602006-03-25 19:31:22 +00009545 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009546 struct sysinfo value;
9547 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009548 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009549 {
bellard579a97f2007-11-11 14:26:47 +00009550 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9551 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009552 __put_user(value.uptime, &target_value->uptime);
9553 __put_user(value.loads[0], &target_value->loads[0]);
9554 __put_user(value.loads[1], &target_value->loads[1]);
9555 __put_user(value.loads[2], &target_value->loads[2]);
9556 __put_user(value.totalram, &target_value->totalram);
9557 __put_user(value.freeram, &target_value->freeram);
9558 __put_user(value.sharedram, &target_value->sharedram);
9559 __put_user(value.bufferram, &target_value->bufferram);
9560 __put_user(value.totalswap, &target_value->totalswap);
9561 __put_user(value.freeswap, &target_value->freeswap);
9562 __put_user(value.procs, &target_value->procs);
9563 __put_user(value.totalhigh, &target_value->totalhigh);
9564 __put_user(value.freehigh, &target_value->freehigh);
9565 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009566 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009567 }
9568 }
9569 break;
thse5febef2007-04-01 18:31:35 +00009570#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009571 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +01009572 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
9573 break;
thse5febef2007-04-01 18:31:35 +00009574#endif
aurel32e5289082009-04-18 16:16:12 +00009575#ifdef TARGET_NR_semget
9576 case TARGET_NR_semget:
9577 ret = get_errno(semget(arg1, arg2, arg3));
9578 break;
9579#endif
9580#ifdef TARGET_NR_semop
9581 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009582 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009583 break;
9584#endif
9585#ifdef TARGET_NR_semctl
9586 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009587 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009588 break;
9589#endif
aurel32eeb438c2008-10-13 21:08:55 +00009590#ifdef TARGET_NR_msgctl
9591 case TARGET_NR_msgctl:
9592 ret = do_msgctl(arg1, arg2, arg3);
9593 break;
9594#endif
9595#ifdef TARGET_NR_msgget
9596 case TARGET_NR_msgget:
9597 ret = get_errno(msgget(arg1, arg2));
9598 break;
9599#endif
9600#ifdef TARGET_NR_msgrcv
9601 case TARGET_NR_msgrcv:
9602 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9603 break;
9604#endif
9605#ifdef TARGET_NR_msgsnd
9606 case TARGET_NR_msgsnd:
9607 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9608 break;
9609#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009610#ifdef TARGET_NR_shmget
9611 case TARGET_NR_shmget:
9612 ret = get_errno(shmget(arg1, arg2, arg3));
9613 break;
9614#endif
9615#ifdef TARGET_NR_shmctl
9616 case TARGET_NR_shmctl:
9617 ret = do_shmctl(arg1, arg2, arg3);
9618 break;
9619#endif
9620#ifdef TARGET_NR_shmat
9621 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +01009622 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009623 break;
9624#endif
9625#ifdef TARGET_NR_shmdt
9626 case TARGET_NR_shmdt:
9627 ret = do_shmdt(arg1);
9628 break;
9629#endif
bellard31e31b82003-02-18 22:55:36 +00009630 case TARGET_NR_fsync:
9631 ret = get_errno(fsync(arg1));
9632 break;
bellard31e31b82003-02-18 22:55:36 +00009633 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009634 /* Linux manages to have three different orderings for its
9635 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9636 * match the kernel's CONFIG_CLONE_* settings.
9637 * Microblaze is further special in that it uses a sixth
9638 * implicit argument to clone for the TLS pointer.
9639 */
9640#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009641 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009642#elif defined(TARGET_CLONE_BACKWARDS)
9643 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9644#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009645 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009646#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009647 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009648#endif
bellard1b6b0292003-03-22 17:31:38 +00009649 break;
bellardec86b0f2003-04-11 00:15:04 +00009650#ifdef __NR_exit_group
9651 /* new thread calls */
9652 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02009653#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00009654 _mcleanup();
9655#endif
bellarde9009672005-04-26 20:42:36 +00009656 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00009657 ret = get_errno(exit_group(arg1));
9658 break;
9659#endif
bellard31e31b82003-02-18 22:55:36 +00009660 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009661 if (!(p = lock_user_string(arg1)))
9662 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009663 ret = get_errno(setdomainname(p, arg2));
9664 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009665 break;
9666 case TARGET_NR_uname:
9667 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009668 {
9669 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009670
bellard579a97f2007-11-11 14:26:47 +00009671 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
9672 goto efault;
bellard29e619b2004-09-13 21:41:04 +00009673 ret = get_errno(sys_uname(buf));
9674 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009675 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009676 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01009677 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00009678 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009679 if (qemu_uname_release && *qemu_uname_release) {
9680 g_strlcpy(buf->release, qemu_uname_release,
9681 sizeof(buf->release));
9682 }
bellard29e619b2004-09-13 21:41:04 +00009683 }
pbrook53a59602006-03-25 19:31:22 +00009684 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009685 }
bellard31e31b82003-02-18 22:55:36 +00009686 break;
bellard6dbad632003-03-16 18:05:05 +00009687#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009688 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00009689 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00009690 break;
j_mayer84409dd2007-04-06 08:56:50 +00009691#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009692 case TARGET_NR_vm86old:
9693 goto unimplemented;
9694 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00009695 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009696 break;
9697#endif
j_mayer84409dd2007-04-06 08:56:50 +00009698#endif
bellard31e31b82003-02-18 22:55:36 +00009699 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02009700 {
9701 struct timex host_buf;
9702
9703 if (target_to_host_timex(&host_buf, arg1) != 0) {
9704 goto efault;
9705 }
9706 ret = get_errno(adjtimex(&host_buf));
9707 if (!is_error(ret)) {
9708 if (host_to_target_timex(arg1, &host_buf) != 0) {
9709 goto efault;
9710 }
9711 }
9712 }
9713 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009714#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
9715 case TARGET_NR_clock_adjtime:
9716 {
9717 struct timex htx, *phtx = &htx;
9718
9719 if (target_to_host_timex(phtx, arg2) != 0) {
9720 goto efault;
9721 }
9722 ret = get_errno(clock_adjtime(arg1, phtx));
9723 if (!is_error(ret) && phtx) {
9724 if (host_to_target_timex(arg2, phtx) != 0) {
9725 goto efault;
9726 }
9727 }
9728 }
9729 break;
9730#endif
thse5febef2007-04-01 18:31:35 +00009731#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00009732 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00009733#endif
bellard31e31b82003-02-18 22:55:36 +00009734 case TARGET_NR_init_module:
9735 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00009736#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00009737 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00009738#endif
bellard31e31b82003-02-18 22:55:36 +00009739 goto unimplemented;
9740 case TARGET_NR_quotactl:
9741 goto unimplemented;
9742 case TARGET_NR_getpgid:
9743 ret = get_errno(getpgid(arg1));
9744 break;
9745 case TARGET_NR_fchdir:
9746 ret = get_errno(fchdir(arg1));
9747 break;
j_mayer84409dd2007-04-06 08:56:50 +00009748#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00009749 case TARGET_NR_bdflush:
9750 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00009751#endif
thse5febef2007-04-01 18:31:35 +00009752#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00009753 case TARGET_NR_sysfs:
9754 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009755#endif
bellard31e31b82003-02-18 22:55:36 +00009756 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00009757 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00009758 break;
thse5febef2007-04-01 18:31:35 +00009759#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00009760 case TARGET_NR_afs_syscall:
9761 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009762#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009763#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009764 case TARGET_NR__llseek:
9765 {
9766 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009767#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +01009768 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +00009769 if (res == -1) {
9770 ret = get_errno(res);
9771 } else {
9772 ret = 0;
9773 }
9774#else
bellard31e31b82003-02-18 22:55:36 +00009775 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00009776#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00009777 if ((ret == 0) && put_user_s64(res, arg4)) {
9778 goto efault;
9779 }
bellard31e31b82003-02-18 22:55:36 +00009780 }
9781 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009782#endif
Chen Gang704eff62015-08-21 05:37:33 +08009783#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00009784 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01009785#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02009786#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00009787 {
pbrook53a59602006-03-25 19:31:22 +00009788 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00009789 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009790 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00009791
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309792 dirp = g_try_malloc(count);
9793 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00009794 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00009795 goto fail;
9796 }
ths3b46e622007-09-17 08:09:54 +00009797
bellard4add45b2003-06-05 01:52:59 +00009798 ret = get_errno(sys_getdents(arg1, dirp, count));
9799 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009800 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00009801 struct target_dirent *tde;
9802 int len = ret;
9803 int reclen, treclen;
9804 int count1, tnamelen;
9805
9806 count1 = 0;
9807 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00009808 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9809 goto efault;
bellard4add45b2003-06-05 01:52:59 +00009810 tde = target_dirp;
9811 while (len > 0) {
9812 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009813 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
9814 assert(tnamelen >= 0);
9815 treclen = tnamelen + offsetof(struct target_dirent, d_name);
9816 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00009817 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009818 tde->d_ino = tswapal(de->d_ino);
9819 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009820 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009821 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009822 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009823 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009824 count1 += treclen;
9825 }
9826 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009827 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009828 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309829 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009830 }
9831#else
bellard31e31b82003-02-18 22:55:36 +00009832 {
aurel326556a832008-10-13 21:08:17 +00009833 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009834 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009835
bellard579a97f2007-11-11 14:26:47 +00009836 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9837 goto efault;
bellard72f03902003-02-18 23:33:18 +00009838 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009839 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009840 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00009841 int len = ret;
9842 int reclen;
9843 de = dirp;
9844 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009845 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00009846 if (reclen > len)
9847 break;
bellard8083a3e2003-03-24 23:12:16 +00009848 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00009849 tswapls(&de->d_ino);
9850 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009851 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00009852 len -= reclen;
9853 }
9854 }
pbrook53a59602006-03-25 19:31:22 +00009855 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00009856 }
bellard4add45b2003-06-05 01:52:59 +00009857#endif
Peter Maydell3307e232013-06-12 16:20:21 +01009858#else
9859 /* Implement getdents in terms of getdents64 */
9860 {
9861 struct linux_dirent64 *dirp;
9862 abi_long count = arg3;
9863
9864 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
9865 if (!dirp) {
9866 goto efault;
9867 }
9868 ret = get_errno(sys_getdents64(arg1, dirp, count));
9869 if (!is_error(ret)) {
9870 /* Convert the dirent64 structs to target dirent. We do this
9871 * in-place, since we can guarantee that a target_dirent is no
9872 * larger than a dirent64; however this means we have to be
9873 * careful to read everything before writing in the new format.
9874 */
9875 struct linux_dirent64 *de;
9876 struct target_dirent *tde;
9877 int len = ret;
9878 int tlen = 0;
9879
9880 de = dirp;
9881 tde = (struct target_dirent *)dirp;
9882 while (len > 0) {
9883 int namelen, treclen;
9884 int reclen = de->d_reclen;
9885 uint64_t ino = de->d_ino;
9886 int64_t off = de->d_off;
9887 uint8_t type = de->d_type;
9888
9889 namelen = strlen(de->d_name);
9890 treclen = offsetof(struct target_dirent, d_name)
9891 + namelen + 2;
9892 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
9893
9894 memmove(tde->d_name, de->d_name, namelen + 1);
9895 tde->d_ino = tswapal(ino);
9896 tde->d_off = tswapal(off);
9897 tde->d_reclen = tswap16(treclen);
9898 /* The target_dirent type is in what was formerly a padding
9899 * byte at the end of the structure:
9900 */
9901 *(((char *)tde) + treclen - 1) = type;
9902
9903 de = (struct linux_dirent64 *)((char *)de + reclen);
9904 tde = (struct target_dirent *)((char *)tde + treclen);
9905 len -= reclen;
9906 tlen += treclen;
9907 }
9908 ret = tlen;
9909 }
9910 unlock_user(dirp, arg2, ret);
9911 }
9912#endif
bellard31e31b82003-02-18 22:55:36 +00009913 break;
Chen Gang704eff62015-08-21 05:37:33 +08009914#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00009915#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00009916 case TARGET_NR_getdents64:
9917 {
aurel326556a832008-10-13 21:08:17 +00009918 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009919 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00009920 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9921 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00009922 ret = get_errno(sys_getdents64(arg1, dirp, count));
9923 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009924 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00009925 int len = ret;
9926 int reclen;
9927 de = dirp;
9928 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00009929 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00009930 if (reclen > len)
9931 break;
bellard8083a3e2003-03-24 23:12:16 +00009932 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00009933 tswap64s((uint64_t *)&de->d_ino);
9934 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00009935 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00009936 len -= reclen;
9937 }
9938 }
pbrook53a59602006-03-25 19:31:22 +00009939 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00009940 }
9941 break;
bellarda541f292004-04-12 20:39:29 +00009942#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01009943#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00009944 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00009945 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00009946 break;
thse5febef2007-04-01 18:31:35 +00009947#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05009948#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
9949# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00009950 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05009951# endif
9952# ifdef TARGET_NR_ppoll
9953 case TARGET_NR_ppoll:
9954# endif
bellard9de5e442003-03-23 16:49:39 +00009955 {
pbrook53a59602006-03-25 19:31:22 +00009956 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00009957 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +00009958 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00009959 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00009960
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009961 pfd = NULL;
9962 target_pfd = NULL;
9963 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +01009964 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
9965 ret = -TARGET_EINVAL;
9966 break;
9967 }
9968
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009969 target_pfd = lock_user(VERIFY_WRITE, arg1,
9970 sizeof(struct target_pollfd) * nfds, 1);
9971 if (!target_pfd) {
9972 goto efault;
9973 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009974
Laurent Vivier3e24bb32015-10-06 01:20:48 +02009975 pfd = alloca(sizeof(struct pollfd) * nfds);
9976 for (i = 0; i < nfds; i++) {
9977 pfd[i].fd = tswap32(target_pfd[i].fd);
9978 pfd[i].events = tswap16(target_pfd[i].events);
9979 }
bellard9de5e442003-03-23 16:49:39 +00009980 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05009981
Peter Maydella6130232016-06-06 19:58:10 +01009982 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009983# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +01009984 case TARGET_NR_ppoll:
9985 {
Mike Frysingerd8035d42011-02-07 01:05:51 -05009986 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
9987 target_sigset_t *target_set;
9988 sigset_t _set, *set = &_set;
9989
9990 if (arg3) {
9991 if (target_to_host_timespec(timeout_ts, arg3)) {
9992 unlock_user(target_pfd, arg1, 0);
9993 goto efault;
9994 }
9995 } else {
9996 timeout_ts = NULL;
9997 }
9998
9999 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010000 if (arg5 != sizeof(target_sigset_t)) {
10001 unlock_user(target_pfd, arg1, 0);
10002 ret = -TARGET_EINVAL;
10003 break;
10004 }
10005
Mike Frysingerd8035d42011-02-07 01:05:51 -050010006 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10007 if (!target_set) {
10008 unlock_user(target_pfd, arg1, 0);
10009 goto efault;
10010 }
10011 target_to_host_sigset(set, target_set);
10012 } else {
10013 set = NULL;
10014 }
10015
Peter Maydella6130232016-06-06 19:58:10 +010010016 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10017 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010018
10019 if (!is_error(ret) && arg3) {
10020 host_to_target_timespec(arg3, timeout_ts);
10021 }
10022 if (arg4) {
10023 unlock_user(target_set, arg4, 0);
10024 }
Peter Maydella6130232016-06-06 19:58:10 +010010025 break;
10026 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010027# endif
Peter Maydella6130232016-06-06 19:58:10 +010010028# ifdef TARGET_NR_poll
10029 case TARGET_NR_poll:
10030 {
10031 struct timespec ts, *pts;
10032
10033 if (arg3 >= 0) {
10034 /* Convert ms to secs, ns */
10035 ts.tv_sec = arg3 / 1000;
10036 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10037 pts = &ts;
10038 } else {
10039 /* -ve poll() timeout means "infinite" */
10040 pts = NULL;
10041 }
10042 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10043 break;
10044 }
10045# endif
10046 default:
10047 g_assert_not_reached();
10048 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010049
bellard9de5e442003-03-23 16:49:39 +000010050 if (!is_error(ret)) {
10051 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010052 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010053 }
10054 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010055 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010056 }
10057 break;
thse5febef2007-04-01 18:31:35 +000010058#endif
bellard31e31b82003-02-18 22:55:36 +000010059 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010060 /* NOTE: the flock constant seems to be the same for every
10061 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010062 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010063 break;
10064 case TARGET_NR_readv:
10065 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010066 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10067 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010068 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010069 unlock_iovec(vec, arg2, arg3, 1);
10070 } else {
10071 ret = -host_to_target_errno(errno);
10072 }
bellard31e31b82003-02-18 22:55:36 +000010073 }
10074 break;
10075 case TARGET_NR_writev:
10076 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010077 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10078 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010079 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010080 unlock_iovec(vec, arg2, arg3, 0);
10081 } else {
10082 ret = -host_to_target_errno(errno);
10083 }
bellard31e31b82003-02-18 22:55:36 +000010084 }
10085 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010086#if defined(TARGET_NR_preadv)
10087 case TARGET_NR_preadv:
10088 {
10089 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10090 if (vec != NULL) {
10091 ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
10092 unlock_iovec(vec, arg2, arg3, 1);
10093 } else {
10094 ret = -host_to_target_errno(errno);
10095 }
10096 }
10097 break;
10098#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010099#if defined(TARGET_NR_pwritev)
10100 case TARGET_NR_pwritev:
10101 {
10102 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10103 if (vec != NULL) {
10104 ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
10105 unlock_iovec(vec, arg2, arg3, 0);
10106 } else {
10107 ret = -host_to_target_errno(errno);
10108 }
10109 }
10110 break;
10111#endif
bellard31e31b82003-02-18 22:55:36 +000010112 case TARGET_NR_getsid:
10113 ret = get_errno(getsid(arg1));
10114 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010115#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010116 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010117 ret = get_errno(fdatasync(arg1));
10118 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010119#endif
Chen Gang704eff62015-08-21 05:37:33 +080010120#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010121 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010122 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010123 return value. */
ths0da46a62007-10-20 20:23:07 +000010124 ret = -TARGET_ENOTDIR;
10125 break;
Chen Gang704eff62015-08-21 05:37:33 +080010126#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010127 case TARGET_NR_sched_getaffinity:
10128 {
10129 unsigned int mask_size;
10130 unsigned long *mask;
10131
10132 /*
10133 * sched_getaffinity needs multiples of ulong, so need to take
10134 * care of mismatches between target ulong and host ulong sizes.
10135 */
10136 if (arg2 & (sizeof(abi_ulong) - 1)) {
10137 ret = -TARGET_EINVAL;
10138 break;
10139 }
10140 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10141
10142 mask = alloca(mask_size);
10143 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10144
10145 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010146 if (ret > arg2) {
10147 /* More data returned than the caller's buffer will fit.
10148 * This only happens if sizeof(abi_long) < sizeof(long)
10149 * and the caller passed us a buffer holding an odd number
10150 * of abi_longs. If the host kernel is actually using the
10151 * extra 4 bytes then fail EINVAL; otherwise we can just
10152 * ignore them and only copy the interesting part.
10153 */
10154 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10155 if (numcpus > arg2 * 8) {
10156 ret = -TARGET_EINVAL;
10157 break;
10158 }
10159 ret = arg2;
10160 }
10161
Mike McCormackcd18f052011-04-18 14:43:36 +090010162 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -050010163 goto efault;
10164 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010165 }
10166 }
10167 break;
10168 case TARGET_NR_sched_setaffinity:
10169 {
10170 unsigned int mask_size;
10171 unsigned long *mask;
10172
10173 /*
10174 * sched_setaffinity needs multiples of ulong, so need to take
10175 * care of mismatches between target ulong and host ulong sizes.
10176 */
10177 if (arg2 & (sizeof(abi_ulong) - 1)) {
10178 ret = -TARGET_EINVAL;
10179 break;
10180 }
10181 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10182
10183 mask = alloca(mask_size);
10184 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
10185 goto efault;
10186 }
10187 memcpy(mask, p, arg2);
10188 unlock_user_struct(p, arg2, 0);
10189
10190 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10191 }
10192 break;
bellard31e31b82003-02-18 22:55:36 +000010193 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010194 {
pbrook53a59602006-03-25 19:31:22 +000010195 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010196 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010197
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010198 if (arg2 == 0) {
10199 return -TARGET_EINVAL;
10200 }
bellard579a97f2007-11-11 14:26:47 +000010201 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10202 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010203 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010204 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010205 ret = get_errno(sched_setparam(arg1, &schp));
10206 }
10207 break;
bellard31e31b82003-02-18 22:55:36 +000010208 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010209 {
pbrook53a59602006-03-25 19:31:22 +000010210 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010211 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010212
10213 if (arg2 == 0) {
10214 return -TARGET_EINVAL;
10215 }
bellard5cd43932003-03-29 16:54:36 +000010216 ret = get_errno(sched_getparam(arg1, &schp));
10217 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010218 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10219 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010220 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010221 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010222 }
10223 }
10224 break;
bellard31e31b82003-02-18 22:55:36 +000010225 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010226 {
pbrook53a59602006-03-25 19:31:22 +000010227 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010228 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010229 if (arg3 == 0) {
10230 return -TARGET_EINVAL;
10231 }
bellard579a97f2007-11-11 14:26:47 +000010232 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10233 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010234 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010235 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010236 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10237 }
10238 break;
bellard31e31b82003-02-18 22:55:36 +000010239 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010240 ret = get_errno(sched_getscheduler(arg1));
10241 break;
bellard31e31b82003-02-18 22:55:36 +000010242 case TARGET_NR_sched_yield:
10243 ret = get_errno(sched_yield());
10244 break;
10245 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010246 ret = get_errno(sched_get_priority_max(arg1));
10247 break;
bellard31e31b82003-02-18 22:55:36 +000010248 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010249 ret = get_errno(sched_get_priority_min(arg1));
10250 break;
bellard31e31b82003-02-18 22:55:36 +000010251 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010252 {
bellard5cd43932003-03-29 16:54:36 +000010253 struct timespec ts;
10254 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10255 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010256 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010257 }
10258 }
10259 break;
bellard31e31b82003-02-18 22:55:36 +000010260 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010261 {
bellard1b6b0292003-03-22 17:31:38 +000010262 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010263 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010264 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010265 if (is_error(ret) && arg2) {
10266 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010267 }
10268 }
10269 break;
thse5febef2007-04-01 18:31:35 +000010270#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010271 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010272 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010273#endif
10274#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010275 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010276 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010277#endif
bellard31e31b82003-02-18 22:55:36 +000010278 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010279 switch (arg1) {
10280 case PR_GET_PDEATHSIG:
10281 {
10282 int deathsig;
10283 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10284 if (!is_error(ret) && arg2
10285 && put_user_ual(deathsig, arg2)) {
10286 goto efault;
thse5574482007-02-11 20:03:13 +000010287 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010288 break;
10289 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010290#ifdef PR_GET_NAME
10291 case PR_GET_NAME:
10292 {
10293 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10294 if (!name) {
10295 goto efault;
10296 }
10297 ret = get_errno(prctl(arg1, (unsigned long)name,
10298 arg3, arg4, arg5));
10299 unlock_user(name, arg2, 16);
10300 break;
10301 }
10302 case PR_SET_NAME:
10303 {
10304 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10305 if (!name) {
10306 goto efault;
10307 }
10308 ret = get_errno(prctl(arg1, (unsigned long)name,
10309 arg3, arg4, arg5));
10310 unlock_user(name, arg2, 0);
10311 break;
10312 }
10313#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +000010314 default:
10315 /* Most prctl options have no pointer arguments */
10316 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10317 break;
10318 }
ths39b9aae2007-02-11 18:36:44 +000010319 break;
bellardd2fd1af2007-11-14 18:08:56 +000010320#ifdef TARGET_NR_arch_prctl
10321 case TARGET_NR_arch_prctl:
10322#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10323 ret = do_arch_prctl(cpu_env, arg1, arg2);
10324 break;
10325#else
10326 goto unimplemented;
10327#endif
10328#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010329#ifdef TARGET_NR_pread64
10330 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +000010331 if (regpairs_aligned(cpu_env)) {
10332 arg4 = arg5;
10333 arg5 = arg6;
10334 }
aurel32f2c7ba12008-03-28 22:32:06 +000010335 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10336 goto efault;
10337 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10338 unlock_user(p, arg2, ret);
10339 break;
10340 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +000010341 if (regpairs_aligned(cpu_env)) {
10342 arg4 = arg5;
10343 arg5 = arg6;
10344 }
aurel32f2c7ba12008-03-28 22:32:06 +000010345 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10346 goto efault;
10347 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10348 unlock_user(p, arg2, 0);
10349 break;
10350#endif
bellard31e31b82003-02-18 22:55:36 +000010351 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010352 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10353 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010354 ret = get_errno(sys_getcwd1(p, arg2));
10355 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010356 break;
10357 case TARGET_NR_capget:
10358 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010359 {
10360 struct target_user_cap_header *target_header;
10361 struct target_user_cap_data *target_data = NULL;
10362 struct __user_cap_header_struct header;
10363 struct __user_cap_data_struct data[2];
10364 struct __user_cap_data_struct *dataptr = NULL;
10365 int i, target_datalen;
10366 int data_items = 1;
10367
10368 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10369 goto efault;
10370 }
10371 header.version = tswap32(target_header->version);
10372 header.pid = tswap32(target_header->pid);
10373
Peter Maydellec864872014-03-19 16:07:30 +000010374 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010375 /* Version 2 and up takes pointer to two user_data structs */
10376 data_items = 2;
10377 }
10378
10379 target_datalen = sizeof(*target_data) * data_items;
10380
10381 if (arg2) {
10382 if (num == TARGET_NR_capget) {
10383 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10384 } else {
10385 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10386 }
10387 if (!target_data) {
10388 unlock_user_struct(target_header, arg1, 0);
10389 goto efault;
10390 }
10391
10392 if (num == TARGET_NR_capset) {
10393 for (i = 0; i < data_items; i++) {
10394 data[i].effective = tswap32(target_data[i].effective);
10395 data[i].permitted = tswap32(target_data[i].permitted);
10396 data[i].inheritable = tswap32(target_data[i].inheritable);
10397 }
10398 }
10399
10400 dataptr = data;
10401 }
10402
10403 if (num == TARGET_NR_capget) {
10404 ret = get_errno(capget(&header, dataptr));
10405 } else {
10406 ret = get_errno(capset(&header, dataptr));
10407 }
10408
10409 /* The kernel always updates version for both capget and capset */
10410 target_header->version = tswap32(header.version);
10411 unlock_user_struct(target_header, arg1, 1);
10412
10413 if (arg2) {
10414 if (num == TARGET_NR_capget) {
10415 for (i = 0; i < data_items; i++) {
10416 target_data[i].effective = tswap32(data[i].effective);
10417 target_data[i].permitted = tswap32(data[i].permitted);
10418 target_data[i].inheritable = tswap32(data[i].inheritable);
10419 }
10420 unlock_user(target_data, arg2, target_datalen);
10421 } else {
10422 unlock_user(target_data, arg2, 0);
10423 }
10424 }
10425 break;
10426 }
bellard31e31b82003-02-18 22:55:36 +000010427 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010428 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010429 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010430
10431#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010432 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010433 {
10434 off_t *offp = NULL;
10435 off_t off;
10436 if (arg3) {
10437 ret = get_user_sal(off, arg3);
10438 if (is_error(ret)) {
10439 break;
10440 }
10441 offp = &off;
10442 }
10443 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10444 if (!is_error(ret) && arg3) {
10445 abi_long ret2 = put_user_sal(off, arg3);
10446 if (is_error(ret2)) {
10447 ret = ret2;
10448 }
10449 }
10450 break;
10451 }
10452#ifdef TARGET_NR_sendfile64
10453 case TARGET_NR_sendfile64:
10454 {
10455 off_t *offp = NULL;
10456 off_t off;
10457 if (arg3) {
10458 ret = get_user_s64(off, arg3);
10459 if (is_error(ret)) {
10460 break;
10461 }
10462 offp = &off;
10463 }
10464 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10465 if (!is_error(ret) && arg3) {
10466 abi_long ret2 = put_user_s64(off, arg3);
10467 if (is_error(ret2)) {
10468 ret = ret2;
10469 }
10470 }
10471 break;
10472 }
10473#endif
10474#else
10475 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010476#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010477 case TARGET_NR_sendfile64:
10478#endif
bellard5cd43932003-03-29 16:54:36 +000010479 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010480#endif
10481
bellardebc05482003-09-30 21:08:41 +000010482#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010483 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010484 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010485#endif
10486#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010487 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010488 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010489#endif
bellard048f6b42005-11-26 18:47:20 +000010490#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010491 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +000010492 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
10493 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010494 break;
bellard048f6b42005-11-26 18:47:20 +000010495#endif
bellardebc05482003-09-30 21:08:41 +000010496#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010497 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010498 {
10499 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010500 int resource = target_to_host_resource(arg1);
10501 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010502 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010503 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010504 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10505 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010506 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10507 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010508 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010509 }
10510 break;
10511 }
bellardebc05482003-09-30 21:08:41 +000010512#endif
bellarda315a142005-01-30 22:59:18 +000010513#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010514 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010515 if (!(p = lock_user_string(arg1)))
10516 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010517 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10518 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010519 break;
bellarda315a142005-01-30 22:59:18 +000010520#endif
10521#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010522 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010523 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010524 break;
bellarda315a142005-01-30 22:59:18 +000010525#endif
10526#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010527 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010528 if (!(p = lock_user_string(arg1)))
10529 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010530 ret = get_errno(stat(path(p), &st));
10531 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010532 if (!is_error(ret))
10533 ret = host_to_target_stat64(cpu_env, arg2, &st);
10534 break;
bellarda315a142005-01-30 22:59:18 +000010535#endif
10536#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010537 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +000010538 if (!(p = lock_user_string(arg1)))
10539 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010540 ret = get_errno(lstat(path(p), &st));
10541 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010542 if (!is_error(ret))
10543 ret = host_to_target_stat64(cpu_env, arg2, &st);
10544 break;
bellarda315a142005-01-30 22:59:18 +000010545#endif
10546#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010547 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010548 ret = get_errno(fstat(arg1, &st));
10549 if (!is_error(ret))
10550 ret = host_to_target_stat64(cpu_env, arg2, &st);
10551 break;
bellardec86b0f2003-04-11 00:15:04 +000010552#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010553#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010554#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010555 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010556#endif
10557#ifdef TARGET_NR_newfstatat
10558 case TARGET_NR_newfstatat:
10559#endif
balrog6a24a772008-09-20 02:23:36 +000010560 if (!(p = lock_user_string(arg2)))
10561 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010562 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010563 if (!is_error(ret))
10564 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010565 break;
bellarda315a142005-01-30 22:59:18 +000010566#endif
Chen Gang704eff62015-08-21 05:37:33 +080010567#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010568 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010569 if (!(p = lock_user_string(arg1)))
10570 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010571 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10572 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010573 break;
Chen Gang704eff62015-08-21 05:37:33 +080010574#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010575#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010576 case TARGET_NR_getuid:
10577 ret = get_errno(high2lowuid(getuid()));
10578 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010579#endif
10580#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010581 case TARGET_NR_getgid:
10582 ret = get_errno(high2lowgid(getgid()));
10583 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010584#endif
10585#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010586 case TARGET_NR_geteuid:
10587 ret = get_errno(high2lowuid(geteuid()));
10588 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010589#endif
10590#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010591 case TARGET_NR_getegid:
10592 ret = get_errno(high2lowgid(getegid()));
10593 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010594#endif
bellard67867302003-11-23 17:05:30 +000010595 case TARGET_NR_setreuid:
10596 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
10597 break;
10598 case TARGET_NR_setregid:
10599 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
10600 break;
10601 case TARGET_NR_getgroups:
10602 {
10603 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010604 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010605 gid_t *grouplist;
10606 int i;
10607
10608 grouplist = alloca(gidsetsize * sizeof(gid_t));
10609 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010610 if (gidsetsize == 0)
10611 break;
bellard67867302003-11-23 17:05:30 +000010612 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010613 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010614 if (!target_grouplist)
10615 goto efault;
balroga2155fc2008-09-20 02:12:08 +000010616 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010617 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010618 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010619 }
10620 }
10621 break;
10622 case TARGET_NR_setgroups:
10623 {
10624 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010625 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010626 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010627 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010628 if (gidsetsize) {
10629 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010630 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010631 if (!target_grouplist) {
10632 ret = -TARGET_EFAULT;
10633 goto fail;
10634 }
10635 for (i = 0; i < gidsetsize; i++) {
10636 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10637 }
10638 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010639 }
bellard67867302003-11-23 17:05:30 +000010640 ret = get_errno(setgroups(gidsetsize, grouplist));
10641 }
10642 break;
10643 case TARGET_NR_fchown:
10644 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
10645 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010646#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010647 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010648 if (!(p = lock_user_string(arg2)))
10649 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010650 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10651 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010652 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000010653 break;
10654#endif
bellard67867302003-11-23 17:05:30 +000010655#ifdef TARGET_NR_setresuid
10656 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010657 ret = get_errno(sys_setresuid(low2highuid(arg1),
10658 low2highuid(arg2),
10659 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010660 break;
10661#endif
10662#ifdef TARGET_NR_getresuid
10663 case TARGET_NR_getresuid:
10664 {
pbrook53a59602006-03-25 19:31:22 +000010665 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010666 ret = get_errno(getresuid(&ruid, &euid, &suid));
10667 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010668 if (put_user_id(high2lowuid(ruid), arg1)
10669 || put_user_id(high2lowuid(euid), arg2)
10670 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000010671 goto efault;
bellard67867302003-11-23 17:05:30 +000010672 }
10673 }
10674 break;
10675#endif
10676#ifdef TARGET_NR_getresgid
10677 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010678 ret = get_errno(sys_setresgid(low2highgid(arg1),
10679 low2highgid(arg2),
10680 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010681 break;
10682#endif
10683#ifdef TARGET_NR_getresgid
10684 case TARGET_NR_getresgid:
10685 {
pbrook53a59602006-03-25 19:31:22 +000010686 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010687 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10688 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010689 if (put_user_id(high2lowgid(rgid), arg1)
10690 || put_user_id(high2lowgid(egid), arg2)
10691 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000010692 goto efault;
bellard67867302003-11-23 17:05:30 +000010693 }
10694 }
10695 break;
10696#endif
Chen Gang704eff62015-08-21 05:37:33 +080010697#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000010698 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000010699 if (!(p = lock_user_string(arg1)))
10700 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010701 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
10702 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010703 break;
Chen Gang704eff62015-08-21 05:37:33 +080010704#endif
bellard67867302003-11-23 17:05:30 +000010705 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010706 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000010707 break;
10708 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010709 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000010710 break;
10711 case TARGET_NR_setfsuid:
10712 ret = get_errno(setfsuid(arg1));
10713 break;
10714 case TARGET_NR_setfsgid:
10715 ret = get_errno(setfsgid(arg1));
10716 break;
bellard67867302003-11-23 17:05:30 +000010717
bellarda315a142005-01-30 22:59:18 +000010718#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000010719 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000010720 if (!(p = lock_user_string(arg1)))
10721 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010722 ret = get_errno(lchown(p, arg2, arg3));
10723 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010724 break;
bellarda315a142005-01-30 22:59:18 +000010725#endif
10726#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000010727 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000010728 ret = get_errno(getuid());
10729 break;
bellarda315a142005-01-30 22:59:18 +000010730#endif
aurel3264b4d282008-11-14 17:20:15 +000010731
10732#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
10733 /* Alpha specific */
10734 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010735 {
10736 uid_t euid;
10737 euid=geteuid();
10738 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
10739 }
aurel3264b4d282008-11-14 17:20:15 +000010740 ret = get_errno(getuid());
10741 break;
10742#endif
10743#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
10744 /* Alpha specific */
10745 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010746 {
10747 uid_t egid;
10748 egid=getegid();
10749 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
10750 }
aurel3264b4d282008-11-14 17:20:15 +000010751 ret = get_errno(getgid());
10752 break;
10753#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080010754#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
10755 /* Alpha specific */
10756 case TARGET_NR_osf_getsysinfo:
10757 ret = -TARGET_EOPNOTSUPP;
10758 switch (arg1) {
10759 case TARGET_GSI_IEEE_FP_CONTROL:
10760 {
10761 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
10762
10763 /* Copied from linux ieee_fpcr_to_swcr. */
10764 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
10765 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
10766 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
10767 | SWCR_TRAP_ENABLE_DZE
10768 | SWCR_TRAP_ENABLE_OVF);
10769 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
10770 | SWCR_TRAP_ENABLE_INE);
10771 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
10772 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
10773
10774 if (put_user_u64 (swcr, arg2))
10775 goto efault;
10776 ret = 0;
10777 }
10778 break;
10779
10780 /* case GSI_IEEE_STATE_AT_SIGNAL:
10781 -- Not implemented in linux kernel.
10782 case GSI_UACPROC:
10783 -- Retrieves current unaligned access state; not much used.
10784 case GSI_PROC_TYPE:
10785 -- Retrieves implver information; surely not used.
10786 case GSI_GET_HWRPB:
10787 -- Grabs a copy of the HWRPB; surely not used.
10788 */
10789 }
10790 break;
10791#endif
10792#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
10793 /* Alpha specific */
10794 case TARGET_NR_osf_setsysinfo:
10795 ret = -TARGET_EOPNOTSUPP;
10796 switch (arg1) {
10797 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010798 {
10799 uint64_t swcr, fpcr, orig_fpcr;
10800
Richard Henderson6e06d512012-06-01 09:08:21 -070010801 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080010802 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070010803 }
10804 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010805 fpcr = orig_fpcr & FPCR_DYN_MASK;
10806
10807 /* Copied from linux ieee_swcr_to_fpcr. */
10808 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
10809 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
10810 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
10811 | SWCR_TRAP_ENABLE_DZE
10812 | SWCR_TRAP_ENABLE_OVF)) << 48;
10813 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
10814 | SWCR_TRAP_ENABLE_INE)) << 57;
10815 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
10816 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
10817
Richard Henderson6e06d512012-06-01 09:08:21 -070010818 cpu_alpha_store_fpcr(cpu_env, fpcr);
10819 ret = 0;
10820 }
10821 break;
10822
10823 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
10824 {
10825 uint64_t exc, fpcr, orig_fpcr;
10826 int si_code;
10827
10828 if (get_user_u64(exc, arg2)) {
10829 goto efault;
10830 }
10831
10832 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
10833
10834 /* We only add to the exception status here. */
10835 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
10836
10837 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010838 ret = 0;
10839
Richard Henderson6e06d512012-06-01 09:08:21 -070010840 /* Old exceptions are not signaled. */
10841 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010842
Richard Henderson6e06d512012-06-01 09:08:21 -070010843 /* If any exceptions set by this call,
10844 and are unmasked, send a signal. */
10845 si_code = 0;
10846 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
10847 si_code = TARGET_FPE_FLTRES;
10848 }
10849 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
10850 si_code = TARGET_FPE_FLTUND;
10851 }
10852 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
10853 si_code = TARGET_FPE_FLTOVF;
10854 }
10855 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
10856 si_code = TARGET_FPE_FLTDIV;
10857 }
10858 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
10859 si_code = TARGET_FPE_FLTINV;
10860 }
10861 if (si_code != 0) {
10862 target_siginfo_t info;
10863 info.si_signo = SIGFPE;
10864 info.si_errno = 0;
10865 info.si_code = si_code;
10866 info._sifields._sigfault._addr
10867 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010010868 queue_signal((CPUArchState *)cpu_env, info.si_signo,
10869 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010870 }
10871 }
10872 break;
10873
10874 /* case SSI_NVPAIRS:
10875 -- Used with SSIN_UACPROC to enable unaligned accesses.
10876 case SSI_IEEE_STATE_AT_SIGNAL:
10877 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
10878 -- Not implemented in linux kernel
10879 */
10880 }
10881 break;
10882#endif
10883#ifdef TARGET_NR_osf_sigprocmask
10884 /* Alpha specific. */
10885 case TARGET_NR_osf_sigprocmask:
10886 {
10887 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010010888 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080010889 sigset_t set, oldset;
10890
10891 switch(arg1) {
10892 case TARGET_SIG_BLOCK:
10893 how = SIG_BLOCK;
10894 break;
10895 case TARGET_SIG_UNBLOCK:
10896 how = SIG_UNBLOCK;
10897 break;
10898 case TARGET_SIG_SETMASK:
10899 how = SIG_SETMASK;
10900 break;
10901 default:
10902 ret = -TARGET_EINVAL;
10903 goto fail;
10904 }
10905 mask = arg2;
10906 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010010907 ret = do_sigprocmask(how, &set, &oldset);
10908 if (!ret) {
10909 host_to_target_old_sigset(&mask, &oldset);
10910 ret = mask;
10911 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080010912 }
10913 break;
10914#endif
aurel3264b4d282008-11-14 17:20:15 +000010915
bellarda315a142005-01-30 22:59:18 +000010916#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000010917 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000010918 ret = get_errno(getgid());
10919 break;
bellarda315a142005-01-30 22:59:18 +000010920#endif
10921#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000010922 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000010923 ret = get_errno(geteuid());
10924 break;
bellarda315a142005-01-30 22:59:18 +000010925#endif
10926#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000010927 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000010928 ret = get_errno(getegid());
10929 break;
bellarda315a142005-01-30 22:59:18 +000010930#endif
10931#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000010932 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000010933 ret = get_errno(setreuid(arg1, arg2));
10934 break;
bellarda315a142005-01-30 22:59:18 +000010935#endif
10936#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000010937 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000010938 ret = get_errno(setregid(arg1, arg2));
10939 break;
bellarda315a142005-01-30 22:59:18 +000010940#endif
10941#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000010942 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000010943 {
10944 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010945 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010946 gid_t *grouplist;
10947 int i;
10948
10949 grouplist = alloca(gidsetsize * sizeof(gid_t));
10950 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010951 if (gidsetsize == 0)
10952 break;
bellard99c475a2005-01-31 20:45:13 +000010953 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010954 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
10955 if (!target_grouplist) {
10956 ret = -TARGET_EFAULT;
10957 goto fail;
10958 }
balroga2155fc2008-09-20 02:12:08 +000010959 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000010960 target_grouplist[i] = tswap32(grouplist[i]);
10961 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000010962 }
10963 }
10964 break;
bellarda315a142005-01-30 22:59:18 +000010965#endif
10966#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000010967 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000010968 {
10969 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000010970 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000010971 gid_t *grouplist;
10972 int i;
ths3b46e622007-09-17 08:09:54 +000010973
bellard99c475a2005-01-31 20:45:13 +000010974 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000010975 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
10976 if (!target_grouplist) {
10977 ret = -TARGET_EFAULT;
10978 goto fail;
10979 }
bellard99c475a2005-01-31 20:45:13 +000010980 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000010981 grouplist[i] = tswap32(target_grouplist[i]);
10982 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000010983 ret = get_errno(setgroups(gidsetsize, grouplist));
10984 }
10985 break;
bellarda315a142005-01-30 22:59:18 +000010986#endif
10987#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000010988 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000010989 ret = get_errno(fchown(arg1, arg2, arg3));
10990 break;
bellarda315a142005-01-30 22:59:18 +000010991#endif
10992#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000010993 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010994 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000010995 break;
bellarda315a142005-01-30 22:59:18 +000010996#endif
10997#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000010998 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000010999 {
pbrook53a59602006-03-25 19:31:22 +000011000 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011001 ret = get_errno(getresuid(&ruid, &euid, &suid));
11002 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011003 if (put_user_u32(ruid, arg1)
11004 || put_user_u32(euid, arg2)
11005 || put_user_u32(suid, arg3))
11006 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011007 }
11008 }
11009 break;
bellarda315a142005-01-30 22:59:18 +000011010#endif
11011#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011012 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011013 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011014 break;
bellarda315a142005-01-30 22:59:18 +000011015#endif
11016#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011017 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011018 {
pbrook53a59602006-03-25 19:31:22 +000011019 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011020 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11021 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011022 if (put_user_u32(rgid, arg1)
11023 || put_user_u32(egid, arg2)
11024 || put_user_u32(sgid, arg3))
11025 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011026 }
11027 }
11028 break;
bellarda315a142005-01-30 22:59:18 +000011029#endif
11030#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011031 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011032 if (!(p = lock_user_string(arg1)))
11033 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011034 ret = get_errno(chown(p, arg2, arg3));
11035 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011036 break;
bellarda315a142005-01-30 22:59:18 +000011037#endif
11038#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011039 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011040 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011041 break;
bellarda315a142005-01-30 22:59:18 +000011042#endif
11043#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011044 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011045 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011046 break;
bellarda315a142005-01-30 22:59:18 +000011047#endif
11048#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011049 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011050 ret = get_errno(setfsuid(arg1));
11051 break;
bellarda315a142005-01-30 22:59:18 +000011052#endif
11053#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011054 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011055 ret = get_errno(setfsgid(arg1));
11056 break;
bellarda315a142005-01-30 22:59:18 +000011057#endif
bellard67867302003-11-23 17:05:30 +000011058
bellard31e31b82003-02-18 22:55:36 +000011059 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011060 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011061#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011062 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011063 {
11064 void *a;
11065 ret = -TARGET_EFAULT;
11066 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
11067 goto efault;
11068 if (!(p = lock_user_string(arg3)))
11069 goto mincore_fail;
11070 ret = get_errno(mincore(a, arg2, p));
11071 unlock_user(p, arg3, ret);
11072 mincore_fail:
11073 unlock_user(a, arg1, 0);
11074 }
11075 break;
bellardffa65c32004-01-04 23:57:22 +000011076#endif
aurel32408321b2008-10-01 21:46:32 +000011077#ifdef TARGET_NR_arm_fadvise64_64
11078 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011079 /* arm_fadvise64_64 looks like fadvise64_64 but
11080 * with different argument order: fd, advice, offset, len
11081 * rather than the usual fd, offset, len, advice.
11082 * Note that offset and len are both 64-bit so appear as
11083 * pairs of 32-bit registers.
11084 */
11085 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11086 target_offset64(arg5, arg6), arg2);
11087 ret = -host_to_target_errno(ret);
11088 break;
aurel32408321b2008-10-01 21:46:32 +000011089#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011090
11091#if TARGET_ABI_BITS == 32
11092
11093#ifdef TARGET_NR_fadvise64_64
11094 case TARGET_NR_fadvise64_64:
11095 /* 6 args: fd, offset (high, low), len (high, low), advice */
11096 if (regpairs_aligned(cpu_env)) {
11097 /* offset is in (3,4), len in (5,6) and advice in 7 */
11098 arg2 = arg3;
11099 arg3 = arg4;
11100 arg4 = arg5;
11101 arg5 = arg6;
11102 arg6 = arg7;
11103 }
11104 ret = -host_to_target_errno(posix_fadvise(arg1,
11105 target_offset64(arg2, arg3),
11106 target_offset64(arg4, arg5),
11107 arg6));
11108 break;
11109#endif
11110
11111#ifdef TARGET_NR_fadvise64
11112 case TARGET_NR_fadvise64:
11113 /* 5 args: fd, offset (high, low), len, advice */
11114 if (regpairs_aligned(cpu_env)) {
11115 /* offset is in (3,4), len in 5 and advice in 6 */
11116 arg2 = arg3;
11117 arg3 = arg4;
11118 arg4 = arg5;
11119 arg5 = arg6;
11120 }
11121 ret = -host_to_target_errno(posix_fadvise(arg1,
11122 target_offset64(arg2, arg3),
11123 arg4, arg5));
11124 break;
11125#endif
11126
11127#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011128#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011129#ifdef TARGET_NR_fadvise64_64
11130 case TARGET_NR_fadvise64_64:
11131#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011132#ifdef TARGET_NR_fadvise64
11133 case TARGET_NR_fadvise64:
11134#endif
11135#ifdef TARGET_S390X
11136 switch (arg4) {
11137 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11138 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11139 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11140 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11141 default: break;
11142 }
11143#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011144 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11145 break;
aurel32408321b2008-10-01 21:46:32 +000011146#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011147#endif /* end of 64-bit ABI fadvise handling */
11148
bellardffa65c32004-01-04 23:57:22 +000011149#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011150 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011151 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011152 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011153 This will break MADV_DONTNEED.
11154 This is a hint, so ignoring and returning success is ok. */
11155 ret = get_errno(0);
11156 break;
bellardffa65c32004-01-04 23:57:22 +000011157#endif
blueswir1992f48a2007-10-14 16:27:31 +000011158#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011159 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011160 {
thsb1e341e2007-03-20 21:50:52 +000011161 int cmd;
bellard77e46722003-04-29 20:39:06 +000011162 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011163 from_flock64_fn *copyfrom = copy_from_user_flock64;
11164 to_flock64_fn *copyto = copy_to_user_flock64;
11165
pbrookce4defa2006-02-09 16:49:55 +000011166#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010011167 if (((CPUARMState *)cpu_env)->eabi) {
11168 copyfrom = copy_from_user_eabi_flock64;
11169 copyto = copy_to_user_eabi_flock64;
11170 }
pbrookce4defa2006-02-09 16:49:55 +000011171#endif
bellard77e46722003-04-29 20:39:06 +000011172
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011173 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011174 if (cmd == -TARGET_EINVAL) {
11175 ret = cmd;
11176 break;
11177 }
thsb1e341e2007-03-20 21:50:52 +000011178
bellard60cd49d2003-03-16 22:53:56 +000011179 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011180 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011181 ret = copyfrom(&fl, arg3);
11182 if (ret) {
11183 break;
ths58134272007-03-31 18:59:32 +000011184 }
thsb1e341e2007-03-20 21:50:52 +000011185 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011186 if (ret == 0) {
11187 ret = copyto(arg3, &fl);
11188 }
bellard77e46722003-04-29 20:39:06 +000011189 break;
11190
thsb1e341e2007-03-20 21:50:52 +000011191 case TARGET_F_SETLK64:
11192 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011193 ret = copyfrom(&fl, arg3);
11194 if (ret) {
11195 break;
pbrookce4defa2006-02-09 16:49:55 +000011196 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011197 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011198 break;
bellard60cd49d2003-03-16 22:53:56 +000011199 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011200 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011201 break;
11202 }
bellard77e46722003-04-29 20:39:06 +000011203 break;
11204 }
bellard60cd49d2003-03-16 22:53:56 +000011205#endif
ths7d600c82006-12-08 01:32:58 +000011206#ifdef TARGET_NR_cacheflush
11207 case TARGET_NR_cacheflush:
11208 /* self-modifying code is handled automatically, so nothing needed */
11209 ret = 0;
11210 break;
11211#endif
bellardebc05482003-09-30 21:08:41 +000011212#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011213 case TARGET_NR_security:
11214 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011215#endif
bellardc573ff62004-01-04 15:51:36 +000011216#ifdef TARGET_NR_getpagesize
11217 case TARGET_NR_getpagesize:
11218 ret = TARGET_PAGE_SIZE;
11219 break;
11220#endif
bellard31e31b82003-02-18 22:55:36 +000011221 case TARGET_NR_gettid:
11222 ret = get_errno(gettid());
11223 break;
thse5febef2007-04-01 18:31:35 +000011224#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011225 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011226#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030011227 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000011228 arg2 = arg3;
11229 arg3 = arg4;
11230 arg4 = arg5;
11231 }
aurel322054ac92008-10-13 21:08:07 +000011232 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
11233#else
11234 ret = get_errno(readahead(arg1, arg2, arg3));
11235#endif
11236 break;
thse5febef2007-04-01 18:31:35 +000011237#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011238#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011239#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011240 case TARGET_NR_listxattr:
11241 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011242 {
11243 void *p, *b = 0;
11244 if (arg2) {
11245 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11246 if (!b) {
11247 ret = -TARGET_EFAULT;
11248 break;
11249 }
11250 }
11251 p = lock_user_string(arg1);
11252 if (p) {
11253 if (num == TARGET_NR_listxattr) {
11254 ret = get_errno(listxattr(p, b, arg3));
11255 } else {
11256 ret = get_errno(llistxattr(p, b, arg3));
11257 }
11258 } else {
11259 ret = -TARGET_EFAULT;
11260 }
11261 unlock_user(p, arg1, 0);
11262 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011263 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011264 }
11265 case TARGET_NR_flistxattr:
11266 {
11267 void *b = 0;
11268 if (arg2) {
11269 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11270 if (!b) {
11271 ret = -TARGET_EFAULT;
11272 break;
11273 }
11274 }
11275 ret = get_errno(flistxattr(arg1, b, arg3));
11276 unlock_user(b, arg2, arg3);
11277 break;
11278 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011279 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011280 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011281 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011282 void *p, *n, *v = 0;
11283 if (arg3) {
11284 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11285 if (!v) {
11286 ret = -TARGET_EFAULT;
11287 break;
11288 }
11289 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011290 p = lock_user_string(arg1);
11291 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011292 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011293 if (num == TARGET_NR_setxattr) {
11294 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11295 } else {
11296 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11297 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011298 } else {
11299 ret = -TARGET_EFAULT;
11300 }
11301 unlock_user(p, arg1, 0);
11302 unlock_user(n, arg2, 0);
11303 unlock_user(v, arg3, 0);
11304 }
11305 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011306 case TARGET_NR_fsetxattr:
11307 {
11308 void *n, *v = 0;
11309 if (arg3) {
11310 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11311 if (!v) {
11312 ret = -TARGET_EFAULT;
11313 break;
11314 }
11315 }
11316 n = lock_user_string(arg2);
11317 if (n) {
11318 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11319 } else {
11320 ret = -TARGET_EFAULT;
11321 }
11322 unlock_user(n, arg2, 0);
11323 unlock_user(v, arg3, 0);
11324 }
11325 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011326 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011327 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011328 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011329 void *p, *n, *v = 0;
11330 if (arg3) {
11331 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11332 if (!v) {
11333 ret = -TARGET_EFAULT;
11334 break;
11335 }
11336 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011337 p = lock_user_string(arg1);
11338 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011339 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011340 if (num == TARGET_NR_getxattr) {
11341 ret = get_errno(getxattr(p, n, v, arg4));
11342 } else {
11343 ret = get_errno(lgetxattr(p, n, v, arg4));
11344 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011345 } else {
11346 ret = -TARGET_EFAULT;
11347 }
11348 unlock_user(p, arg1, 0);
11349 unlock_user(n, arg2, 0);
11350 unlock_user(v, arg3, arg4);
11351 }
11352 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011353 case TARGET_NR_fgetxattr:
11354 {
11355 void *n, *v = 0;
11356 if (arg3) {
11357 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11358 if (!v) {
11359 ret = -TARGET_EFAULT;
11360 break;
11361 }
11362 }
11363 n = lock_user_string(arg2);
11364 if (n) {
11365 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11366 } else {
11367 ret = -TARGET_EFAULT;
11368 }
11369 unlock_user(n, arg2, 0);
11370 unlock_user(v, arg3, arg4);
11371 }
11372 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011373 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011374 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011375 {
11376 void *p, *n;
11377 p = lock_user_string(arg1);
11378 n = lock_user_string(arg2);
11379 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011380 if (num == TARGET_NR_removexattr) {
11381 ret = get_errno(removexattr(p, n));
11382 } else {
11383 ret = get_errno(lremovexattr(p, n));
11384 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011385 } else {
11386 ret = -TARGET_EFAULT;
11387 }
11388 unlock_user(p, arg1, 0);
11389 unlock_user(n, arg2, 0);
11390 }
11391 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011392 case TARGET_NR_fremovexattr:
11393 {
11394 void *n;
11395 n = lock_user_string(arg2);
11396 if (n) {
11397 ret = get_errno(fremovexattr(arg1, n));
11398 } else {
11399 ret = -TARGET_EFAULT;
11400 }
11401 unlock_user(n, arg2, 0);
11402 }
11403 break;
bellardebc05482003-09-30 21:08:41 +000011404#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011405#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011406#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011407 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011408#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011409 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011410 ret = 0;
11411 break;
edgar_iglef967792009-01-07 14:19:38 +000011412#elif defined(TARGET_CRIS)
11413 if (arg1 & 0xff)
11414 ret = -TARGET_EINVAL;
11415 else {
11416 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11417 ret = 0;
11418 }
11419 break;
bellard8d18e892007-11-14 15:18:40 +000011420#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11421 ret = do_set_thread_area(cpu_env, arg1);
11422 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011423#elif defined(TARGET_M68K)
11424 {
Andreas Färber0429a972013-08-26 18:14:44 +020011425 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011426 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011427 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011428 break;
11429 }
ths6f5b89a2007-03-02 20:48:00 +000011430#else
11431 goto unimplemented_nowarn;
11432#endif
11433#endif
11434#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011435 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011436#if defined(TARGET_I386) && defined(TARGET_ABI32)
11437 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011438 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011439#elif defined(TARGET_M68K)
11440 {
Andreas Färber0429a972013-08-26 18:14:44 +020011441 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011442 ret = ts->tp_value;
11443 break;
11444 }
bellard8d18e892007-11-14 15:18:40 +000011445#else
bellard5cd43932003-03-29 16:54:36 +000011446 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011447#endif
bellard8d18e892007-11-14 15:18:40 +000011448#endif
bellard48dc41e2006-06-21 18:15:50 +000011449#ifdef TARGET_NR_getdomainname
11450 case TARGET_NR_getdomainname:
11451 goto unimplemented_nowarn;
11452#endif
ths6f5b89a2007-03-02 20:48:00 +000011453
thsb5906f92007-03-19 13:32:45 +000011454#ifdef TARGET_NR_clock_gettime
11455 case TARGET_NR_clock_gettime:
11456 {
11457 struct timespec ts;
11458 ret = get_errno(clock_gettime(arg1, &ts));
11459 if (!is_error(ret)) {
11460 host_to_target_timespec(arg2, &ts);
11461 }
11462 break;
11463 }
11464#endif
11465#ifdef TARGET_NR_clock_getres
11466 case TARGET_NR_clock_getres:
11467 {
11468 struct timespec ts;
11469 ret = get_errno(clock_getres(arg1, &ts));
11470 if (!is_error(ret)) {
11471 host_to_target_timespec(arg2, &ts);
11472 }
11473 break;
11474 }
11475#endif
pbrook63d76512008-05-29 13:43:29 +000011476#ifdef TARGET_NR_clock_nanosleep
11477 case TARGET_NR_clock_nanosleep:
11478 {
11479 struct timespec ts;
11480 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011481 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11482 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011483 if (arg4)
11484 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011485
11486#if defined(TARGET_PPC)
11487 /* clock_nanosleep is odd in that it returns positive errno values.
11488 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011489 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011490 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11491 }
11492#endif
pbrook63d76512008-05-29 13:43:29 +000011493 break;
11494 }
11495#endif
thsb5906f92007-03-19 13:32:45 +000011496
ths6f5b89a2007-03-02 20:48:00 +000011497#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11498 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011499 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11500 break;
ths6f5b89a2007-03-02 20:48:00 +000011501#endif
11502
ths4cae1d12007-07-12 11:06:53 +000011503 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011504 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011505 break;
ths4cae1d12007-07-12 11:06:53 +000011506
ths71455572007-06-21 21:45:30 +000011507 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011508 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011509 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011510 break;
ths71455572007-06-21 21:45:30 +000011511
ths4f2b1fe2007-06-21 21:57:12 +000011512#ifdef TARGET_NR_set_robust_list
11513 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011514 case TARGET_NR_get_robust_list:
11515 /* The ABI for supporting robust futexes has userspace pass
11516 * the kernel a pointer to a linked list which is updated by
11517 * userspace after the syscall; the list is walked by the kernel
11518 * when the thread exits. Since the linked list in QEMU guest
11519 * memory isn't a valid linked list for the host and we have
11520 * no way to reliably intercept the thread-death event, we can't
11521 * support these. Silently return ENOSYS so that guest userspace
11522 * falls back to a non-robust futex implementation (which should
11523 * be OK except in the corner case of the guest crashing while
11524 * holding a mutex that is shared with another process via
11525 * shared memory).
11526 */
11527 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011528#endif
11529
Peter Maydell1acae9f2013-07-02 14:04:12 +010011530#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011531 case TARGET_NR_utimensat:
11532 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011533 struct timespec *tsp, ts[2];
11534 if (!arg3) {
11535 tsp = NULL;
11536 } else {
11537 target_to_host_timespec(ts, arg3);
11538 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11539 tsp = ts;
11540 }
ths9007f0e2007-09-25 17:50:37 +000011541 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011542 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011543 else {
bellard579a97f2007-11-11 14:26:47 +000011544 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011545 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011546 goto fail;
11547 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011548 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011549 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011550 }
11551 }
11552 break;
11553#endif
pbrookbd0c5662008-05-29 14:34:11 +000011554 case TARGET_NR_futex:
11555 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11556 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011557#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011558 case TARGET_NR_inotify_init:
11559 ret = get_errno(sys_inotify_init());
11560 break;
11561#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011562#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011563#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11564 case TARGET_NR_inotify_init1:
11565 ret = get_errno(sys_inotify_init1(arg1));
11566 break;
11567#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011568#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011569#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011570 case TARGET_NR_inotify_add_watch:
11571 p = lock_user_string(arg2);
11572 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11573 unlock_user(p, arg2, 0);
11574 break;
11575#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011576#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011577 case TARGET_NR_inotify_rm_watch:
11578 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
11579 break;
11580#endif
ths9007f0e2007-09-25 17:50:37 +000011581
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011582#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011583 case TARGET_NR_mq_open:
11584 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011585 struct mq_attr posix_mq_attr;
11586 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000011587
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011588 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
11589 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
11590 goto efault;
Tom Mustab6ce1f62014-08-12 13:53:36 -050011591 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011592 p = lock_user_string(arg1 - 1);
11593 if (!p) {
11594 goto efault;
11595 }
11596 ret = get_errno(mq_open(p, host_flags, arg3, &posix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000011597 unlock_user (p, arg1, 0);
11598 }
11599 break;
11600
11601 case TARGET_NR_mq_unlink:
11602 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010011603 if (!p) {
11604 ret = -TARGET_EFAULT;
11605 break;
11606 }
aurel3224e10032009-04-15 16:11:43 +000011607 ret = get_errno(mq_unlink(p));
11608 unlock_user (p, arg1, 0);
11609 break;
11610
11611 case TARGET_NR_mq_timedsend:
11612 {
11613 struct timespec ts;
11614
11615 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11616 if (arg5 != 0) {
11617 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011618 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011619 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011620 } else {
11621 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011622 }
aurel3224e10032009-04-15 16:11:43 +000011623 unlock_user (p, arg2, arg3);
11624 }
11625 break;
11626
11627 case TARGET_NR_mq_timedreceive:
11628 {
11629 struct timespec ts;
11630 unsigned int prio;
11631
11632 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11633 if (arg5 != 0) {
11634 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011635 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11636 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011637 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011638 } else {
11639 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11640 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011641 }
aurel3224e10032009-04-15 16:11:43 +000011642 unlock_user (p, arg2, arg3);
11643 if (arg4 != 0)
11644 put_user_u32(prio, arg4);
11645 }
11646 break;
11647
11648 /* Not implemented for now... */
11649/* case TARGET_NR_mq_notify: */
11650/* break; */
11651
11652 case TARGET_NR_mq_getsetattr:
11653 {
11654 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11655 ret = 0;
11656 if (arg3 != 0) {
11657 ret = mq_getattr(arg1, &posix_mq_attr_out);
11658 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11659 }
11660 if (arg2 != 0) {
11661 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
11662 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
11663 }
11664
11665 }
11666 break;
11667#endif
11668
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011669#ifdef CONFIG_SPLICE
11670#ifdef TARGET_NR_tee
11671 case TARGET_NR_tee:
11672 {
11673 ret = get_errno(tee(arg1,arg2,arg3,arg4));
11674 }
11675 break;
11676#endif
11677#ifdef TARGET_NR_splice
11678 case TARGET_NR_splice:
11679 {
11680 loff_t loff_in, loff_out;
11681 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010011682 if (arg2) {
11683 if (get_user_u64(loff_in, arg2)) {
11684 goto efault;
11685 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011686 ploff_in = &loff_in;
11687 }
Andreas Schwab17644b32015-03-10 17:11:35 +010011688 if (arg4) {
11689 if (get_user_u64(loff_out, arg4)) {
11690 goto efault;
11691 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011692 ploff_out = &loff_out;
11693 }
11694 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010011695 if (arg2) {
11696 if (put_user_u64(loff_in, arg2)) {
11697 goto efault;
11698 }
11699 }
11700 if (arg4) {
11701 if (put_user_u64(loff_out, arg4)) {
11702 goto efault;
11703 }
11704 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011705 }
11706 break;
11707#endif
11708#ifdef TARGET_NR_vmsplice
11709 case TARGET_NR_vmsplice:
11710 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011711 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11712 if (vec != NULL) {
11713 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
11714 unlock_iovec(vec, arg2, arg3, 0);
11715 } else {
11716 ret = -host_to_target_errno(errno);
11717 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011718 }
11719 break;
11720#endif
11721#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030011722#ifdef CONFIG_EVENTFD
11723#if defined(TARGET_NR_eventfd)
11724 case TARGET_NR_eventfd:
11725 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020011726 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011727 break;
11728#endif
11729#if defined(TARGET_NR_eventfd2)
11730 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020011731 {
11732 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
11733 if (arg2 & TARGET_O_NONBLOCK) {
11734 host_flags |= O_NONBLOCK;
11735 }
11736 if (arg2 & TARGET_O_CLOEXEC) {
11737 host_flags |= O_CLOEXEC;
11738 }
11739 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020011740 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030011741 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020011742 }
Riku Voipioc2882b92009-08-12 15:08:24 +030011743#endif
11744#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030011745#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
11746 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010011747#if TARGET_ABI_BITS == 32
11748 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
11749 target_offset64(arg5, arg6)));
11750#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030011751 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010011752#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030011753 break;
11754#endif
Peter Maydellc727f472011-01-06 11:05:10 +000011755#if defined(CONFIG_SYNC_FILE_RANGE)
11756#if defined(TARGET_NR_sync_file_range)
11757 case TARGET_NR_sync_file_range:
11758#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030011759#if defined(TARGET_MIPS)
11760 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11761 target_offset64(arg5, arg6), arg7));
11762#else
Peter Maydellc727f472011-01-06 11:05:10 +000011763 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
11764 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030011765#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000011766#else
11767 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
11768#endif
11769 break;
11770#endif
11771#if defined(TARGET_NR_sync_file_range2)
11772 case TARGET_NR_sync_file_range2:
11773 /* This is like sync_file_range but the arguments are reordered */
11774#if TARGET_ABI_BITS == 32
11775 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11776 target_offset64(arg5, arg6), arg2));
11777#else
11778 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
11779#endif
11780 break;
11781#endif
11782#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020011783#if defined(TARGET_NR_signalfd4)
11784 case TARGET_NR_signalfd4:
11785 ret = do_signalfd4(arg1, arg2, arg4);
11786 break;
11787#endif
11788#if defined(TARGET_NR_signalfd)
11789 case TARGET_NR_signalfd:
11790 ret = do_signalfd4(arg1, arg2, 0);
11791 break;
11792#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000011793#if defined(CONFIG_EPOLL)
11794#if defined(TARGET_NR_epoll_create)
11795 case TARGET_NR_epoll_create:
11796 ret = get_errno(epoll_create(arg1));
11797 break;
11798#endif
11799#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
11800 case TARGET_NR_epoll_create1:
11801 ret = get_errno(epoll_create1(arg1));
11802 break;
11803#endif
11804#if defined(TARGET_NR_epoll_ctl)
11805 case TARGET_NR_epoll_ctl:
11806 {
11807 struct epoll_event ep;
11808 struct epoll_event *epp = 0;
11809 if (arg4) {
11810 struct target_epoll_event *target_ep;
11811 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
11812 goto efault;
11813 }
11814 ep.events = tswap32(target_ep->events);
11815 /* The epoll_data_t union is just opaque data to the kernel,
11816 * so we transfer all 64 bits across and need not worry what
11817 * actual data type it is.
11818 */
11819 ep.data.u64 = tswap64(target_ep->data.u64);
11820 unlock_user_struct(target_ep, arg4, 0);
11821 epp = &ep;
11822 }
11823 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
11824 break;
11825 }
11826#endif
11827
Peter Maydell227f0212016-06-06 19:58:11 +010011828#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011829#if defined(TARGET_NR_epoll_wait)
11830 case TARGET_NR_epoll_wait:
11831#endif
Peter Maydell227f0212016-06-06 19:58:11 +010011832#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011833 case TARGET_NR_epoll_pwait:
11834#endif
11835 {
11836 struct target_epoll_event *target_ep;
11837 struct epoll_event *ep;
11838 int epfd = arg1;
11839 int maxevents = arg3;
11840 int timeout = arg4;
11841
Peter Maydell2ba7fae32016-07-18 15:35:59 +010011842 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
11843 ret = -TARGET_EINVAL;
11844 break;
11845 }
11846
Peter Maydell3b6edd12011-02-15 18:35:05 +000011847 target_ep = lock_user(VERIFY_WRITE, arg2,
11848 maxevents * sizeof(struct target_epoll_event), 1);
11849 if (!target_ep) {
11850 goto efault;
11851 }
11852
Peter Maydell04c95f42016-07-18 15:36:00 +010011853 ep = g_try_new(struct epoll_event, maxevents);
11854 if (!ep) {
11855 unlock_user(target_ep, arg2, 0);
11856 ret = -TARGET_ENOMEM;
11857 break;
11858 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000011859
11860 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010011861#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000011862 case TARGET_NR_epoll_pwait:
11863 {
11864 target_sigset_t *target_set;
11865 sigset_t _set, *set = &_set;
11866
11867 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010011868 if (arg6 != sizeof(target_sigset_t)) {
11869 ret = -TARGET_EINVAL;
11870 break;
11871 }
11872
Peter Maydell3b6edd12011-02-15 18:35:05 +000011873 target_set = lock_user(VERIFY_READ, arg5,
11874 sizeof(target_sigset_t), 1);
11875 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010011876 ret = -TARGET_EFAULT;
11877 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000011878 }
11879 target_to_host_sigset(set, target_set);
11880 unlock_user(target_set, arg5, 0);
11881 } else {
11882 set = NULL;
11883 }
11884
Peter Maydell227f0212016-06-06 19:58:11 +010011885 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11886 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011887 break;
11888 }
11889#endif
11890#if defined(TARGET_NR_epoll_wait)
11891 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010011892 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
11893 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000011894 break;
11895#endif
11896 default:
11897 ret = -TARGET_ENOSYS;
11898 }
11899 if (!is_error(ret)) {
11900 int i;
11901 for (i = 0; i < ret; i++) {
11902 target_ep[i].events = tswap32(ep[i].events);
11903 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
11904 }
Peter Maydell04c95f42016-07-18 15:36:00 +010011905 unlock_user(target_ep, arg2,
11906 ret * sizeof(struct target_epoll_event));
11907 } else {
11908 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000011909 }
Peter Maydell04c95f42016-07-18 15:36:00 +010011910 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000011911 break;
11912 }
11913#endif
11914#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010011915#ifdef TARGET_NR_prlimit64
11916 case TARGET_NR_prlimit64:
11917 {
11918 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
11919 struct target_rlimit64 *target_rnew, *target_rold;
11920 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010011921 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010011922 if (arg3) {
11923 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
11924 goto efault;
11925 }
11926 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
11927 rnew.rlim_max = tswap64(target_rnew->rlim_max);
11928 unlock_user_struct(target_rnew, arg3, 0);
11929 rnewp = &rnew;
11930 }
11931
Felix Janda95018012014-12-02 22:11:17 +010011932 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010011933 if (!is_error(ret) && arg4) {
11934 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
11935 goto efault;
11936 }
11937 target_rold->rlim_cur = tswap64(rold.rlim_cur);
11938 target_rold->rlim_max = tswap64(rold.rlim_max);
11939 unlock_user_struct(target_rold, arg4, 1);
11940 }
11941 break;
11942 }
11943#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070011944#ifdef TARGET_NR_gethostname
11945 case TARGET_NR_gethostname:
11946 {
11947 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
11948 if (name) {
11949 ret = get_errno(gethostname(name, arg2));
11950 unlock_user(name, arg1, arg2);
11951 } else {
11952 ret = -TARGET_EFAULT;
11953 }
11954 break;
11955 }
11956#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011957#ifdef TARGET_NR_atomic_cmpxchg_32
11958 case TARGET_NR_atomic_cmpxchg_32:
11959 {
11960 /* should use start_exclusive from main.c */
11961 abi_ulong mem_value;
11962 if (get_user_u32(mem_value, arg6)) {
11963 target_siginfo_t info;
11964 info.si_signo = SIGSEGV;
11965 info.si_errno = 0;
11966 info.si_code = TARGET_SEGV_MAPERR;
11967 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011968 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11969 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011970 ret = 0xdeadbeef;
11971
11972 }
11973 if (mem_value == arg2)
11974 put_user_u32(arg1, arg6);
11975 ret = mem_value;
11976 break;
11977 }
11978#endif
11979#ifdef TARGET_NR_atomic_barrier
11980 case TARGET_NR_atomic_barrier:
11981 {
11982 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000011983 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030011984 break;
11985 }
11986#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011987
11988#ifdef TARGET_NR_timer_create
11989 case TARGET_NR_timer_create:
11990 {
11991 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
11992
11993 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011994
11995 int clkid = arg1;
11996 int timer_index = next_free_host_timer();
11997
11998 if (timer_index < 0) {
11999 ret = -TARGET_EAGAIN;
12000 } else {
12001 timer_t *phtimer = g_posix_timers + timer_index;
12002
12003 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012004 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012005 ret = target_to_host_sigevent(phost_sevp, arg2);
12006 if (ret != 0) {
12007 break;
12008 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012009 }
12010
12011 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12012 if (ret) {
12013 phtimer = NULL;
12014 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012015 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012016 goto efault;
12017 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012018 }
12019 }
12020 break;
12021 }
12022#endif
12023
12024#ifdef TARGET_NR_timer_settime
12025 case TARGET_NR_timer_settime:
12026 {
12027 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12028 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012029 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012030
Alexander Grafaecc8862014-11-10 21:33:03 +010012031 if (timerid < 0) {
12032 ret = timerid;
12033 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012034 ret = -TARGET_EINVAL;
12035 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012036 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012037 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12038
12039 target_to_host_itimerspec(&hspec_new, arg3);
12040 ret = get_errno(
12041 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
12042 host_to_target_itimerspec(arg2, &hspec_old);
12043 }
12044 break;
12045 }
12046#endif
12047
12048#ifdef TARGET_NR_timer_gettime
12049 case TARGET_NR_timer_gettime:
12050 {
12051 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012052 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012053
Alexander Grafaecc8862014-11-10 21:33:03 +010012054 if (timerid < 0) {
12055 ret = timerid;
12056 } else if (!arg2) {
12057 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012058 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012059 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012060 struct itimerspec hspec;
12061 ret = get_errno(timer_gettime(htimer, &hspec));
12062
12063 if (host_to_target_itimerspec(arg2, &hspec)) {
12064 ret = -TARGET_EFAULT;
12065 }
12066 }
12067 break;
12068 }
12069#endif
12070
12071#ifdef TARGET_NR_timer_getoverrun
12072 case TARGET_NR_timer_getoverrun:
12073 {
12074 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012075 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012076
Alexander Grafaecc8862014-11-10 21:33:03 +010012077 if (timerid < 0) {
12078 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012079 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012080 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012081 ret = get_errno(timer_getoverrun(htimer));
12082 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012083 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012084 break;
12085 }
12086#endif
12087
12088#ifdef TARGET_NR_timer_delete
12089 case TARGET_NR_timer_delete:
12090 {
12091 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012092 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012093
Alexander Grafaecc8862014-11-10 21:33:03 +010012094 if (timerid < 0) {
12095 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012096 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012097 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012098 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012099 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012100 }
12101 break;
12102 }
12103#endif
12104
Riku Voipio51834342014-06-22 11:25:42 +010012105#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12106 case TARGET_NR_timerfd_create:
12107 ret = get_errno(timerfd_create(arg1,
12108 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12109 break;
12110#endif
12111
12112#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12113 case TARGET_NR_timerfd_gettime:
12114 {
12115 struct itimerspec its_curr;
12116
12117 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12118
12119 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12120 goto efault;
12121 }
12122 }
12123 break;
12124#endif
12125
12126#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12127 case TARGET_NR_timerfd_settime:
12128 {
12129 struct itimerspec its_new, its_old, *p_new;
12130
12131 if (arg3) {
12132 if (target_to_host_itimerspec(&its_new, arg3)) {
12133 goto efault;
12134 }
12135 p_new = &its_new;
12136 } else {
12137 p_new = NULL;
12138 }
12139
12140 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12141
12142 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12143 goto efault;
12144 }
12145 }
12146 break;
12147#endif
12148
Paul Burtonab31cda2014-06-22 11:25:43 +010012149#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12150 case TARGET_NR_ioprio_get:
12151 ret = get_errno(ioprio_get(arg1, arg2));
12152 break;
12153#endif
12154
12155#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12156 case TARGET_NR_ioprio_set:
12157 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12158 break;
12159#endif
12160
Riku Voipio9af5c902014-08-12 15:58:57 +030012161#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12162 case TARGET_NR_setns:
12163 ret = get_errno(setns(arg1, arg2));
12164 break;
12165#endif
12166#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12167 case TARGET_NR_unshare:
12168 ret = get_errno(unshare(arg1));
12169 break;
12170#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012171#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12172 case TARGET_NR_kcmp:
12173 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12174 break;
12175#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012176
bellard31e31b82003-02-18 22:55:36 +000012177 default:
12178 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000012179 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012180#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 +000012181 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012182#endif
ths0da46a62007-10-20 20:23:07 +000012183 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012184 break;
12185 }
bellard579a97f2007-11-11 14:26:47 +000012186fail:
bellardc573ff62004-01-04 15:51:36 +000012187#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012188 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012189#endif
thsb92c47c2007-11-01 00:07:38 +000012190 if(do_strace)
12191 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020012192 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012193 return ret;
bellard579a97f2007-11-11 14:26:47 +000012194efault:
12195 ret = -TARGET_EFAULT;
12196 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012197}