blob: 909dde6de67aa6faa7c7a0b68fdca3daca0e08b2 [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>
Helge Delleree1ac3a2017-02-18 23:31:30 +010060#include <linux/icmpv6.h>
61#include <linux/errqueue.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020062#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030063#ifdef CONFIG_TIMERFD
64#include <sys/timerfd.h>
65#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020066#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000067#include <sys/gmon.h>
68#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030069#ifdef CONFIG_EVENTFD
70#include <sys/eventfd.h>
71#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000072#ifdef CONFIG_EPOLL
73#include <sys/epoll.h>
74#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070075#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010076#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070077#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000078#ifdef CONFIG_SENDFILE
79#include <sys/sendfile.h>
80#endif
bellard31e31b82003-02-18 22:55:36 +000081
82#define termios host_termios
83#define winsize host_winsize
84#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000085#define sgttyb host_sgttyb /* same as target */
86#define tchars host_tchars /* same as target */
87#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000088
89#include <linux/termios.h>
90#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000091#include <linux/cdrom.h>
92#include <linux/hdreg.h>
93#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000094#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000095#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030096#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000097#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000098#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000099#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200100#include <linux/fb.h>
101#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100102#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000103#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100104#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200105#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100106#include <linux/blkpg.h>
Laurent Viviera82ea932016-06-27 00:18:22 +0200107#include <netpacket/packet.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200108#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200109#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200110#include <linux/rtnetlink.h>
Laurent Vivierc5dff282016-06-27 18:54:30 +0200111#include <linux/if_bridge.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200112#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200113#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000114#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200115#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000116
bellard3ef693a2003-03-23 20:17:16 +0000117#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000118
Peter Maydell5ea2fc82016-08-02 18:41:27 +0100119#ifndef CLONE_IO
120#define CLONE_IO 0x80000000 /* Clone io context */
121#endif
122
123/* We can't directly call the host clone syscall, because this will
124 * badly confuse libc (breaking mutexes, for example). So we must
125 * divide clone flags into:
126 * * flag combinations that look like pthread_create()
127 * * flag combinations that look like fork()
128 * * flags we can implement within QEMU itself
129 * * flags we can't support and will return an error for
130 */
131/* For thread creation, all these flags must be present; for
132 * fork, none must be present.
133 */
134#define CLONE_THREAD_FLAGS \
135 (CLONE_VM | CLONE_FS | CLONE_FILES | \
136 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
137
138/* These flags are ignored:
139 * CLONE_DETACHED is now ignored by the kernel;
140 * CLONE_IO is just an optimisation hint to the I/O scheduler
141 */
142#define CLONE_IGNORED_FLAGS \
143 (CLONE_DETACHED | CLONE_IO)
144
145/* Flags for fork which we can implement within QEMU itself */
146#define CLONE_OPTIONAL_FORK_FLAGS \
147 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
148 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
149
150/* Flags for thread creation which we can implement within QEMU itself */
151#define CLONE_OPTIONAL_THREAD_FLAGS \
152 (CLONE_SETTLS | CLONE_PARENT_SETTID | \
153 CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
154
155#define CLONE_INVALID_FORK_FLAGS \
156 (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
157
158#define CLONE_INVALID_THREAD_FLAGS \
159 (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \
160 CLONE_IGNORED_FLAGS))
161
162/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
163 * have almost all been allocated. We cannot support any of
164 * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
165 * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
166 * The checks against the invalid thread masks above will catch these.
167 * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
168 */
pbrook30813ce2008-06-02 15:45:44 +0000169
bellard72f03902003-02-18 23:33:18 +0000170//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100171/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
172 * once. This exercises the codepaths for restart.
173 */
174//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000175
bellard1a9353d2003-03-16 20:28:50 +0000176//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000177#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
178#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000179
bellard70a194b2003-08-11 22:20:16 +0000180#undef _syscall0
181#undef _syscall1
182#undef _syscall2
183#undef _syscall3
184#undef _syscall4
185#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000186#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000187
bellard83fcb512006-06-14 13:37:16 +0000188#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000189static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000190{ \
191 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000192}
193
bellard83fcb512006-06-14 13:37:16 +0000194#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000195static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000196{ \
197 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000198}
199
bellard83fcb512006-06-14 13:37:16 +0000200#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000201static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000202{ \
203 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000204}
205
bellard83fcb512006-06-14 13:37:16 +0000206#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000207static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000208{ \
209 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000210}
211
bellard83fcb512006-06-14 13:37:16 +0000212#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000213static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000214{ \
215 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000216}
217
bellard83fcb512006-06-14 13:37:16 +0000218#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
219 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000220static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000221{ \
222 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000223}
bellard83fcb512006-06-14 13:37:16 +0000224
225
226#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
227 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000228static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
229 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000230{ \
231 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
232}
233
bellard70a194b2003-08-11 22:20:16 +0000234
bellard31e31b82003-02-18 22:55:36 +0000235#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000236#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000237#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000238#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000239#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000240#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000241#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000242#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000243#define __NR_sys_inotify_init __NR_inotify_init
244#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
245#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000246
Alexander Graf42a39fb2011-04-15 17:32:45 +0200247#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
248 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000249#define __NR__llseek __NR_lseek
250#endif
251
James Hogana29e5ba2014-03-25 21:51:08 +0000252/* Newer kernel ports have llseek() instead of _llseek() */
253#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
254#define TARGET_NR__llseek TARGET_NR_llseek
255#endif
256
bellard72f03902003-02-18 23:33:18 +0000257#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000258_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000259#else
ths0da46a62007-10-20 20:23:07 +0000260/* This is a replacement for the host gettid() and must return a host
261 errno. */
bellard72f03902003-02-18 23:33:18 +0000262static int gettid(void) {
263 return -ENOSYS;
264}
265#endif
Chen Gang704eff62015-08-21 05:37:33 +0800266#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000267_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100268#endif
269#if !defined(__NR_getdents) || \
270 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000271_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
272#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700273#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000274_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
275 loff_t *, res, uint, wh);
276#endif
277_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
278_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000279#ifdef __NR_exit_group
280_syscall1(int,exit_group,int,error_code)
281#endif
282#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
283_syscall1(int,set_tid_address,int *,tidptr)
284#endif
aurel323b3f24a2009-04-15 16:12:13 +0000285#if defined(TARGET_NR_futex) && defined(__NR_futex)
286_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
287 const struct timespec *,timeout,int *,uaddr2,int,val3)
288#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500289#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
290_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
291 unsigned long *, user_mask_ptr);
292#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
293_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
294 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200295_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
296 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000297_syscall2(int, capget, struct __user_cap_header_struct *, header,
298 struct __user_cap_data_struct *, data);
299_syscall2(int, capset, struct __user_cap_header_struct *, header,
300 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100301#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
302_syscall2(int, ioprio_get, int, which, int, who)
303#endif
304#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
305_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
306#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100307#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
308_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
309#endif
aurel323b3f24a2009-04-15 16:12:13 +0000310
Laurent Vivier2f147882016-09-25 22:20:20 +0200311#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
312_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
313 unsigned long, idx1, unsigned long, idx2)
314#endif
315
aurel323b3f24a2009-04-15 16:12:13 +0000316static bitmask_transtbl fcntl_flags_tbl[] = {
317 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
318 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
319 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
320 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
321 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
322 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
323 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
324 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700325 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000326 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
327 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
328 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
329 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000330#if defined(O_DIRECT)
331 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
332#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700333#if defined(O_NOATIME)
334 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
335#endif
336#if defined(O_CLOEXEC)
337 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
338#endif
339#if defined(O_PATH)
340 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
341#endif
342 /* Don't terminate the list prematurely on 64-bit host+guest. */
343#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
344 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
345#endif
aurel323b3f24a2009-04-15 16:12:13 +0000346 { 0, 0, 0, 0 }
347};
348
Michal Privoznik60c6b792016-08-19 10:06:40 +0200349enum {
350 QEMU_IFLA_BR_UNSPEC,
351 QEMU_IFLA_BR_FORWARD_DELAY,
352 QEMU_IFLA_BR_HELLO_TIME,
353 QEMU_IFLA_BR_MAX_AGE,
354 QEMU_IFLA_BR_AGEING_TIME,
355 QEMU_IFLA_BR_STP_STATE,
356 QEMU_IFLA_BR_PRIORITY,
357 QEMU_IFLA_BR_VLAN_FILTERING,
358 QEMU_IFLA_BR_VLAN_PROTOCOL,
359 QEMU_IFLA_BR_GROUP_FWD_MASK,
360 QEMU_IFLA_BR_ROOT_ID,
361 QEMU_IFLA_BR_BRIDGE_ID,
362 QEMU_IFLA_BR_ROOT_PORT,
363 QEMU_IFLA_BR_ROOT_PATH_COST,
364 QEMU_IFLA_BR_TOPOLOGY_CHANGE,
365 QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
366 QEMU_IFLA_BR_HELLO_TIMER,
367 QEMU_IFLA_BR_TCN_TIMER,
368 QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER,
369 QEMU_IFLA_BR_GC_TIMER,
370 QEMU_IFLA_BR_GROUP_ADDR,
371 QEMU_IFLA_BR_FDB_FLUSH,
372 QEMU_IFLA_BR_MCAST_ROUTER,
373 QEMU_IFLA_BR_MCAST_SNOOPING,
374 QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR,
375 QEMU_IFLA_BR_MCAST_QUERIER,
376 QEMU_IFLA_BR_MCAST_HASH_ELASTICITY,
377 QEMU_IFLA_BR_MCAST_HASH_MAX,
378 QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT,
379 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT,
380 QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL,
381 QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL,
382 QEMU_IFLA_BR_MCAST_QUERIER_INTVL,
383 QEMU_IFLA_BR_MCAST_QUERY_INTVL,
384 QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
385 QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
386 QEMU_IFLA_BR_NF_CALL_IPTABLES,
387 QEMU_IFLA_BR_NF_CALL_IP6TABLES,
388 QEMU_IFLA_BR_NF_CALL_ARPTABLES,
389 QEMU_IFLA_BR_VLAN_DEFAULT_PVID,
390 QEMU_IFLA_BR_PAD,
391 QEMU_IFLA_BR_VLAN_STATS_ENABLED,
392 QEMU_IFLA_BR_MCAST_STATS_ENABLED,
393 QEMU___IFLA_BR_MAX,
394};
395
396enum {
397 QEMU_IFLA_UNSPEC,
398 QEMU_IFLA_ADDRESS,
399 QEMU_IFLA_BROADCAST,
400 QEMU_IFLA_IFNAME,
401 QEMU_IFLA_MTU,
402 QEMU_IFLA_LINK,
403 QEMU_IFLA_QDISC,
404 QEMU_IFLA_STATS,
405 QEMU_IFLA_COST,
406 QEMU_IFLA_PRIORITY,
407 QEMU_IFLA_MASTER,
408 QEMU_IFLA_WIRELESS,
409 QEMU_IFLA_PROTINFO,
410 QEMU_IFLA_TXQLEN,
411 QEMU_IFLA_MAP,
412 QEMU_IFLA_WEIGHT,
413 QEMU_IFLA_OPERSTATE,
414 QEMU_IFLA_LINKMODE,
415 QEMU_IFLA_LINKINFO,
416 QEMU_IFLA_NET_NS_PID,
417 QEMU_IFLA_IFALIAS,
418 QEMU_IFLA_NUM_VF,
419 QEMU_IFLA_VFINFO_LIST,
420 QEMU_IFLA_STATS64,
421 QEMU_IFLA_VF_PORTS,
422 QEMU_IFLA_PORT_SELF,
423 QEMU_IFLA_AF_SPEC,
424 QEMU_IFLA_GROUP,
425 QEMU_IFLA_NET_NS_FD,
426 QEMU_IFLA_EXT_MASK,
427 QEMU_IFLA_PROMISCUITY,
428 QEMU_IFLA_NUM_TX_QUEUES,
429 QEMU_IFLA_NUM_RX_QUEUES,
430 QEMU_IFLA_CARRIER,
431 QEMU_IFLA_PHYS_PORT_ID,
432 QEMU_IFLA_CARRIER_CHANGES,
433 QEMU_IFLA_PHYS_SWITCH_ID,
434 QEMU_IFLA_LINK_NETNSID,
435 QEMU_IFLA_PHYS_PORT_NAME,
436 QEMU_IFLA_PROTO_DOWN,
437 QEMU_IFLA_GSO_MAX_SEGS,
438 QEMU_IFLA_GSO_MAX_SIZE,
439 QEMU_IFLA_PAD,
440 QEMU_IFLA_XDP,
441 QEMU___IFLA_MAX
442};
443
444enum {
445 QEMU_IFLA_BRPORT_UNSPEC,
446 QEMU_IFLA_BRPORT_STATE,
447 QEMU_IFLA_BRPORT_PRIORITY,
448 QEMU_IFLA_BRPORT_COST,
449 QEMU_IFLA_BRPORT_MODE,
450 QEMU_IFLA_BRPORT_GUARD,
451 QEMU_IFLA_BRPORT_PROTECT,
452 QEMU_IFLA_BRPORT_FAST_LEAVE,
453 QEMU_IFLA_BRPORT_LEARNING,
454 QEMU_IFLA_BRPORT_UNICAST_FLOOD,
455 QEMU_IFLA_BRPORT_PROXYARP,
456 QEMU_IFLA_BRPORT_LEARNING_SYNC,
457 QEMU_IFLA_BRPORT_PROXYARP_WIFI,
458 QEMU_IFLA_BRPORT_ROOT_ID,
459 QEMU_IFLA_BRPORT_BRIDGE_ID,
460 QEMU_IFLA_BRPORT_DESIGNATED_PORT,
461 QEMU_IFLA_BRPORT_DESIGNATED_COST,
462 QEMU_IFLA_BRPORT_ID,
463 QEMU_IFLA_BRPORT_NO,
464 QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
465 QEMU_IFLA_BRPORT_CONFIG_PENDING,
466 QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER,
467 QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER,
468 QEMU_IFLA_BRPORT_HOLD_TIMER,
469 QEMU_IFLA_BRPORT_FLUSH,
470 QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
471 QEMU_IFLA_BRPORT_PAD,
472 QEMU___IFLA_BRPORT_MAX
473};
474
475enum {
476 QEMU_IFLA_INFO_UNSPEC,
477 QEMU_IFLA_INFO_KIND,
478 QEMU_IFLA_INFO_DATA,
479 QEMU_IFLA_INFO_XSTATS,
480 QEMU_IFLA_INFO_SLAVE_KIND,
481 QEMU_IFLA_INFO_SLAVE_DATA,
482 QEMU___IFLA_INFO_MAX,
483};
484
485enum {
486 QEMU_IFLA_INET_UNSPEC,
487 QEMU_IFLA_INET_CONF,
488 QEMU___IFLA_INET_MAX,
489};
490
491enum {
492 QEMU_IFLA_INET6_UNSPEC,
493 QEMU_IFLA_INET6_FLAGS,
494 QEMU_IFLA_INET6_CONF,
495 QEMU_IFLA_INET6_STATS,
496 QEMU_IFLA_INET6_MCAST,
497 QEMU_IFLA_INET6_CACHEINFO,
498 QEMU_IFLA_INET6_ICMP6STATS,
499 QEMU_IFLA_INET6_TOKEN,
500 QEMU_IFLA_INET6_ADDR_GEN_MODE,
501 QEMU___IFLA_INET6_MAX
502};
503
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100504typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100505typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200506typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100507 TargetFdDataFunc host_to_target_data;
508 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100509 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200510} TargetFdTrans;
511
512static TargetFdTrans **target_fd_trans;
513
514static unsigned int target_fd_max;
515
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200516static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
517{
518 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
519 return target_fd_trans[fd]->target_to_host_data;
520 }
521 return NULL;
522}
523
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100524static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200525{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100526 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100527 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200528 }
529 return NULL;
530}
531
Laurent Vivier7b36f782015-10-28 21:40:44 +0100532static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
533{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100534 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100535 return target_fd_trans[fd]->target_to_host_addr;
536 }
537 return NULL;
538}
539
Laurent Viviere36800c2015-10-02 14:48:09 +0200540static void fd_trans_register(int fd, TargetFdTrans *trans)
541{
542 unsigned int oldmax;
543
544 if (fd >= target_fd_max) {
545 oldmax = target_fd_max;
546 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100547 target_fd_trans = g_renew(TargetFdTrans *,
548 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200549 memset((void *)(target_fd_trans + oldmax), 0,
550 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
551 }
552 target_fd_trans[fd] = trans;
553}
554
555static void fd_trans_unregister(int fd)
556{
557 if (fd >= 0 && fd < target_fd_max) {
558 target_fd_trans[fd] = NULL;
559 }
560}
561
562static void fd_trans_dup(int oldfd, int newfd)
563{
564 fd_trans_unregister(newfd);
565 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
566 fd_trans_register(newfd, target_fd_trans[oldfd]);
567 }
568}
569
aurel323b3f24a2009-04-15 16:12:13 +0000570static int sys_getcwd1(char *buf, size_t size)
571{
572 if (getcwd(buf, size) == NULL) {
573 /* getcwd() sets errno */
574 return (-1);
575 }
aurel32aaf4ad32009-04-16 14:17:14 +0000576 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000577}
578
Peter Maydell1acae9f2013-07-02 14:04:12 +0100579#ifdef TARGET_NR_utimensat
Peter Maydell700fa582016-07-18 11:47:55 +0100580#if defined(__NR_utimensat)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100581#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000582_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
583 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100584#else
585static int sys_utimensat(int dirfd, const char *pathname,
586 const struct timespec times[2], int flags)
587{
588 errno = ENOSYS;
589 return -1;
590}
ths9007f0e2007-09-25 17:50:37 +0000591#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100592#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000593
594#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000595#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000596
aurel3239b59762008-10-01 21:46:50 +0000597#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000598static int sys_inotify_init(void)
599{
600 return (inotify_init());
601}
aurel3239b59762008-10-01 21:46:50 +0000602#endif
603#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000604static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
605{
606 return (inotify_add_watch(fd, pathname, mask));
607}
aurel3239b59762008-10-01 21:46:50 +0000608#endif
609#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000610static int sys_inotify_rm_watch(int fd, int32_t wd)
611{
aurel328690e422009-04-17 13:50:32 +0000612 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000613}
aurel3239b59762008-10-01 21:46:50 +0000614#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000615#ifdef CONFIG_INOTIFY1
616#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
617static int sys_inotify_init1(int flags)
618{
619 return (inotify_init1(flags));
620}
621#endif
622#endif
aurel323b3f24a2009-04-15 16:12:13 +0000623#else
624/* Userspace can usually survive runtime without inotify */
625#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000626#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000627#undef TARGET_NR_inotify_add_watch
628#undef TARGET_NR_inotify_rm_watch
629#endif /* CONFIG_INOTIFY */
630
Peter Maydell163a05a2011-06-27 17:44:52 +0100631#if defined(TARGET_NR_prlimit64)
632#ifndef __NR_prlimit64
633# define __NR_prlimit64 -1
634#endif
635#define __NR_sys_prlimit64 __NR_prlimit64
636/* The glibc rlimit structure may not be that used by the underlying syscall */
637struct host_rlimit64 {
638 uint64_t rlim_cur;
639 uint64_t rlim_max;
640};
641_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
642 const struct host_rlimit64 *, new_limit,
643 struct host_rlimit64 *, old_limit)
644#endif
645
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100646
647#if defined(TARGET_NR_timer_create)
648/* Maxiumum of 32 active POSIX timers allowed at any one time. */
649static timer_t g_posix_timers[32] = { 0, } ;
650
651static inline int next_free_host_timer(void)
652{
653 int k ;
654 /* FIXME: Does finding the next free slot require a lock? */
655 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
656 if (g_posix_timers[k] == 0) {
657 g_posix_timers[k] = (timer_t) 1;
658 return k;
659 }
660 }
661 return -1;
662}
663#endif
664
Riku Voipio48e515d2011-07-12 15:40:51 +0300665/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000666#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300667static inline int regpairs_aligned(void *cpu_env) {
668 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
669}
Aleksandar Markovicd7779ac2016-09-19 13:44:42 +0200670#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
Riku Voipio48e515d2011-07-12 15:40:51 +0300671static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000672#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
673/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
674 * of registers which translates to the same as ARM/MIPS, because we start with
675 * r3 as arg1 */
676static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300677#else
678static inline int regpairs_aligned(void *cpu_env) { return 0; }
679#endif
680
thsb92c47c2007-11-01 00:07:38 +0000681#define ERRNO_TABLE_SIZE 1200
682
683/* target_to_host_errno_table[] is initialized from
684 * host_to_target_errno_table[] in syscall_init(). */
685static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
686};
687
ths637947f2007-06-01 12:09:19 +0000688/*
thsfe8f0962007-07-12 10:59:21 +0000689 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000690 * minus the errnos that are not actually generic to all archs.
691 */
thsb92c47c2007-11-01 00:07:38 +0000692static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800693 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000694 [EIDRM] = TARGET_EIDRM,
695 [ECHRNG] = TARGET_ECHRNG,
696 [EL2NSYNC] = TARGET_EL2NSYNC,
697 [EL3HLT] = TARGET_EL3HLT,
698 [EL3RST] = TARGET_EL3RST,
699 [ELNRNG] = TARGET_ELNRNG,
700 [EUNATCH] = TARGET_EUNATCH,
701 [ENOCSI] = TARGET_ENOCSI,
702 [EL2HLT] = TARGET_EL2HLT,
703 [EDEADLK] = TARGET_EDEADLK,
704 [ENOLCK] = TARGET_ENOLCK,
705 [EBADE] = TARGET_EBADE,
706 [EBADR] = TARGET_EBADR,
707 [EXFULL] = TARGET_EXFULL,
708 [ENOANO] = TARGET_ENOANO,
709 [EBADRQC] = TARGET_EBADRQC,
710 [EBADSLT] = TARGET_EBADSLT,
711 [EBFONT] = TARGET_EBFONT,
712 [ENOSTR] = TARGET_ENOSTR,
713 [ENODATA] = TARGET_ENODATA,
714 [ETIME] = TARGET_ETIME,
715 [ENOSR] = TARGET_ENOSR,
716 [ENONET] = TARGET_ENONET,
717 [ENOPKG] = TARGET_ENOPKG,
718 [EREMOTE] = TARGET_EREMOTE,
719 [ENOLINK] = TARGET_ENOLINK,
720 [EADV] = TARGET_EADV,
721 [ESRMNT] = TARGET_ESRMNT,
722 [ECOMM] = TARGET_ECOMM,
723 [EPROTO] = TARGET_EPROTO,
724 [EDOTDOT] = TARGET_EDOTDOT,
725 [EMULTIHOP] = TARGET_EMULTIHOP,
726 [EBADMSG] = TARGET_EBADMSG,
727 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
728 [EOVERFLOW] = TARGET_EOVERFLOW,
729 [ENOTUNIQ] = TARGET_ENOTUNIQ,
730 [EBADFD] = TARGET_EBADFD,
731 [EREMCHG] = TARGET_EREMCHG,
732 [ELIBACC] = TARGET_ELIBACC,
733 [ELIBBAD] = TARGET_ELIBBAD,
734 [ELIBSCN] = TARGET_ELIBSCN,
735 [ELIBMAX] = TARGET_ELIBMAX,
736 [ELIBEXEC] = TARGET_ELIBEXEC,
737 [EILSEQ] = TARGET_EILSEQ,
738 [ENOSYS] = TARGET_ENOSYS,
739 [ELOOP] = TARGET_ELOOP,
740 [ERESTART] = TARGET_ERESTART,
741 [ESTRPIPE] = TARGET_ESTRPIPE,
742 [ENOTEMPTY] = TARGET_ENOTEMPTY,
743 [EUSERS] = TARGET_EUSERS,
744 [ENOTSOCK] = TARGET_ENOTSOCK,
745 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
746 [EMSGSIZE] = TARGET_EMSGSIZE,
747 [EPROTOTYPE] = TARGET_EPROTOTYPE,
748 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
749 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
750 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
751 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
752 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
753 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
754 [EADDRINUSE] = TARGET_EADDRINUSE,
755 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
756 [ENETDOWN] = TARGET_ENETDOWN,
757 [ENETUNREACH] = TARGET_ENETUNREACH,
758 [ENETRESET] = TARGET_ENETRESET,
759 [ECONNABORTED] = TARGET_ECONNABORTED,
760 [ECONNRESET] = TARGET_ECONNRESET,
761 [ENOBUFS] = TARGET_ENOBUFS,
762 [EISCONN] = TARGET_EISCONN,
763 [ENOTCONN] = TARGET_ENOTCONN,
764 [EUCLEAN] = TARGET_EUCLEAN,
765 [ENOTNAM] = TARGET_ENOTNAM,
766 [ENAVAIL] = TARGET_ENAVAIL,
767 [EISNAM] = TARGET_EISNAM,
768 [EREMOTEIO] = TARGET_EREMOTEIO,
Aleksandar Markovic0444a3b2016-09-19 13:44:43 +0200769 [EDQUOT] = TARGET_EDQUOT,
ths637947f2007-06-01 12:09:19 +0000770 [ESHUTDOWN] = TARGET_ESHUTDOWN,
771 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
772 [ETIMEDOUT] = TARGET_ETIMEDOUT,
773 [ECONNREFUSED] = TARGET_ECONNREFUSED,
774 [EHOSTDOWN] = TARGET_EHOSTDOWN,
775 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
776 [EALREADY] = TARGET_EALREADY,
777 [EINPROGRESS] = TARGET_EINPROGRESS,
778 [ESTALE] = TARGET_ESTALE,
779 [ECANCELED] = TARGET_ECANCELED,
780 [ENOMEDIUM] = TARGET_ENOMEDIUM,
781 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000782#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000783 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000784#endif
785#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000786 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000787#endif
788#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000789 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000790#endif
791#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000792 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000793#endif
794#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000795 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000796#endif
797#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000798 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000799#endif
Aleksandar Markovicda39db62016-09-22 18:56:56 +0200800#ifdef ENOMSG
801 [ENOMSG] = TARGET_ENOMSG,
802#endif
Richard Hendersonfe8ed7d2016-12-05 13:08:12 -0800803#ifdef ERKFILL
804 [ERFKILL] = TARGET_ERFKILL,
805#endif
806#ifdef EHWPOISON
807 [EHWPOISON] = TARGET_EHWPOISON,
808#endif
thsb92c47c2007-11-01 00:07:38 +0000809};
ths637947f2007-06-01 12:09:19 +0000810
811static inline int host_to_target_errno(int err)
812{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100813 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
814 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000815 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100816 }
ths637947f2007-06-01 12:09:19 +0000817 return err;
818}
819
thsb92c47c2007-11-01 00:07:38 +0000820static inline int target_to_host_errno(int err)
821{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100822 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
823 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000824 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100825 }
thsb92c47c2007-11-01 00:07:38 +0000826 return err;
827}
828
blueswir1992f48a2007-10-14 16:27:31 +0000829static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000830{
831 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000832 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000833 else
834 return ret;
835}
836
blueswir1992f48a2007-10-14 16:27:31 +0000837static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000838{
blueswir1992f48a2007-10-14 16:27:31 +0000839 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000840}
841
Peter Maydell7dcdaea2016-06-06 19:58:18 +0100842const char *target_strerror(int err)
thsb92c47c2007-11-01 00:07:38 +0000843{
Peter Maydellda2a34f2016-06-06 19:58:19 +0100844 if (err == TARGET_ERESTARTSYS) {
845 return "To be restarted";
846 }
847 if (err == TARGET_QEMU_ESIGRETURN) {
848 return "Successful exit from sigreturn";
849 }
850
Alexander Graf962b2892011-11-21 12:04:07 +0100851 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
852 return NULL;
853 }
thsb92c47c2007-11-01 00:07:38 +0000854 return strerror(target_to_host_errno(err));
855}
856
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100857#define safe_syscall0(type, name) \
858static type safe_##name(void) \
859{ \
860 return safe_syscall(__NR_##name); \
861}
862
863#define safe_syscall1(type, name, type1, arg1) \
864static type safe_##name(type1 arg1) \
865{ \
866 return safe_syscall(__NR_##name, arg1); \
867}
868
869#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
870static type safe_##name(type1 arg1, type2 arg2) \
871{ \
872 return safe_syscall(__NR_##name, arg1, arg2); \
873}
874
875#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
876static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
877{ \
878 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
879}
880
881#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
882 type4, arg4) \
883static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
884{ \
885 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
886}
887
888#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
889 type4, arg4, type5, arg5) \
890static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
891 type5 arg5) \
892{ \
893 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
894}
895
896#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
897 type4, arg4, type5, arg5, type6, arg6) \
898static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
899 type5 arg5, type6 arg6) \
900{ \
901 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
902}
903
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100904safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
905safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100906safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
907 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100908safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
909 struct rusage *, rusage)
910safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
911 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100912safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100913safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
914 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydella6130232016-06-06 19:58:10 +0100915safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
916 struct timespec *, tsp, const sigset_t *, sigmask,
917 size_t, sigsetsize)
Peter Maydell227f0212016-06-06 19:58:11 +0100918safe_syscall6(int, epoll_pwait, int, epfd, struct epoll_event *, events,
919 int, maxevents, int, timeout, const sigset_t *, sigmask,
920 size_t, sigsetsize)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100921safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
922 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100923safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100924safe_syscall2(int, kill, pid_t, pid, int, sig)
925safe_syscall2(int, tkill, int, tid, int, sig)
926safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100927safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
928safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Dejan Jovicevic0f263862016-10-11 11:52:46 +0200929safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
930 unsigned long, pos_l, unsigned long, pos_h)
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +0200931safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
932 unsigned long, pos_l, unsigned long, pos_h)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100933safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
934 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100935safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
936 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
937safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
938 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
939safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
940safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100941safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100942safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
943 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydellff6dc132016-06-06 19:58:13 +0100944safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
945 int, flags)
Peter Maydell9e518222016-06-06 19:58:09 +0100946safe_syscall2(int, nanosleep, const struct timespec *, req,
947 struct timespec *, rem)
948#ifdef TARGET_NR_clock_nanosleep
949safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
950 const struct timespec *, req, struct timespec *, rem)
951#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100952#ifdef __NR_msgsnd
953safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
954 int, flags)
955safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
956 long, msgtype, int, flags)
Peter Maydellffb7ee72016-06-06 19:58:12 +0100957safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
958 unsigned, nsops, const struct timespec *, timeout)
Peter Maydell89f9fe42016-06-06 19:58:05 +0100959#else
960/* This host kernel architecture uses a single ipc syscall; fake up
961 * wrappers for the sub-operations to hide this implementation detail.
962 * Annoyingly we can't include linux/ipc.h to get the constant definitions
963 * for the call parameter because some structs in there conflict with the
964 * sys/ipc.h ones. So we just define them here, and rely on them being
965 * the same for all host architectures.
966 */
Peter Maydellffb7ee72016-06-06 19:58:12 +0100967#define Q_SEMTIMEDOP 4
Peter Maydell89f9fe42016-06-06 19:58:05 +0100968#define Q_MSGSND 11
969#define Q_MSGRCV 12
970#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
971
972safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
973 void *, ptr, long, fifth)
974static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
975{
976 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
977}
978static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
979{
980 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
981}
Peter Maydellffb7ee72016-06-06 19:58:12 +0100982static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
983 const struct timespec *timeout)
984{
985 return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
986 (long)timeout);
987}
Peter Maydell89f9fe42016-06-06 19:58:05 +0100988#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100989#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
990safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
991 size_t, len, unsigned, prio, const struct timespec *, timeout)
992safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
993 size_t, len, unsigned *, prio, const struct timespec *, timeout)
994#endif
Peter Maydell49ca6f32016-06-06 19:58:14 +0100995/* We do ioctl like this rather than via safe_syscall3 to preserve the
996 * "third argument might be integer or pointer or not present" behaviour of
997 * the libc function.
998 */
999#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
Peter Maydell435da5e2016-06-13 11:22:05 +01001000/* Similarly for fcntl. Note that callers must always:
1001 * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
1002 * use the flock64 struct rather than unsuffixed flock
1003 * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
1004 */
1005#ifdef __NR_fcntl64
1006#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
1007#else
1008#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
1009#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +01001010
Paul Burton8289d112014-06-22 11:25:33 +01001011static inline int host_to_target_sock_type(int host_type)
1012{
1013 int target_type;
1014
1015 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
1016 case SOCK_DGRAM:
1017 target_type = TARGET_SOCK_DGRAM;
1018 break;
1019 case SOCK_STREAM:
1020 target_type = TARGET_SOCK_STREAM;
1021 break;
1022 default:
1023 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
1024 break;
1025 }
1026
1027#if defined(SOCK_CLOEXEC)
1028 if (host_type & SOCK_CLOEXEC) {
1029 target_type |= TARGET_SOCK_CLOEXEC;
1030 }
1031#endif
1032
1033#if defined(SOCK_NONBLOCK)
1034 if (host_type & SOCK_NONBLOCK) {
1035 target_type |= TARGET_SOCK_NONBLOCK;
1036 }
1037#endif
1038
1039 return target_type;
1040}
1041
blueswir1992f48a2007-10-14 16:27:31 +00001042static abi_ulong target_brk;
1043static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +00001044static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +00001045
blueswir1992f48a2007-10-14 16:27:31 +00001046void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001047{
blueswir14c1de732007-07-07 20:45:44 +00001048 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +00001049 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +00001050}
1051
vincent4d1de872011-06-14 21:56:33 +00001052//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
1053#define DEBUGF_BRK(message, args...)
1054
ths0da46a62007-10-20 20:23:07 +00001055/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001056abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +00001057{
blueswir1992f48a2007-10-14 16:27:31 +00001058 abi_long mapped_addr;
Peter Maydellef4330c2016-07-22 13:41:52 +01001059 abi_ulong new_alloc_size;
bellard31e31b82003-02-18 22:55:36 +00001060
Paul Brook3a0c6c42012-02-09 19:04:27 +00001061 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +00001062
vincent4d1de872011-06-14 21:56:33 +00001063 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001064 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001065 return target_brk;
1066 }
1067 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001068 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
1069 target_brk);
vincent4d1de872011-06-14 21:56:33 +00001070 return target_brk;
1071 }
bellard31e31b82003-02-18 22:55:36 +00001072
vincent4d1de872011-06-14 21:56:33 +00001073 /* If the new brk is less than the highest page reserved to the
1074 * target heap allocation, set it and we're almost done... */
1075 if (new_brk <= brk_page) {
1076 /* Heap contents are initialized to zero, as for anonymous
1077 * mapped pages. */
1078 if (new_brk > target_brk) {
1079 memset(g2h(target_brk), 0, new_brk - target_brk);
1080 }
bellard31e31b82003-02-18 22:55:36 +00001081 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001082 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +00001083 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001084 }
1085
Peter Maydell00faf082011-04-18 16:34:24 +01001086 /* We need to allocate more memory after the brk... Note that
1087 * we don't use MAP_FIXED because that will map over the top of
1088 * any existing mapping (like the one with the host libc or qemu
1089 * itself); instead we treat "mapped but at wrong address" as
1090 * a failure and unmap again.
1091 */
vincent4d1de872011-06-14 21:56:33 +00001092 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +00001093 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +00001094 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +01001095 MAP_ANON|MAP_PRIVATE, 0, 0));
1096
1097 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +02001098 /* Heap contents are initialized to zero, as for anonymous
1099 * mapped pages. Technically the new pages are already
1100 * initialized to zero since they *are* anonymous mapped
1101 * pages, however we have to take care with the contents that
1102 * come from the remaining part of the previous page: it may
1103 * contains garbage data due to a previous heap usage (grown
1104 * then shrunken). */
1105 memset(g2h(target_brk), 0, brk_page - target_brk);
1106
Peter Maydell00faf082011-04-18 16:34:24 +01001107 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +00001108 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +00001109 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
1110 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001111 return target_brk;
1112 } else if (mapped_addr != -1) {
1113 /* Mapped but at wrong address, meaning there wasn't actually
1114 * enough space for this brk.
1115 */
1116 target_munmap(mapped_addr, new_alloc_size);
1117 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +00001118 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +00001119 }
1120 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +00001121 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +01001122 }
balrog7ab240a2008-04-26 12:17:34 +00001123
Richard Henderson7dd46c02010-05-03 10:07:49 -07001124#if defined(TARGET_ALPHA)
1125 /* We (partially) emulate OSF/1 on Alpha, which requires we
1126 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +01001127 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -07001128#endif
Peter Maydell00faf082011-04-18 16:34:24 +01001129 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +00001130 return target_brk;
bellard31e31b82003-02-18 22:55:36 +00001131}
1132
ths26edcf42007-12-09 02:25:24 +00001133static inline abi_long copy_from_user_fdset(fd_set *fds,
1134 abi_ulong target_fds_addr,
1135 int n)
bellard31e31b82003-02-18 22:55:36 +00001136{
ths26edcf42007-12-09 02:25:24 +00001137 int i, nw, j, k;
1138 abi_ulong b, *target_fds;
1139
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001140 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001141 if (!(target_fds = lock_user(VERIFY_READ,
1142 target_fds_addr,
1143 sizeof(abi_ulong) * nw,
1144 1)))
1145 return -TARGET_EFAULT;
1146
1147 FD_ZERO(fds);
1148 k = 0;
1149 for (i = 0; i < nw; i++) {
1150 /* grab the abi_ulong */
1151 __get_user(b, &target_fds[i]);
1152 for (j = 0; j < TARGET_ABI_BITS; j++) {
1153 /* check the bit inside the abi_ulong */
1154 if ((b >> j) & 1)
1155 FD_SET(k, fds);
1156 k++;
bellard31e31b82003-02-18 22:55:36 +00001157 }
bellard31e31b82003-02-18 22:55:36 +00001158 }
ths26edcf42007-12-09 02:25:24 +00001159
1160 unlock_user(target_fds, target_fds_addr, 0);
1161
1162 return 0;
bellard31e31b82003-02-18 22:55:36 +00001163}
1164
Mike Frysinger055e0902011-06-03 17:01:49 -04001165static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
1166 abi_ulong target_fds_addr,
1167 int n)
1168{
1169 if (target_fds_addr) {
1170 if (copy_from_user_fdset(fds, target_fds_addr, n))
1171 return -TARGET_EFAULT;
1172 *fds_ptr = fds;
1173 } else {
1174 *fds_ptr = NULL;
1175 }
1176 return 0;
1177}
1178
ths26edcf42007-12-09 02:25:24 +00001179static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
1180 const fd_set *fds,
1181 int n)
bellard31e31b82003-02-18 22:55:36 +00001182{
bellard31e31b82003-02-18 22:55:36 +00001183 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +00001184 abi_long v;
ths26edcf42007-12-09 02:25:24 +00001185 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +00001186
Laurent Vivierb1b2db22016-05-31 18:36:02 +02001187 nw = DIV_ROUND_UP(n, TARGET_ABI_BITS);
ths26edcf42007-12-09 02:25:24 +00001188 if (!(target_fds = lock_user(VERIFY_WRITE,
1189 target_fds_addr,
1190 sizeof(abi_ulong) * nw,
1191 0)))
1192 return -TARGET_EFAULT;
1193
1194 k = 0;
1195 for (i = 0; i < nw; i++) {
1196 v = 0;
1197 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +00001198 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +00001199 k++;
bellard31e31b82003-02-18 22:55:36 +00001200 }
ths26edcf42007-12-09 02:25:24 +00001201 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +00001202 }
ths26edcf42007-12-09 02:25:24 +00001203
1204 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
1205
1206 return 0;
bellard31e31b82003-02-18 22:55:36 +00001207}
1208
bellardc596ed12003-07-13 17:32:31 +00001209#if defined(__alpha__)
1210#define HOST_HZ 1024
1211#else
1212#define HOST_HZ 100
1213#endif
1214
blueswir1992f48a2007-10-14 16:27:31 +00001215static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +00001216{
1217#if HOST_HZ == TARGET_HZ
1218 return ticks;
1219#else
1220 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
1221#endif
1222}
1223
bellard579a97f2007-11-11 14:26:47 +00001224static inline abi_long host_to_target_rusage(abi_ulong target_addr,
1225 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +00001226{
pbrook53a59602006-03-25 19:31:22 +00001227 struct target_rusage *target_rusage;
1228
bellard579a97f2007-11-11 14:26:47 +00001229 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
1230 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001231 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
1232 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
1233 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
1234 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
1235 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
1236 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
1237 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
1238 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
1239 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
1240 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
1241 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1242 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1243 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1244 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1245 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1246 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1247 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1248 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001249 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001250
1251 return 0;
bellardb4091862003-05-16 15:39:34 +00001252}
1253
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001254static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001255{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001256 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001257 rlim_t result;
1258
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001259 target_rlim_swap = tswapal(target_rlim);
1260 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1261 return RLIM_INFINITY;
1262
1263 result = target_rlim_swap;
1264 if (target_rlim_swap != (rlim_t)result)
1265 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001266
1267 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001268}
1269
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001270static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001271{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001272 abi_ulong target_rlim_swap;
1273 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001274
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001275 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001276 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001277 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001278 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001279 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001280
1281 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001282}
1283
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001284static inline int target_to_host_resource(int code)
1285{
1286 switch (code) {
1287 case TARGET_RLIMIT_AS:
1288 return RLIMIT_AS;
1289 case TARGET_RLIMIT_CORE:
1290 return RLIMIT_CORE;
1291 case TARGET_RLIMIT_CPU:
1292 return RLIMIT_CPU;
1293 case TARGET_RLIMIT_DATA:
1294 return RLIMIT_DATA;
1295 case TARGET_RLIMIT_FSIZE:
1296 return RLIMIT_FSIZE;
1297 case TARGET_RLIMIT_LOCKS:
1298 return RLIMIT_LOCKS;
1299 case TARGET_RLIMIT_MEMLOCK:
1300 return RLIMIT_MEMLOCK;
1301 case TARGET_RLIMIT_MSGQUEUE:
1302 return RLIMIT_MSGQUEUE;
1303 case TARGET_RLIMIT_NICE:
1304 return RLIMIT_NICE;
1305 case TARGET_RLIMIT_NOFILE:
1306 return RLIMIT_NOFILE;
1307 case TARGET_RLIMIT_NPROC:
1308 return RLIMIT_NPROC;
1309 case TARGET_RLIMIT_RSS:
1310 return RLIMIT_RSS;
1311 case TARGET_RLIMIT_RTPRIO:
1312 return RLIMIT_RTPRIO;
1313 case TARGET_RLIMIT_SIGPENDING:
1314 return RLIMIT_SIGPENDING;
1315 case TARGET_RLIMIT_STACK:
1316 return RLIMIT_STACK;
1317 default:
1318 return code;
1319 }
1320}
1321
ths788f5ec2007-12-09 02:37:05 +00001322static inline abi_long copy_from_user_timeval(struct timeval *tv,
1323 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001324{
pbrook53a59602006-03-25 19:31:22 +00001325 struct target_timeval *target_tv;
1326
ths788f5ec2007-12-09 02:37:05 +00001327 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001328 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001329
1330 __get_user(tv->tv_sec, &target_tv->tv_sec);
1331 __get_user(tv->tv_usec, &target_tv->tv_usec);
1332
1333 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001334
1335 return 0;
bellard31e31b82003-02-18 22:55:36 +00001336}
1337
ths788f5ec2007-12-09 02:37:05 +00001338static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1339 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001340{
pbrook53a59602006-03-25 19:31:22 +00001341 struct target_timeval *target_tv;
1342
ths788f5ec2007-12-09 02:37:05 +00001343 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001344 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001345
1346 __put_user(tv->tv_sec, &target_tv->tv_sec);
1347 __put_user(tv->tv_usec, &target_tv->tv_usec);
1348
1349 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001350
1351 return 0;
bellard31e31b82003-02-18 22:55:36 +00001352}
1353
Paul Burtonef4467e2014-06-22 11:25:40 +01001354static inline abi_long copy_from_user_timezone(struct timezone *tz,
1355 abi_ulong target_tz_addr)
1356{
1357 struct target_timezone *target_tz;
1358
1359 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1360 return -TARGET_EFAULT;
1361 }
1362
1363 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1364 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1365
1366 unlock_user_struct(target_tz, target_tz_addr, 0);
1367
1368 return 0;
1369}
1370
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001371#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1372#include <mqueue.h>
1373
aurel3224e10032009-04-15 16:11:43 +00001374static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1375 abi_ulong target_mq_attr_addr)
1376{
1377 struct target_mq_attr *target_mq_attr;
1378
1379 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1380 target_mq_attr_addr, 1))
1381 return -TARGET_EFAULT;
1382
1383 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1384 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1385 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1386 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1387
1388 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1389
1390 return 0;
1391}
1392
1393static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1394 const struct mq_attr *attr)
1395{
1396 struct target_mq_attr *target_mq_attr;
1397
1398 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1399 target_mq_attr_addr, 0))
1400 return -TARGET_EFAULT;
1401
1402 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1403 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1404 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1405 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1406
1407 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1408
1409 return 0;
1410}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001411#endif
bellard31e31b82003-02-18 22:55:36 +00001412
Mike Frysinger055e0902011-06-03 17:01:49 -04001413#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001414/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001415static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001416 abi_ulong rfd_addr, abi_ulong wfd_addr,
1417 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001418{
1419 fd_set rfds, wfds, efds;
1420 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001421 struct timeval tv;
1422 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001423 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001424
Mike Frysinger055e0902011-06-03 17:01:49 -04001425 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1426 if (ret) {
1427 return ret;
pbrook53a59602006-03-25 19:31:22 +00001428 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001429 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1430 if (ret) {
1431 return ret;
pbrook53a59602006-03-25 19:31:22 +00001432 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001433 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1434 if (ret) {
1435 return ret;
pbrook53a59602006-03-25 19:31:22 +00001436 }
ths3b46e622007-09-17 08:09:54 +00001437
ths26edcf42007-12-09 02:25:24 +00001438 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001439 if (copy_from_user_timeval(&tv, target_tv_addr))
1440 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001441 ts.tv_sec = tv.tv_sec;
1442 ts.tv_nsec = tv.tv_usec * 1000;
1443 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001444 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001445 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001446 }
ths26edcf42007-12-09 02:25:24 +00001447
Peter Maydell6df9d382016-05-12 18:47:51 +01001448 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1449 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001450
ths26edcf42007-12-09 02:25:24 +00001451 if (!is_error(ret)) {
1452 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1453 return -TARGET_EFAULT;
1454 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1455 return -TARGET_EFAULT;
1456 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1457 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001458
Peter Maydell6df9d382016-05-12 18:47:51 +01001459 if (target_tv_addr) {
1460 tv.tv_sec = ts.tv_sec;
1461 tv.tv_usec = ts.tv_nsec / 1000;
1462 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1463 return -TARGET_EFAULT;
1464 }
1465 }
bellard31e31b82003-02-18 22:55:36 +00001466 }
bellard579a97f2007-11-11 14:26:47 +00001467
bellard31e31b82003-02-18 22:55:36 +00001468 return ret;
1469}
Laurent Vivier5457dc92016-07-08 01:17:27 +02001470
1471#if defined(TARGET_WANT_OLD_SYS_SELECT)
1472static abi_long do_old_select(abi_ulong arg1)
1473{
1474 struct target_sel_arg_struct *sel;
1475 abi_ulong inp, outp, exp, tvp;
1476 long nsel;
1477
1478 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) {
1479 return -TARGET_EFAULT;
1480 }
1481
1482 nsel = tswapal(sel->n);
1483 inp = tswapal(sel->inp);
1484 outp = tswapal(sel->outp);
1485 exp = tswapal(sel->exp);
1486 tvp = tswapal(sel->tvp);
1487
1488 unlock_user_struct(sel, arg1, 0);
1489
1490 return do_select(nsel, inp, outp, exp, tvp);
1491}
1492#endif
Mike Frysinger055e0902011-06-03 17:01:49 -04001493#endif
bellard31e31b82003-02-18 22:55:36 +00001494
Riku Voipio099d6b02009-05-05 12:10:04 +03001495static abi_long do_pipe2(int host_pipe[], int flags)
1496{
1497#ifdef CONFIG_PIPE2
1498 return pipe2(host_pipe, flags);
1499#else
1500 return -ENOSYS;
1501#endif
1502}
1503
Richard Hendersonfb41a662010-05-03 10:07:52 -07001504static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1505 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001506{
1507 int host_pipe[2];
1508 abi_long ret;
1509 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1510
1511 if (is_error(ret))
1512 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001513
1514 /* Several targets have special calling conventions for the original
1515 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1516 if (!is_pipe2) {
1517#if defined(TARGET_ALPHA)
1518 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1519 return host_pipe[0];
1520#elif defined(TARGET_MIPS)
1521 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1522 return host_pipe[0];
1523#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001524 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001525 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001526#elif defined(TARGET_SPARC)
1527 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1528 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001529#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001530 }
1531
Riku Voipio099d6b02009-05-05 12:10:04 +03001532 if (put_user_s32(host_pipe[0], pipedes)
1533 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1534 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001535 return get_errno(ret);
1536}
1537
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001538static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1539 abi_ulong target_addr,
1540 socklen_t len)
1541{
1542 struct target_ip_mreqn *target_smreqn;
1543
1544 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1545 if (!target_smreqn)
1546 return -TARGET_EFAULT;
1547 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1548 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1549 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001550 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001551 unlock_user(target_smreqn, target_addr, 0);
1552
1553 return 0;
1554}
1555
Laurent Vivier7b36f782015-10-28 21:40:44 +01001556static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001557 abi_ulong target_addr,
1558 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001559{
aurel32607175e2009-04-15 16:11:59 +00001560 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1561 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001562 struct target_sockaddr *target_saddr;
1563
Laurent Vivier7b36f782015-10-28 21:40:44 +01001564 if (fd_trans_target_to_host_addr(fd)) {
1565 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1566 }
1567
bellard579a97f2007-11-11 14:26:47 +00001568 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1569 if (!target_saddr)
1570 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001571
1572 sa_family = tswap16(target_saddr->sa_family);
1573
1574 /* Oops. The caller might send a incomplete sun_path; sun_path
1575 * must be terminated by \0 (see the manual page), but
1576 * unfortunately it is quite common to specify sockaddr_un
1577 * length as "strlen(x->sun_path)" while it should be
1578 * "strlen(...) + 1". We'll fix that here if needed.
1579 * Linux kernel has a similar feature.
1580 */
1581
1582 if (sa_family == AF_UNIX) {
1583 if (len < unix_maxlen && len > 0) {
1584 char *cp = (char*)target_saddr;
1585
1586 if ( cp[len-1] && !cp[len] )
1587 len++;
1588 }
1589 if (len > unix_maxlen)
1590 len = unix_maxlen;
1591 }
1592
pbrook53a59602006-03-25 19:31:22 +00001593 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001594 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001595 if (sa_family == AF_NETLINK) {
1596 struct sockaddr_nl *nladdr;
1597
1598 nladdr = (struct sockaddr_nl *)addr;
1599 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1600 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1601 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001602 struct target_sockaddr_ll *lladdr;
1603
1604 lladdr = (struct target_sockaddr_ll *)addr;
1605 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1606 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1607 }
pbrook53a59602006-03-25 19:31:22 +00001608 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001609
1610 return 0;
bellard7854b052003-03-29 17:22:23 +00001611}
1612
bellard579a97f2007-11-11 14:26:47 +00001613static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1614 struct sockaddr *addr,
1615 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001616{
pbrook53a59602006-03-25 19:31:22 +00001617 struct target_sockaddr *target_saddr;
1618
Peter Maydella1e22192016-07-07 15:44:43 +01001619 if (len == 0) {
1620 return 0;
1621 }
1622
bellard579a97f2007-11-11 14:26:47 +00001623 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1624 if (!target_saddr)
1625 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001626 memcpy(target_saddr, addr, len);
Peter Maydella1e22192016-07-07 15:44:43 +01001627 if (len >= offsetof(struct target_sockaddr, sa_family) +
1628 sizeof(target_saddr->sa_family)) {
1629 target_saddr->sa_family = tswap16(addr->sa_family);
1630 }
1631 if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001632 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1633 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1634 target_nl->nl_groups = tswap32(target_nl->nl_groups);
Laurent Viviera82ea932016-06-27 00:18:22 +02001635 } else if (addr->sa_family == AF_PACKET) {
1636 struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
1637 target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
1638 target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
Helge Delleree1ac3a2017-02-18 23:31:30 +01001639 } else if (addr->sa_family == AF_INET6 &&
1640 len >= sizeof(struct target_sockaddr_in6)) {
1641 struct target_sockaddr_in6 *target_in6 =
1642 (struct target_sockaddr_in6 *)target_saddr;
1643 target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001644 }
pbrook53a59602006-03-25 19:31:22 +00001645 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001646
1647 return 0;
bellard7854b052003-03-29 17:22:23 +00001648}
1649
bellard5a4a8982007-11-11 17:39:18 +00001650static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1651 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001652{
1653 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001654 abi_long msg_controllen;
1655 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001656 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001657 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001658
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001659 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001660 if (msg_controllen < sizeof (struct target_cmsghdr))
1661 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001662 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001663 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001664 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001665 if (!target_cmsg)
1666 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001667
1668 while (cmsg && target_cmsg) {
1669 void *data = CMSG_DATA(cmsg);
1670 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1671
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001672 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001673 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1674
1675 space += CMSG_SPACE(len);
1676 if (space > msgh->msg_controllen) {
1677 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001678 /* This is a QEMU bug, since we allocated the payload
1679 * area ourselves (unlike overflow in host-to-target
1680 * conversion, which is just the guest giving us a buffer
1681 * that's too small). It can't happen for the payload types
1682 * we currently support; if it becomes an issue in future
1683 * we would need to improve our allocation strategy to
1684 * something more intelligent than "twice the size of the
1685 * target buffer we're reading from".
1686 */
bellard31febb72005-12-18 20:03:27 +00001687 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001688 break;
1689 }
1690
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001691 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1692 cmsg->cmsg_level = SOL_SOCKET;
1693 } else {
1694 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1695 }
bellard7854b052003-03-29 17:22:23 +00001696 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1697 cmsg->cmsg_len = CMSG_LEN(len);
1698
Alex Suykov30b8b682014-12-23 07:52:58 +02001699 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001700 int *fd = (int *)data;
1701 int *target_fd = (int *)target_data;
1702 int i, numfds = len / sizeof(int);
1703
Peter Maydell876e23c2015-05-26 19:46:32 +01001704 for (i = 0; i < numfds; i++) {
1705 __get_user(fd[i], target_fd + i);
1706 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001707 } else if (cmsg->cmsg_level == SOL_SOCKET
1708 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1709 struct ucred *cred = (struct ucred *)data;
1710 struct target_ucred *target_cred =
1711 (struct target_ucred *)target_data;
1712
Peter Maydell876e23c2015-05-26 19:46:32 +01001713 __get_user(cred->pid, &target_cred->pid);
1714 __get_user(cred->uid, &target_cred->uid);
1715 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001716 } else {
1717 gemu_log("Unsupported ancillary data: %d/%d\n",
1718 cmsg->cmsg_level, cmsg->cmsg_type);
1719 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001720 }
1721
1722 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001723 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1724 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001725 }
bellard5a4a8982007-11-11 17:39:18 +00001726 unlock_user(target_cmsg, target_cmsg_addr, 0);
1727 the_end:
bellard7854b052003-03-29 17:22:23 +00001728 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001729 return 0;
bellard7854b052003-03-29 17:22:23 +00001730}
1731
bellard5a4a8982007-11-11 17:39:18 +00001732static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1733 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001734{
1735 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001736 abi_long msg_controllen;
1737 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001738 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001739 socklen_t space = 0;
1740
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001741 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001742 if (msg_controllen < sizeof (struct target_cmsghdr))
1743 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001744 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001745 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001746 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001747 if (!target_cmsg)
1748 return -TARGET_EFAULT;
1749
bellard7854b052003-03-29 17:22:23 +00001750 while (cmsg && target_cmsg) {
1751 void *data = CMSG_DATA(cmsg);
1752 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1753
1754 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001755 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001756
Peter Maydellc2aeb252015-05-26 19:46:31 +01001757 /* We never copy a half-header but may copy half-data;
1758 * this is Linux's behaviour in put_cmsg(). Note that
1759 * truncation here is a guest problem (which we report
1760 * to the guest via the CTRUNC bit), unlike truncation
1761 * in target_to_host_cmsg, which is a QEMU bug.
1762 */
1763 if (msg_controllen < sizeof(struct cmsghdr)) {
1764 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001765 break;
1766 }
1767
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001768 if (cmsg->cmsg_level == SOL_SOCKET) {
1769 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1770 } else {
1771 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1772 }
bellard7854b052003-03-29 17:22:23 +00001773 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001774
Peter Maydellc2aeb252015-05-26 19:46:31 +01001775 tgt_len = TARGET_CMSG_LEN(len);
1776
1777 /* Payload types which need a different size of payload on
1778 * the target must adjust tgt_len here.
1779 */
1780 switch (cmsg->cmsg_level) {
1781 case SOL_SOCKET:
1782 switch (cmsg->cmsg_type) {
1783 case SO_TIMESTAMP:
1784 tgt_len = sizeof(struct target_timeval);
1785 break;
1786 default:
1787 break;
1788 }
1789 default:
1790 break;
1791 }
1792
1793 if (msg_controllen < tgt_len) {
1794 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1795 tgt_len = msg_controllen;
1796 }
1797
1798 /* We must now copy-and-convert len bytes of payload
1799 * into tgt_len bytes of destination space. Bear in mind
1800 * that in both source and destination we may be dealing
1801 * with a truncated value!
1802 */
Huw Davies52b65492014-04-17 14:02:47 +01001803 switch (cmsg->cmsg_level) {
1804 case SOL_SOCKET:
1805 switch (cmsg->cmsg_type) {
1806 case SCM_RIGHTS:
1807 {
1808 int *fd = (int *)data;
1809 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001810 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001811
Peter Maydell876e23c2015-05-26 19:46:32 +01001812 for (i = 0; i < numfds; i++) {
1813 __put_user(fd[i], target_fd + i);
1814 }
Huw Davies52b65492014-04-17 14:02:47 +01001815 break;
1816 }
1817 case SO_TIMESTAMP:
1818 {
1819 struct timeval *tv = (struct timeval *)data;
1820 struct target_timeval *target_tv =
1821 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001822
Peter Maydellc2aeb252015-05-26 19:46:31 +01001823 if (len != sizeof(struct timeval) ||
1824 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001825 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001826 }
Huw Davies52b65492014-04-17 14:02:47 +01001827
1828 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001829 __put_user(tv->tv_sec, &target_tv->tv_sec);
1830 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001831 break;
1832 }
Huw Davies4bc29752014-04-17 14:02:48 +01001833 case SCM_CREDENTIALS:
1834 {
1835 struct ucred *cred = (struct ucred *)data;
1836 struct target_ucred *target_cred =
1837 (struct target_ucred *)target_data;
1838
1839 __put_user(cred->pid, &target_cred->pid);
1840 __put_user(cred->uid, &target_cred->uid);
1841 __put_user(cred->gid, &target_cred->gid);
1842 break;
1843 }
Huw Davies52b65492014-04-17 14:02:47 +01001844 default:
1845 goto unimplemented;
1846 }
1847 break;
1848
Helge Delleree1ac3a2017-02-18 23:31:30 +01001849 case SOL_IP:
1850 switch (cmsg->cmsg_type) {
1851 case IP_TTL:
1852 {
1853 uint32_t *v = (uint32_t *)data;
1854 uint32_t *t_int = (uint32_t *)target_data;
1855
1856 __put_user(*v, t_int);
1857 break;
1858 }
1859 case IP_RECVERR:
1860 {
1861 struct errhdr_t {
1862 struct sock_extended_err ee;
1863 struct sockaddr_in offender;
1864 };
1865 struct errhdr_t *errh = (struct errhdr_t *)data;
1866 struct errhdr_t *target_errh =
1867 (struct errhdr_t *)target_data;
1868
1869 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1870 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1871 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1872 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1873 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1874 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1875 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1876 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1877 (void *) &errh->offender, sizeof(errh->offender));
1878 break;
1879 }
1880 default:
1881 goto unimplemented;
1882 }
1883 break;
1884
1885 case SOL_IPV6:
1886 switch (cmsg->cmsg_type) {
1887 case IPV6_HOPLIMIT:
1888 {
1889 uint32_t *v = (uint32_t *)data;
1890 uint32_t *t_int = (uint32_t *)target_data;
1891
1892 __put_user(*v, t_int);
1893 break;
1894 }
1895 case IPV6_RECVERR:
1896 {
1897 struct errhdr6_t {
1898 struct sock_extended_err ee;
1899 struct sockaddr_in6 offender;
1900 };
1901 struct errhdr6_t *errh = (struct errhdr6_t *)data;
1902 struct errhdr6_t *target_errh =
1903 (struct errhdr6_t *)target_data;
1904
1905 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
1906 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
1907 __put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
1908 __put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
1909 __put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
1910 __put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
1911 __put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
1912 host_to_target_sockaddr((unsigned long) &target_errh->offender,
1913 (void *) &errh->offender, sizeof(errh->offender));
1914 break;
1915 }
1916 default:
1917 goto unimplemented;
1918 }
1919 break;
1920
Huw Davies52b65492014-04-17 14:02:47 +01001921 default:
1922 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001923 gemu_log("Unsupported ancillary data: %d/%d\n",
1924 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001925 memcpy(target_data, data, MIN(len, tgt_len));
1926 if (tgt_len > len) {
1927 memset(target_data + len, 0, tgt_len - len);
1928 }
bellard7854b052003-03-29 17:22:23 +00001929 }
1930
Peter Maydellc2aeb252015-05-26 19:46:31 +01001931 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001932 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001933 if (msg_controllen < tgt_space) {
1934 tgt_space = msg_controllen;
1935 }
1936 msg_controllen -= tgt_space;
1937 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001938 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001939 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1940 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001941 }
bellard5a4a8982007-11-11 17:39:18 +00001942 unlock_user(target_cmsg, target_cmsg_addr, space);
1943 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001944 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001945 return 0;
bellard7854b052003-03-29 17:22:23 +00001946}
1947
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001948static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1949{
1950 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1951 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1952 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1953 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1954 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1955}
1956
1957static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1958 size_t len,
1959 abi_long (*host_to_target_nlmsg)
1960 (struct nlmsghdr *))
1961{
1962 uint32_t nlmsg_len;
1963 abi_long ret;
1964
1965 while (len > sizeof(struct nlmsghdr)) {
1966
1967 nlmsg_len = nlh->nlmsg_len;
1968 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1969 nlmsg_len > len) {
1970 break;
1971 }
1972
1973 switch (nlh->nlmsg_type) {
1974 case NLMSG_DONE:
1975 tswap_nlmsghdr(nlh);
1976 return 0;
1977 case NLMSG_NOOP:
1978 break;
1979 case NLMSG_ERROR:
1980 {
1981 struct nlmsgerr *e = NLMSG_DATA(nlh);
1982 e->error = tswap32(e->error);
1983 tswap_nlmsghdr(&e->msg);
1984 tswap_nlmsghdr(nlh);
1985 return 0;
1986 }
1987 default:
1988 ret = host_to_target_nlmsg(nlh);
1989 if (ret < 0) {
1990 tswap_nlmsghdr(nlh);
1991 return ret;
1992 }
1993 break;
1994 }
1995 tswap_nlmsghdr(nlh);
1996 len -= NLMSG_ALIGN(nlmsg_len);
1997 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1998 }
1999 return 0;
2000}
2001
2002static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
2003 size_t len,
2004 abi_long (*target_to_host_nlmsg)
2005 (struct nlmsghdr *))
2006{
2007 int ret;
2008
2009 while (len > sizeof(struct nlmsghdr)) {
2010 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
2011 tswap32(nlh->nlmsg_len) > len) {
2012 break;
2013 }
2014 tswap_nlmsghdr(nlh);
2015 switch (nlh->nlmsg_type) {
2016 case NLMSG_DONE:
2017 return 0;
2018 case NLMSG_NOOP:
2019 break;
2020 case NLMSG_ERROR:
2021 {
2022 struct nlmsgerr *e = NLMSG_DATA(nlh);
2023 e->error = tswap32(e->error);
2024 tswap_nlmsghdr(&e->msg);
Laurent Vivier84f34b02016-06-14 15:07:09 +02002025 return 0;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002026 }
2027 default:
2028 ret = target_to_host_nlmsg(nlh);
2029 if (ret < 0) {
2030 return ret;
2031 }
2032 }
2033 len -= NLMSG_ALIGN(nlh->nlmsg_len);
2034 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
2035 }
2036 return 0;
2037}
2038
Laurent Vivier575b22b2016-06-02 22:14:15 +02002039#ifdef CONFIG_RTNETLINK
Laurent Vivierc5dff282016-06-27 18:54:30 +02002040static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr,
2041 size_t len, void *context,
2042 abi_long (*host_to_target_nlattr)
2043 (struct nlattr *,
2044 void *context))
2045{
2046 unsigned short nla_len;
2047 abi_long ret;
2048
2049 while (len > sizeof(struct nlattr)) {
2050 nla_len = nlattr->nla_len;
2051 if (nla_len < sizeof(struct nlattr) ||
2052 nla_len > len) {
2053 break;
2054 }
2055 ret = host_to_target_nlattr(nlattr, context);
2056 nlattr->nla_len = tswap16(nlattr->nla_len);
2057 nlattr->nla_type = tswap16(nlattr->nla_type);
2058 if (ret < 0) {
2059 return ret;
2060 }
2061 len -= NLA_ALIGN(nla_len);
2062 nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len));
2063 }
2064 return 0;
2065}
2066
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002067static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
2068 size_t len,
2069 abi_long (*host_to_target_rtattr)
2070 (struct rtattr *))
2071{
2072 unsigned short rta_len;
2073 abi_long ret;
2074
2075 while (len > sizeof(struct rtattr)) {
2076 rta_len = rtattr->rta_len;
2077 if (rta_len < sizeof(struct rtattr) ||
2078 rta_len > len) {
2079 break;
2080 }
2081 ret = host_to_target_rtattr(rtattr);
2082 rtattr->rta_len = tswap16(rtattr->rta_len);
2083 rtattr->rta_type = tswap16(rtattr->rta_type);
2084 if (ret < 0) {
2085 return ret;
2086 }
2087 len -= RTA_ALIGN(rta_len);
2088 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
2089 }
2090 return 0;
2091}
2092
Laurent Vivierc5dff282016-06-27 18:54:30 +02002093#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN)
2094
2095static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
2096 void *context)
2097{
2098 uint16_t *u16;
2099 uint32_t *u32;
2100 uint64_t *u64;
2101
2102 switch (nlattr->nla_type) {
2103 /* no data */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002104 case QEMU_IFLA_BR_FDB_FLUSH:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002105 break;
2106 /* binary */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002107 case QEMU_IFLA_BR_GROUP_ADDR:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002108 break;
2109 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002110 case QEMU_IFLA_BR_VLAN_FILTERING:
2111 case QEMU_IFLA_BR_TOPOLOGY_CHANGE:
2112 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED:
2113 case QEMU_IFLA_BR_MCAST_ROUTER:
2114 case QEMU_IFLA_BR_MCAST_SNOOPING:
2115 case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR:
2116 case QEMU_IFLA_BR_MCAST_QUERIER:
2117 case QEMU_IFLA_BR_NF_CALL_IPTABLES:
2118 case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
2119 case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002120 break;
2121 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002122 case QEMU_IFLA_BR_PRIORITY:
2123 case QEMU_IFLA_BR_VLAN_PROTOCOL:
2124 case QEMU_IFLA_BR_GROUP_FWD_MASK:
2125 case QEMU_IFLA_BR_ROOT_PORT:
2126 case QEMU_IFLA_BR_VLAN_DEFAULT_PVID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002127 u16 = NLA_DATA(nlattr);
2128 *u16 = tswap16(*u16);
2129 break;
2130 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002131 case QEMU_IFLA_BR_FORWARD_DELAY:
2132 case QEMU_IFLA_BR_HELLO_TIME:
2133 case QEMU_IFLA_BR_MAX_AGE:
2134 case QEMU_IFLA_BR_AGEING_TIME:
2135 case QEMU_IFLA_BR_STP_STATE:
2136 case QEMU_IFLA_BR_ROOT_PATH_COST:
2137 case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY:
2138 case QEMU_IFLA_BR_MCAST_HASH_MAX:
2139 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT:
2140 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002141 u32 = NLA_DATA(nlattr);
2142 *u32 = tswap32(*u32);
2143 break;
2144 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002145 case QEMU_IFLA_BR_HELLO_TIMER:
2146 case QEMU_IFLA_BR_TCN_TIMER:
2147 case QEMU_IFLA_BR_GC_TIMER:
2148 case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER:
2149 case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL:
2150 case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL:
2151 case QEMU_IFLA_BR_MCAST_QUERIER_INTVL:
2152 case QEMU_IFLA_BR_MCAST_QUERY_INTVL:
2153 case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
2154 case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002155 u64 = NLA_DATA(nlattr);
2156 *u64 = tswap64(*u64);
2157 break;
2158 /* ifla_bridge_id: uin8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002159 case QEMU_IFLA_BR_ROOT_ID:
2160 case QEMU_IFLA_BR_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002161 break;
2162 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002163 gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002164 break;
2165 }
2166 return 0;
2167}
2168
2169static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
2170 void *context)
2171{
2172 uint16_t *u16;
2173 uint32_t *u32;
2174 uint64_t *u64;
2175
2176 switch (nlattr->nla_type) {
2177 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002178 case QEMU_IFLA_BRPORT_STATE:
2179 case QEMU_IFLA_BRPORT_MODE:
2180 case QEMU_IFLA_BRPORT_GUARD:
2181 case QEMU_IFLA_BRPORT_PROTECT:
2182 case QEMU_IFLA_BRPORT_FAST_LEAVE:
2183 case QEMU_IFLA_BRPORT_LEARNING:
2184 case QEMU_IFLA_BRPORT_UNICAST_FLOOD:
2185 case QEMU_IFLA_BRPORT_PROXYARP:
2186 case QEMU_IFLA_BRPORT_LEARNING_SYNC:
2187 case QEMU_IFLA_BRPORT_PROXYARP_WIFI:
2188 case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
2189 case QEMU_IFLA_BRPORT_CONFIG_PENDING:
2190 case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002191 break;
2192 /* uint16_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002193 case QEMU_IFLA_BRPORT_PRIORITY:
2194 case QEMU_IFLA_BRPORT_DESIGNATED_PORT:
2195 case QEMU_IFLA_BRPORT_DESIGNATED_COST:
2196 case QEMU_IFLA_BRPORT_ID:
2197 case QEMU_IFLA_BRPORT_NO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002198 u16 = NLA_DATA(nlattr);
2199 *u16 = tswap16(*u16);
2200 break;
2201 /* uin32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002202 case QEMU_IFLA_BRPORT_COST:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002203 u32 = NLA_DATA(nlattr);
2204 *u32 = tswap32(*u32);
2205 break;
2206 /* uint64_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002207 case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER:
2208 case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER:
2209 case QEMU_IFLA_BRPORT_HOLD_TIMER:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002210 u64 = NLA_DATA(nlattr);
2211 *u64 = tswap64(*u64);
2212 break;
2213 /* ifla_bridge_id: uint8_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002214 case QEMU_IFLA_BRPORT_ROOT_ID:
2215 case QEMU_IFLA_BRPORT_BRIDGE_ID:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002216 break;
2217 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002218 gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002219 break;
2220 }
2221 return 0;
2222}
2223
2224struct linkinfo_context {
2225 int len;
2226 char *name;
2227 int slave_len;
2228 char *slave_name;
2229};
2230
2231static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr,
2232 void *context)
2233{
2234 struct linkinfo_context *li_context = context;
2235
2236 switch (nlattr->nla_type) {
2237 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002238 case QEMU_IFLA_INFO_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002239 li_context->name = NLA_DATA(nlattr);
2240 li_context->len = nlattr->nla_len - NLA_HDRLEN;
2241 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002242 case QEMU_IFLA_INFO_SLAVE_KIND:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002243 li_context->slave_name = NLA_DATA(nlattr);
2244 li_context->slave_len = nlattr->nla_len - NLA_HDRLEN;
2245 break;
2246 /* stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002247 case QEMU_IFLA_INFO_XSTATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002248 /* FIXME: only used by CAN */
2249 break;
2250 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002251 case QEMU_IFLA_INFO_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002252 if (strncmp(li_context->name, "bridge",
2253 li_context->len) == 0) {
2254 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2255 nlattr->nla_len,
2256 NULL,
2257 host_to_target_data_bridge_nlattr);
2258 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002259 gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n", li_context->name);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002260 }
2261 break;
Michal Privoznik60c6b792016-08-19 10:06:40 +02002262 case QEMU_IFLA_INFO_SLAVE_DATA:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002263 if (strncmp(li_context->slave_name, "bridge",
2264 li_context->slave_len) == 0) {
2265 return host_to_target_for_each_nlattr(NLA_DATA(nlattr),
2266 nlattr->nla_len,
2267 NULL,
2268 host_to_target_slave_data_bridge_nlattr);
2269 } else {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002270 gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n",
Laurent Vivierc5dff282016-06-27 18:54:30 +02002271 li_context->slave_name);
2272 }
2273 break;
2274 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002275 gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n", nlattr->nla_type);
Laurent Vivierc5dff282016-06-27 18:54:30 +02002276 break;
2277 }
2278
2279 return 0;
2280}
2281
2282static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr,
2283 void *context)
2284{
2285 uint32_t *u32;
2286 int i;
2287
2288 switch (nlattr->nla_type) {
Michal Privoznik60c6b792016-08-19 10:06:40 +02002289 case QEMU_IFLA_INET_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002290 u32 = NLA_DATA(nlattr);
2291 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2292 i++) {
2293 u32[i] = tswap32(u32[i]);
2294 }
2295 break;
2296 default:
2297 gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type);
2298 }
2299 return 0;
2300}
2301
2302static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr,
2303 void *context)
2304{
2305 uint32_t *u32;
2306 uint64_t *u64;
2307 struct ifla_cacheinfo *ci;
2308 int i;
2309
2310 switch (nlattr->nla_type) {
2311 /* binaries */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002312 case QEMU_IFLA_INET6_TOKEN:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002313 break;
2314 /* uint8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002315 case QEMU_IFLA_INET6_ADDR_GEN_MODE:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002316 break;
2317 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002318 case QEMU_IFLA_INET6_FLAGS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002319 u32 = NLA_DATA(nlattr);
2320 *u32 = tswap32(*u32);
2321 break;
2322 /* uint32_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002323 case QEMU_IFLA_INET6_CONF:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002324 u32 = NLA_DATA(nlattr);
2325 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32);
2326 i++) {
2327 u32[i] = tswap32(u32[i]);
2328 }
2329 break;
2330 /* ifla_cacheinfo */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002331 case QEMU_IFLA_INET6_CACHEINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002332 ci = NLA_DATA(nlattr);
2333 ci->max_reasm_len = tswap32(ci->max_reasm_len);
2334 ci->tstamp = tswap32(ci->tstamp);
2335 ci->reachable_time = tswap32(ci->reachable_time);
2336 ci->retrans_time = tswap32(ci->retrans_time);
2337 break;
2338 /* uint64_t[] */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002339 case QEMU_IFLA_INET6_STATS:
2340 case QEMU_IFLA_INET6_ICMP6STATS:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002341 u64 = NLA_DATA(nlattr);
2342 for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64);
2343 i++) {
2344 u64[i] = tswap64(u64[i]);
2345 }
2346 break;
2347 default:
2348 gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type);
2349 }
2350 return 0;
2351}
2352
2353static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
2354 void *context)
2355{
2356 switch (nlattr->nla_type) {
2357 case AF_INET:
2358 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2359 NULL,
2360 host_to_target_data_inet_nlattr);
2361 case AF_INET6:
2362 return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len,
2363 NULL,
2364 host_to_target_data_inet6_nlattr);
2365 default:
2366 gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type);
2367 break;
2368 }
2369 return 0;
2370}
2371
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002372static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
2373{
2374 uint32_t *u32;
2375 struct rtnl_link_stats *st;
2376 struct rtnl_link_stats64 *st64;
2377 struct rtnl_link_ifmap *map;
Laurent Vivierc5dff282016-06-27 18:54:30 +02002378 struct linkinfo_context li_context;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002379
2380 switch (rtattr->rta_type) {
2381 /* binary stream */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002382 case QEMU_IFLA_ADDRESS:
2383 case QEMU_IFLA_BROADCAST:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002384 /* string */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002385 case QEMU_IFLA_IFNAME:
2386 case QEMU_IFLA_QDISC:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002387 break;
2388 /* uin8_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002389 case QEMU_IFLA_OPERSTATE:
2390 case QEMU_IFLA_LINKMODE:
2391 case QEMU_IFLA_CARRIER:
2392 case QEMU_IFLA_PROTO_DOWN:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002393 break;
2394 /* uint32_t */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002395 case QEMU_IFLA_MTU:
2396 case QEMU_IFLA_LINK:
2397 case QEMU_IFLA_WEIGHT:
2398 case QEMU_IFLA_TXQLEN:
2399 case QEMU_IFLA_CARRIER_CHANGES:
2400 case QEMU_IFLA_NUM_RX_QUEUES:
2401 case QEMU_IFLA_NUM_TX_QUEUES:
2402 case QEMU_IFLA_PROMISCUITY:
2403 case QEMU_IFLA_EXT_MASK:
2404 case QEMU_IFLA_LINK_NETNSID:
2405 case QEMU_IFLA_GROUP:
2406 case QEMU_IFLA_MASTER:
2407 case QEMU_IFLA_NUM_VF:
Laurent Viviera1488b82016-10-27 03:00:49 +02002408 case QEMU_IFLA_GSO_MAX_SEGS:
2409 case QEMU_IFLA_GSO_MAX_SIZE:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002410 u32 = RTA_DATA(rtattr);
2411 *u32 = tswap32(*u32);
2412 break;
2413 /* struct rtnl_link_stats */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002414 case QEMU_IFLA_STATS:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002415 st = RTA_DATA(rtattr);
2416 st->rx_packets = tswap32(st->rx_packets);
2417 st->tx_packets = tswap32(st->tx_packets);
2418 st->rx_bytes = tswap32(st->rx_bytes);
2419 st->tx_bytes = tswap32(st->tx_bytes);
2420 st->rx_errors = tswap32(st->rx_errors);
2421 st->tx_errors = tswap32(st->tx_errors);
2422 st->rx_dropped = tswap32(st->rx_dropped);
2423 st->tx_dropped = tswap32(st->tx_dropped);
2424 st->multicast = tswap32(st->multicast);
2425 st->collisions = tswap32(st->collisions);
2426
2427 /* detailed rx_errors: */
2428 st->rx_length_errors = tswap32(st->rx_length_errors);
2429 st->rx_over_errors = tswap32(st->rx_over_errors);
2430 st->rx_crc_errors = tswap32(st->rx_crc_errors);
2431 st->rx_frame_errors = tswap32(st->rx_frame_errors);
2432 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
2433 st->rx_missed_errors = tswap32(st->rx_missed_errors);
2434
2435 /* detailed tx_errors */
2436 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
2437 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
2438 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
2439 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
2440 st->tx_window_errors = tswap32(st->tx_window_errors);
2441
2442 /* for cslip etc */
2443 st->rx_compressed = tswap32(st->rx_compressed);
2444 st->tx_compressed = tswap32(st->tx_compressed);
2445 break;
2446 /* struct rtnl_link_stats64 */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002447 case QEMU_IFLA_STATS64:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002448 st64 = RTA_DATA(rtattr);
2449 st64->rx_packets = tswap64(st64->rx_packets);
2450 st64->tx_packets = tswap64(st64->tx_packets);
2451 st64->rx_bytes = tswap64(st64->rx_bytes);
2452 st64->tx_bytes = tswap64(st64->tx_bytes);
2453 st64->rx_errors = tswap64(st64->rx_errors);
2454 st64->tx_errors = tswap64(st64->tx_errors);
2455 st64->rx_dropped = tswap64(st64->rx_dropped);
2456 st64->tx_dropped = tswap64(st64->tx_dropped);
2457 st64->multicast = tswap64(st64->multicast);
2458 st64->collisions = tswap64(st64->collisions);
2459
2460 /* detailed rx_errors: */
2461 st64->rx_length_errors = tswap64(st64->rx_length_errors);
2462 st64->rx_over_errors = tswap64(st64->rx_over_errors);
2463 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
2464 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
2465 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
2466 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
2467
2468 /* detailed tx_errors */
2469 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
2470 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
2471 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
2472 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
2473 st64->tx_window_errors = tswap64(st64->tx_window_errors);
2474
2475 /* for cslip etc */
2476 st64->rx_compressed = tswap64(st64->rx_compressed);
2477 st64->tx_compressed = tswap64(st64->tx_compressed);
2478 break;
2479 /* struct rtnl_link_ifmap */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002480 case QEMU_IFLA_MAP:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002481 map = RTA_DATA(rtattr);
2482 map->mem_start = tswap64(map->mem_start);
2483 map->mem_end = tswap64(map->mem_end);
2484 map->base_addr = tswap64(map->base_addr);
2485 map->irq = tswap16(map->irq);
2486 break;
2487 /* nested */
Michal Privoznik60c6b792016-08-19 10:06:40 +02002488 case QEMU_IFLA_LINKINFO:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002489 memset(&li_context, 0, sizeof(li_context));
2490 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2491 &li_context,
2492 host_to_target_data_linkinfo_nlattr);
Michal Privoznik60c6b792016-08-19 10:06:40 +02002493 case QEMU_IFLA_AF_SPEC:
Laurent Vivierc5dff282016-06-27 18:54:30 +02002494 return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
2495 NULL,
2496 host_to_target_data_spec_nlattr);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002497 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002498 gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002499 break;
2500 }
2501 return 0;
2502}
2503
2504static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
2505{
2506 uint32_t *u32;
2507 struct ifa_cacheinfo *ci;
2508
2509 switch (rtattr->rta_type) {
2510 /* binary: depends on family type */
2511 case IFA_ADDRESS:
2512 case IFA_LOCAL:
2513 break;
2514 /* string */
2515 case IFA_LABEL:
2516 break;
2517 /* u32 */
2518 case IFA_FLAGS:
2519 case IFA_BROADCAST:
2520 u32 = RTA_DATA(rtattr);
2521 *u32 = tswap32(*u32);
2522 break;
2523 /* struct ifa_cacheinfo */
2524 case IFA_CACHEINFO:
2525 ci = RTA_DATA(rtattr);
2526 ci->ifa_prefered = tswap32(ci->ifa_prefered);
2527 ci->ifa_valid = tswap32(ci->ifa_valid);
2528 ci->cstamp = tswap32(ci->cstamp);
2529 ci->tstamp = tswap32(ci->tstamp);
2530 break;
2531 default:
2532 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
2533 break;
2534 }
2535 return 0;
2536}
2537
2538static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
2539{
2540 uint32_t *u32;
2541 switch (rtattr->rta_type) {
2542 /* binary: depends on family type */
2543 case RTA_GATEWAY:
2544 case RTA_DST:
2545 case RTA_PREFSRC:
2546 break;
2547 /* u32 */
2548 case RTA_PRIORITY:
2549 case RTA_TABLE:
2550 case RTA_OIF:
2551 u32 = RTA_DATA(rtattr);
2552 *u32 = tswap32(*u32);
2553 break;
2554 default:
2555 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
2556 break;
2557 }
2558 return 0;
2559}
2560
2561static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
2562 uint32_t rtattr_len)
2563{
2564 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2565 host_to_target_data_link_rtattr);
2566}
2567
2568static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
2569 uint32_t rtattr_len)
2570{
2571 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2572 host_to_target_data_addr_rtattr);
2573}
2574
2575static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
2576 uint32_t rtattr_len)
2577{
2578 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
2579 host_to_target_data_route_rtattr);
2580}
2581
2582static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
2583{
2584 uint32_t nlmsg_len;
2585 struct ifinfomsg *ifi;
2586 struct ifaddrmsg *ifa;
2587 struct rtmsg *rtm;
2588
2589 nlmsg_len = nlh->nlmsg_len;
2590 switch (nlh->nlmsg_type) {
2591 case RTM_NEWLINK:
2592 case RTM_DELLINK:
2593 case RTM_GETLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002594 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2595 ifi = NLMSG_DATA(nlh);
2596 ifi->ifi_type = tswap16(ifi->ifi_type);
2597 ifi->ifi_index = tswap32(ifi->ifi_index);
2598 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2599 ifi->ifi_change = tswap32(ifi->ifi_change);
2600 host_to_target_link_rtattr(IFLA_RTA(ifi),
2601 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
2602 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002603 break;
2604 case RTM_NEWADDR:
2605 case RTM_DELADDR:
2606 case RTM_GETADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002607 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2608 ifa = NLMSG_DATA(nlh);
2609 ifa->ifa_index = tswap32(ifa->ifa_index);
2610 host_to_target_addr_rtattr(IFA_RTA(ifa),
2611 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
2612 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002613 break;
2614 case RTM_NEWROUTE:
2615 case RTM_DELROUTE:
2616 case RTM_GETROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002617 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2618 rtm = NLMSG_DATA(nlh);
2619 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2620 host_to_target_route_rtattr(RTM_RTA(rtm),
2621 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
2622 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002623 break;
2624 default:
2625 return -TARGET_EINVAL;
2626 }
2627 return 0;
2628}
2629
2630static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
2631 size_t len)
2632{
2633 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
2634}
2635
2636static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
2637 size_t len,
2638 abi_long (*target_to_host_rtattr)
2639 (struct rtattr *))
2640{
2641 abi_long ret;
2642
2643 while (len >= sizeof(struct rtattr)) {
2644 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
2645 tswap16(rtattr->rta_len) > len) {
2646 break;
2647 }
2648 rtattr->rta_len = tswap16(rtattr->rta_len);
2649 rtattr->rta_type = tswap16(rtattr->rta_type);
2650 ret = target_to_host_rtattr(rtattr);
2651 if (ret < 0) {
2652 return ret;
2653 }
2654 len -= RTA_ALIGN(rtattr->rta_len);
2655 rtattr = (struct rtattr *)(((char *)rtattr) +
2656 RTA_ALIGN(rtattr->rta_len));
2657 }
2658 return 0;
2659}
2660
2661static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
2662{
2663 switch (rtattr->rta_type) {
2664 default:
Michal Privoznik60c6b792016-08-19 10:06:40 +02002665 gemu_log("Unknown target QEMU_IFLA type: %d\n", rtattr->rta_type);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002666 break;
2667 }
2668 return 0;
2669}
2670
2671static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
2672{
2673 switch (rtattr->rta_type) {
2674 /* binary: depends on family type */
2675 case IFA_LOCAL:
2676 case IFA_ADDRESS:
2677 break;
2678 default:
2679 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2680 break;
2681 }
2682 return 0;
2683}
2684
2685static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2686{
2687 uint32_t *u32;
2688 switch (rtattr->rta_type) {
2689 /* binary: depends on family type */
2690 case RTA_DST:
2691 case RTA_SRC:
2692 case RTA_GATEWAY:
2693 break;
2694 /* u32 */
Laurent Vivier434f2862016-10-06 14:55:10 +02002695 case RTA_PRIORITY:
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002696 case RTA_OIF:
2697 u32 = RTA_DATA(rtattr);
2698 *u32 = tswap32(*u32);
2699 break;
2700 default:
2701 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2702 break;
2703 }
2704 return 0;
2705}
2706
2707static void target_to_host_link_rtattr(struct rtattr *rtattr,
2708 uint32_t rtattr_len)
2709{
2710 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2711 target_to_host_data_link_rtattr);
2712}
2713
2714static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2715 uint32_t rtattr_len)
2716{
2717 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2718 target_to_host_data_addr_rtattr);
2719}
2720
2721static void target_to_host_route_rtattr(struct rtattr *rtattr,
2722 uint32_t rtattr_len)
2723{
2724 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2725 target_to_host_data_route_rtattr);
2726}
2727
2728static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2729{
2730 struct ifinfomsg *ifi;
2731 struct ifaddrmsg *ifa;
2732 struct rtmsg *rtm;
2733
2734 switch (nlh->nlmsg_type) {
2735 case RTM_GETLINK:
2736 break;
2737 case RTM_NEWLINK:
2738 case RTM_DELLINK:
Laurent Vivierb9403972016-06-16 21:01:37 +02002739 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
2740 ifi = NLMSG_DATA(nlh);
2741 ifi->ifi_type = tswap16(ifi->ifi_type);
2742 ifi->ifi_index = tswap32(ifi->ifi_index);
2743 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2744 ifi->ifi_change = tswap32(ifi->ifi_change);
2745 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2746 NLMSG_LENGTH(sizeof(*ifi)));
2747 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002748 break;
2749 case RTM_GETADDR:
2750 case RTM_NEWADDR:
2751 case RTM_DELADDR:
Laurent Vivierb9403972016-06-16 21:01:37 +02002752 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
2753 ifa = NLMSG_DATA(nlh);
2754 ifa->ifa_index = tswap32(ifa->ifa_index);
2755 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2756 NLMSG_LENGTH(sizeof(*ifa)));
2757 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002758 break;
2759 case RTM_GETROUTE:
2760 break;
2761 case RTM_NEWROUTE:
2762 case RTM_DELROUTE:
Laurent Vivierb9403972016-06-16 21:01:37 +02002763 if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
2764 rtm = NLMSG_DATA(nlh);
2765 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2766 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2767 NLMSG_LENGTH(sizeof(*rtm)));
2768 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002769 break;
2770 default:
2771 return -TARGET_EOPNOTSUPP;
2772 }
2773 return 0;
2774}
2775
2776static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2777{
2778 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2779}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002780#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002781
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002782static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2783{
2784 switch (nlh->nlmsg_type) {
2785 default:
2786 gemu_log("Unknown host audit message type %d\n",
2787 nlh->nlmsg_type);
2788 return -TARGET_EINVAL;
2789 }
2790 return 0;
2791}
2792
2793static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2794 size_t len)
2795{
2796 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2797}
2798
2799static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2800{
2801 switch (nlh->nlmsg_type) {
2802 case AUDIT_USER:
2803 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2804 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2805 break;
2806 default:
2807 gemu_log("Unknown target audit message type %d\n",
2808 nlh->nlmsg_type);
2809 return -TARGET_EINVAL;
2810 }
2811
2812 return 0;
2813}
2814
2815static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2816{
2817 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2818}
2819
ths0da46a62007-10-20 20:23:07 +00002820/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002821static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002822 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002823{
blueswir1992f48a2007-10-14 16:27:31 +00002824 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002825 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002826 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002827 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002828
bellard8853f862004-02-22 14:57:26 +00002829 switch(level) {
2830 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002831 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002832 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002833 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002834
bellard2f619692007-11-16 10:46:05 +00002835 if (get_user_u32(val, optval_addr))
2836 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002837 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2838 break;
2839 case SOL_IP:
2840 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002841 case IP_TOS:
2842 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002843 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002844 case IP_ROUTER_ALERT:
2845 case IP_RECVOPTS:
2846 case IP_RETOPTS:
2847 case IP_PKTINFO:
2848 case IP_MTU_DISCOVER:
2849 case IP_RECVERR:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002850 case IP_RECVTTL:
bellard2efbe912005-07-23 15:10:20 +00002851 case IP_RECVTOS:
2852#ifdef IP_FREEBIND
2853 case IP_FREEBIND:
2854#endif
2855 case IP_MULTICAST_TTL:
2856 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002857 val = 0;
2858 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002859 if (get_user_u32(val, optval_addr))
2860 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002861 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002862 if (get_user_u8(val, optval_addr))
2863 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002864 }
2865 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2866 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002867 case IP_ADD_MEMBERSHIP:
2868 case IP_DROP_MEMBERSHIP:
2869 if (optlen < sizeof (struct target_ip_mreq) ||
2870 optlen > sizeof (struct target_ip_mreqn))
2871 return -TARGET_EINVAL;
2872
2873 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2874 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2875 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2876 break;
2877
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002878 case IP_BLOCK_SOURCE:
2879 case IP_UNBLOCK_SOURCE:
2880 case IP_ADD_SOURCE_MEMBERSHIP:
2881 case IP_DROP_SOURCE_MEMBERSHIP:
2882 if (optlen != sizeof (struct target_ip_mreq_source))
2883 return -TARGET_EINVAL;
2884
2885 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2886 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2887 unlock_user (ip_mreq_source, optval_addr, 0);
2888 break;
2889
bellard8853f862004-02-22 14:57:26 +00002890 default:
2891 goto unimplemented;
2892 }
2893 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002894 case SOL_IPV6:
2895 switch (optname) {
2896 case IPV6_MTU_DISCOVER:
2897 case IPV6_MTU:
2898 case IPV6_V6ONLY:
2899 case IPV6_RECVPKTINFO:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002900 case IPV6_UNICAST_HOPS:
2901 case IPV6_RECVERR:
2902 case IPV6_RECVHOPLIMIT:
2903 case IPV6_2292HOPLIMIT:
2904 case IPV6_CHECKSUM:
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002905 val = 0;
2906 if (optlen < sizeof(uint32_t)) {
2907 return -TARGET_EINVAL;
2908 }
2909 if (get_user_u32(val, optval_addr)) {
2910 return -TARGET_EFAULT;
2911 }
2912 ret = get_errno(setsockopt(sockfd, level, optname,
2913 &val, sizeof(val)));
2914 break;
Helge Delleree1ac3a2017-02-18 23:31:30 +01002915 case IPV6_PKTINFO:
2916 {
2917 struct in6_pktinfo pki;
2918
2919 if (optlen < sizeof(pki)) {
2920 return -TARGET_EINVAL;
2921 }
2922
2923 if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
2924 return -TARGET_EFAULT;
2925 }
2926
2927 pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
2928
2929 ret = get_errno(setsockopt(sockfd, level, optname,
2930 &pki, sizeof(pki)));
2931 break;
2932 }
2933 default:
2934 goto unimplemented;
2935 }
2936 break;
2937 case SOL_ICMPV6:
2938 switch (optname) {
2939 case ICMPV6_FILTER:
2940 {
2941 struct icmp6_filter icmp6f;
2942
2943 if (optlen > sizeof(icmp6f)) {
2944 optlen = sizeof(icmp6f);
2945 }
2946
2947 if (copy_from_user(&icmp6f, optval_addr, optlen)) {
2948 return -TARGET_EFAULT;
2949 }
2950
2951 for (val = 0; val < 8; val++) {
2952 icmp6f.data[val] = tswap32(icmp6f.data[val]);
2953 }
2954
2955 ret = get_errno(setsockopt(sockfd, level, optname,
2956 &icmp6f, optlen));
2957 break;
2958 }
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002959 default:
2960 goto unimplemented;
2961 }
2962 break;
Jing Huang920394d2012-07-24 13:59:23 +00002963 case SOL_RAW:
2964 switch (optname) {
2965 case ICMP_FILTER:
Helge Delleree1ac3a2017-02-18 23:31:30 +01002966 case IPV6_CHECKSUM:
2967 /* those take an u32 value */
Jing Huang920394d2012-07-24 13:59:23 +00002968 if (optlen < sizeof(uint32_t)) {
2969 return -TARGET_EINVAL;
2970 }
2971
2972 if (get_user_u32(val, optval_addr)) {
2973 return -TARGET_EFAULT;
2974 }
2975 ret = get_errno(setsockopt(sockfd, level, optname,
2976 &val, sizeof(val)));
2977 break;
2978
2979 default:
2980 goto unimplemented;
2981 }
2982 break;
bellard3532fa72006-06-24 15:06:03 +00002983 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002984 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002985 case TARGET_SO_RCVTIMEO:
2986 {
2987 struct timeval tv;
2988
2989 optname = SO_RCVTIMEO;
2990
2991set_timeout:
2992 if (optlen != sizeof(struct target_timeval)) {
2993 return -TARGET_EINVAL;
2994 }
2995
2996 if (copy_from_user_timeval(&tv, optval_addr)) {
2997 return -TARGET_EFAULT;
2998 }
2999
3000 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3001 &tv, sizeof(tv)));
3002 return ret;
3003 }
3004 case TARGET_SO_SNDTIMEO:
3005 optname = SO_SNDTIMEO;
3006 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02003007 case TARGET_SO_ATTACH_FILTER:
3008 {
3009 struct target_sock_fprog *tfprog;
3010 struct target_sock_filter *tfilter;
3011 struct sock_fprog fprog;
3012 struct sock_filter *filter;
3013 int i;
3014
3015 if (optlen != sizeof(*tfprog)) {
3016 return -TARGET_EINVAL;
3017 }
3018 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
3019 return -TARGET_EFAULT;
3020 }
3021 if (!lock_user_struct(VERIFY_READ, tfilter,
3022 tswapal(tfprog->filter), 0)) {
3023 unlock_user_struct(tfprog, optval_addr, 1);
3024 return -TARGET_EFAULT;
3025 }
3026
3027 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303028 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003029 if (filter == NULL) {
3030 unlock_user_struct(tfilter, tfprog->filter, 1);
3031 unlock_user_struct(tfprog, optval_addr, 1);
3032 return -TARGET_ENOMEM;
3033 }
3034 for (i = 0; i < fprog.len; i++) {
3035 filter[i].code = tswap16(tfilter[i].code);
3036 filter[i].jt = tfilter[i].jt;
3037 filter[i].jf = tfilter[i].jf;
3038 filter[i].k = tswap32(tfilter[i].k);
3039 }
3040 fprog.filter = filter;
3041
3042 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
3043 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303044 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02003045
3046 unlock_user_struct(tfilter, tfprog->filter, 1);
3047 unlock_user_struct(tfprog, optval_addr, 1);
3048 return ret;
3049 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003050 case TARGET_SO_BINDTODEVICE:
3051 {
3052 char *dev_ifname, *addr_ifname;
3053
3054 if (optlen > IFNAMSIZ - 1) {
3055 optlen = IFNAMSIZ - 1;
3056 }
3057 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
3058 if (!dev_ifname) {
3059 return -TARGET_EFAULT;
3060 }
3061 optname = SO_BINDTODEVICE;
3062 addr_ifname = alloca(IFNAMSIZ);
3063 memcpy(addr_ifname, dev_ifname, optlen);
3064 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08003065 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
3066 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02003067 unlock_user (dev_ifname, optval_addr, 0);
3068 return ret;
3069 }
bellard8853f862004-02-22 14:57:26 +00003070 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00003071 case TARGET_SO_DEBUG:
3072 optname = SO_DEBUG;
3073 break;
3074 case TARGET_SO_REUSEADDR:
3075 optname = SO_REUSEADDR;
3076 break;
3077 case TARGET_SO_TYPE:
3078 optname = SO_TYPE;
3079 break;
3080 case TARGET_SO_ERROR:
3081 optname = SO_ERROR;
3082 break;
3083 case TARGET_SO_DONTROUTE:
3084 optname = SO_DONTROUTE;
3085 break;
3086 case TARGET_SO_BROADCAST:
3087 optname = SO_BROADCAST;
3088 break;
3089 case TARGET_SO_SNDBUF:
3090 optname = SO_SNDBUF;
3091 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003092 case TARGET_SO_SNDBUFFORCE:
3093 optname = SO_SNDBUFFORCE;
3094 break;
bellard3532fa72006-06-24 15:06:03 +00003095 case TARGET_SO_RCVBUF:
3096 optname = SO_RCVBUF;
3097 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01003098 case TARGET_SO_RCVBUFFORCE:
3099 optname = SO_RCVBUFFORCE;
3100 break;
bellard3532fa72006-06-24 15:06:03 +00003101 case TARGET_SO_KEEPALIVE:
3102 optname = SO_KEEPALIVE;
3103 break;
3104 case TARGET_SO_OOBINLINE:
3105 optname = SO_OOBINLINE;
3106 break;
3107 case TARGET_SO_NO_CHECK:
3108 optname = SO_NO_CHECK;
3109 break;
3110 case TARGET_SO_PRIORITY:
3111 optname = SO_PRIORITY;
3112 break;
bellard5e83e8e2005-03-01 22:32:06 +00003113#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00003114 case TARGET_SO_BSDCOMPAT:
3115 optname = SO_BSDCOMPAT;
3116 break;
bellard5e83e8e2005-03-01 22:32:06 +00003117#endif
bellard3532fa72006-06-24 15:06:03 +00003118 case TARGET_SO_PASSCRED:
3119 optname = SO_PASSCRED;
3120 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01003121 case TARGET_SO_PASSSEC:
3122 optname = SO_PASSSEC;
3123 break;
bellard3532fa72006-06-24 15:06:03 +00003124 case TARGET_SO_TIMESTAMP:
3125 optname = SO_TIMESTAMP;
3126 break;
3127 case TARGET_SO_RCVLOWAT:
3128 optname = SO_RCVLOWAT;
3129 break;
bellard8853f862004-02-22 14:57:26 +00003130 break;
3131 default:
3132 goto unimplemented;
3133 }
bellard3532fa72006-06-24 15:06:03 +00003134 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00003135 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00003136
bellard2f619692007-11-16 10:46:05 +00003137 if (get_user_u32(val, optval_addr))
3138 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00003139 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00003140 break;
bellard7854b052003-03-29 17:22:23 +00003141 default:
bellard8853f862004-02-22 14:57:26 +00003142 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02003143 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00003144 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00003145 }
bellard8853f862004-02-22 14:57:26 +00003146 return ret;
bellard7854b052003-03-29 17:22:23 +00003147}
3148
ths0da46a62007-10-20 20:23:07 +00003149/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003150static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00003151 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00003152{
blueswir1992f48a2007-10-14 16:27:31 +00003153 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00003154 int len, val;
3155 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00003156
3157 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00003158 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003159 level = SOL_SOCKET;
3160 switch (optname) {
3161 /* These don't just return a single integer */
3162 case TARGET_SO_LINGER:
3163 case TARGET_SO_RCVTIMEO:
3164 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003165 case TARGET_SO_PEERNAME:
3166 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02003167 case TARGET_SO_PEERCRED: {
3168 struct ucred cr;
3169 socklen_t crlen;
3170 struct target_ucred *tcr;
3171
3172 if (get_user_u32(len, optlen)) {
3173 return -TARGET_EFAULT;
3174 }
3175 if (len < 0) {
3176 return -TARGET_EINVAL;
3177 }
3178
3179 crlen = sizeof(cr);
3180 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
3181 &cr, &crlen));
3182 if (ret < 0) {
3183 return ret;
3184 }
3185 if (len > crlen) {
3186 len = crlen;
3187 }
3188 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
3189 return -TARGET_EFAULT;
3190 }
3191 __put_user(cr.pid, &tcr->pid);
3192 __put_user(cr.uid, &tcr->uid);
3193 __put_user(cr.gid, &tcr->gid);
3194 unlock_user_struct(tcr, optval_addr, 1);
3195 if (put_user_u32(len, optlen)) {
3196 return -TARGET_EFAULT;
3197 }
3198 break;
3199 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003200 /* Options with 'int' argument. */
3201 case TARGET_SO_DEBUG:
3202 optname = SO_DEBUG;
3203 goto int_case;
3204 case TARGET_SO_REUSEADDR:
3205 optname = SO_REUSEADDR;
3206 goto int_case;
3207 case TARGET_SO_TYPE:
3208 optname = SO_TYPE;
3209 goto int_case;
3210 case TARGET_SO_ERROR:
3211 optname = SO_ERROR;
3212 goto int_case;
3213 case TARGET_SO_DONTROUTE:
3214 optname = SO_DONTROUTE;
3215 goto int_case;
3216 case TARGET_SO_BROADCAST:
3217 optname = SO_BROADCAST;
3218 goto int_case;
3219 case TARGET_SO_SNDBUF:
3220 optname = SO_SNDBUF;
3221 goto int_case;
3222 case TARGET_SO_RCVBUF:
3223 optname = SO_RCVBUF;
3224 goto int_case;
3225 case TARGET_SO_KEEPALIVE:
3226 optname = SO_KEEPALIVE;
3227 goto int_case;
3228 case TARGET_SO_OOBINLINE:
3229 optname = SO_OOBINLINE;
3230 goto int_case;
3231 case TARGET_SO_NO_CHECK:
3232 optname = SO_NO_CHECK;
3233 goto int_case;
3234 case TARGET_SO_PRIORITY:
3235 optname = SO_PRIORITY;
3236 goto int_case;
3237#ifdef SO_BSDCOMPAT
3238 case TARGET_SO_BSDCOMPAT:
3239 optname = SO_BSDCOMPAT;
3240 goto int_case;
3241#endif
3242 case TARGET_SO_PASSCRED:
3243 optname = SO_PASSCRED;
3244 goto int_case;
3245 case TARGET_SO_TIMESTAMP:
3246 optname = SO_TIMESTAMP;
3247 goto int_case;
3248 case TARGET_SO_RCVLOWAT:
3249 optname = SO_RCVLOWAT;
3250 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01003251 case TARGET_SO_ACCEPTCONN:
3252 optname = SO_ACCEPTCONN;
3253 goto int_case;
bellard8853f862004-02-22 14:57:26 +00003254 default:
bellard2efbe912005-07-23 15:10:20 +00003255 goto int_case;
3256 }
3257 break;
3258 case SOL_TCP:
3259 /* TCP options all take an 'int' value. */
3260 int_case:
bellard2f619692007-11-16 10:46:05 +00003261 if (get_user_u32(len, optlen))
3262 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003263 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003264 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003265 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00003266 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3267 if (ret < 0)
3268 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01003269 if (optname == SO_TYPE) {
3270 val = host_to_target_sock_type(val);
3271 }
bellard2efbe912005-07-23 15:10:20 +00003272 if (len > lv)
3273 len = lv;
bellard2f619692007-11-16 10:46:05 +00003274 if (len == 4) {
3275 if (put_user_u32(val, optval_addr))
3276 return -TARGET_EFAULT;
3277 } else {
3278 if (put_user_u8(val, optval_addr))
3279 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02003280 }
bellard2f619692007-11-16 10:46:05 +00003281 if (put_user_u32(len, optlen))
3282 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003283 break;
3284 case SOL_IP:
3285 switch(optname) {
3286 case IP_TOS:
3287 case IP_TTL:
3288 case IP_HDRINCL:
3289 case IP_ROUTER_ALERT:
3290 case IP_RECVOPTS:
3291 case IP_RETOPTS:
3292 case IP_PKTINFO:
3293 case IP_MTU_DISCOVER:
3294 case IP_RECVERR:
3295 case IP_RECVTOS:
3296#ifdef IP_FREEBIND
3297 case IP_FREEBIND:
3298#endif
3299 case IP_MULTICAST_TTL:
3300 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00003301 if (get_user_u32(len, optlen))
3302 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00003303 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00003304 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05003305 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00003306 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
3307 if (ret < 0)
3308 return ret;
bellard2efbe912005-07-23 15:10:20 +00003309 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00003310 len = 1;
bellard2f619692007-11-16 10:46:05 +00003311 if (put_user_u32(len, optlen)
3312 || put_user_u8(val, optval_addr))
3313 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003314 } else {
bellard2efbe912005-07-23 15:10:20 +00003315 if (len > sizeof(int))
3316 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00003317 if (put_user_u32(len, optlen)
3318 || put_user_u32(val, optval_addr))
3319 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00003320 }
bellard8853f862004-02-22 14:57:26 +00003321 break;
bellard2efbe912005-07-23 15:10:20 +00003322 default:
thsc02f4992007-12-18 02:39:59 +00003323 ret = -TARGET_ENOPROTOOPT;
3324 break;
bellard8853f862004-02-22 14:57:26 +00003325 }
3326 break;
3327 default:
3328 unimplemented:
3329 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
3330 level, optname);
thsc02f4992007-12-18 02:39:59 +00003331 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00003332 break;
3333 }
3334 return ret;
bellard7854b052003-03-29 17:22:23 +00003335}
3336
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003337static struct iovec *lock_iovec(int type, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003338 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003339{
3340 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003341 struct iovec *vec;
3342 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00003343 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00003344 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05003345 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00003346
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003347 if (count == 0) {
3348 errno = 0;
3349 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003350 }
Peter Maydelldab32b32016-07-15 14:57:26 +01003351 if (count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003352 errno = EINVAL;
3353 return NULL;
3354 }
3355
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303356 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003357 if (vec == NULL) {
3358 errno = ENOMEM;
3359 return NULL;
3360 }
3361
3362 target_vec = lock_user(VERIFY_READ, target_addr,
3363 count * sizeof(struct target_iovec), 1);
3364 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003365 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003366 goto fail2;
3367 }
3368
3369 /* ??? If host page size > target page size, this will result in a
3370 value larger than what we can actually support. */
3371 max_len = 0x7fffffff & TARGET_PAGE_MASK;
3372 total_len = 0;
3373
3374 for (i = 0; i < count; i++) {
3375 abi_ulong base = tswapal(target_vec[i].iov_base);
3376 abi_long len = tswapal(target_vec[i].iov_len);
3377
3378 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00003379 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003380 goto fail;
3381 } else if (len == 0) {
3382 /* Zero length pointer is ignored. */
3383 vec[i].iov_base = 0;
3384 } else {
3385 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05003386 /* If the first buffer pointer is bad, this is a fault. But
3387 * subsequent bad buffers will result in a partial write; this
3388 * is realized by filling the vector with null pointers and
3389 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003390 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05003391 if (i == 0) {
3392 err = EFAULT;
3393 goto fail;
3394 } else {
3395 bad_address = true;
3396 }
3397 }
3398 if (bad_address) {
3399 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003400 }
3401 if (len > max_len - total_len) {
3402 len = max_len - total_len;
3403 }
3404 }
3405 vec[i].iov_len = len;
3406 total_len += len;
3407 }
3408
3409 unlock_user(target_vec, target_addr, 0);
3410 return vec;
3411
3412 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08003413 while (--i >= 0) {
3414 if (tswapal(target_vec[i].iov_len) > 0) {
3415 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
3416 }
3417 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003418 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003419 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303420 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00003421 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003422 return NULL;
pbrook53a59602006-03-25 19:31:22 +00003423}
3424
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003425static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
Peter Maydelldab32b32016-07-15 14:57:26 +01003426 abi_ulong count, int copy)
pbrook53a59602006-03-25 19:31:22 +00003427{
3428 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00003429 int i;
3430
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003431 target_vec = lock_user(VERIFY_READ, target_addr,
3432 count * sizeof(struct target_iovec), 1);
3433 if (target_vec) {
3434 for (i = 0; i < count; i++) {
3435 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08003436 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003437 if (len < 0) {
3438 break;
3439 }
balrogd732dcb2008-10-28 10:21:03 +00003440 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
3441 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003442 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00003443 }
bellard579a97f2007-11-11 14:26:47 +00003444
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303445 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00003446}
3447
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003448static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003449{
3450 int host_type = 0;
3451 int target_type = *type;
3452
3453 switch (target_type & TARGET_SOCK_TYPE_MASK) {
3454 case TARGET_SOCK_DGRAM:
3455 host_type = SOCK_DGRAM;
3456 break;
3457 case TARGET_SOCK_STREAM:
3458 host_type = SOCK_STREAM;
3459 break;
3460 default:
3461 host_type = target_type & TARGET_SOCK_TYPE_MASK;
3462 break;
3463 }
3464 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003465#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003466 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003467#else
3468 return -TARGET_EINVAL;
3469#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003470 }
3471 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003472#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003473 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003474#elif !defined(O_NONBLOCK)
3475 return -TARGET_EINVAL;
3476#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003477 }
3478 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003479 return 0;
3480}
3481
3482/* Try to emulate socket type flags after socket creation. */
3483static int sock_flags_fixup(int fd, int target_type)
3484{
3485#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
3486 if (target_type & TARGET_SOCK_NONBLOCK) {
3487 int flags = fcntl(fd, F_GETFL);
3488 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
3489 close(fd);
3490 return -TARGET_EINVAL;
3491 }
3492 }
3493#endif
3494 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003495}
3496
Laurent Vivier0cf22722015-10-28 21:40:45 +01003497static abi_long packet_target_to_host_sockaddr(void *host_addr,
3498 abi_ulong target_addr,
3499 socklen_t len)
3500{
3501 struct sockaddr *addr = host_addr;
3502 struct target_sockaddr *target_saddr;
3503
3504 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
3505 if (!target_saddr) {
3506 return -TARGET_EFAULT;
3507 }
3508
3509 memcpy(addr, target_saddr, len);
3510 addr->sa_family = tswap16(target_saddr->sa_family);
3511 /* spkt_protocol is big-endian */
3512
3513 unlock_user(target_saddr, target_addr, 0);
3514 return 0;
3515}
3516
3517static TargetFdTrans target_packet_trans = {
3518 .target_to_host_addr = packet_target_to_host_sockaddr,
3519};
3520
Laurent Vivier575b22b2016-06-02 22:14:15 +02003521#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003522static abi_long netlink_route_target_to_host(void *buf, size_t len)
3523{
Laurent Vivieref759f62016-06-21 19:51:13 +02003524 abi_long ret;
3525
3526 ret = target_to_host_nlmsg_route(buf, len);
3527 if (ret < 0) {
3528 return ret;
3529 }
3530
3531 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003532}
3533
3534static abi_long netlink_route_host_to_target(void *buf, size_t len)
3535{
Laurent Vivieref759f62016-06-21 19:51:13 +02003536 abi_long ret;
3537
3538 ret = host_to_target_nlmsg_route(buf, len);
3539 if (ret < 0) {
3540 return ret;
3541 }
3542
3543 return len;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003544}
3545
3546static TargetFdTrans target_netlink_route_trans = {
3547 .target_to_host_data = netlink_route_target_to_host,
3548 .host_to_target_data = netlink_route_host_to_target,
3549};
Laurent Vivier575b22b2016-06-02 22:14:15 +02003550#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003551
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003552static abi_long netlink_audit_target_to_host(void *buf, size_t len)
3553{
Laurent Vivieref759f62016-06-21 19:51:13 +02003554 abi_long ret;
3555
3556 ret = target_to_host_nlmsg_audit(buf, len);
3557 if (ret < 0) {
3558 return ret;
3559 }
3560
3561 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003562}
3563
3564static abi_long netlink_audit_host_to_target(void *buf, size_t len)
3565{
Laurent Vivieref759f62016-06-21 19:51:13 +02003566 abi_long ret;
3567
3568 ret = host_to_target_nlmsg_audit(buf, len);
3569 if (ret < 0) {
3570 return ret;
3571 }
3572
3573 return len;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003574}
3575
3576static TargetFdTrans target_netlink_audit_trans = {
3577 .target_to_host_data = netlink_audit_target_to_host,
3578 .host_to_target_data = netlink_audit_host_to_target,
3579};
3580
ths0da46a62007-10-20 20:23:07 +00003581/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003582static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00003583{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003584 int target_type = type;
3585 int ret;
3586
3587 ret = target_to_host_sock_type(&type);
3588 if (ret) {
3589 return ret;
3590 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003591
Laurent Vivier575b22b2016-06-02 22:14:15 +02003592 if (domain == PF_NETLINK && !(
3593#ifdef CONFIG_RTNETLINK
3594 protocol == NETLINK_ROUTE ||
3595#endif
3596 protocol == NETLINK_KOBJECT_UEVENT ||
3597 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003598 return -EPFNOSUPPORT;
3599 }
Laurent Vivierff626f22015-10-28 21:40:42 +01003600
3601 if (domain == AF_PACKET ||
3602 (domain == AF_INET && type == SOCK_PACKET)) {
3603 protocol = tswap16(protocol);
3604 }
3605
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003606 ret = get_errno(socket(domain, type, protocol));
3607 if (ret >= 0) {
3608 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01003609 if (type == SOCK_PACKET) {
3610 /* Manage an obsolete case :
3611 * if socket type is SOCK_PACKET, bind by name
3612 */
3613 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003614 } else if (domain == PF_NETLINK) {
3615 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02003616#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003617 case NETLINK_ROUTE:
3618 fd_trans_register(ret, &target_netlink_route_trans);
3619 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02003620#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02003621 case NETLINK_KOBJECT_UEVENT:
3622 /* nothing to do: messages are strings */
3623 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02003624 case NETLINK_AUDIT:
3625 fd_trans_register(ret, &target_netlink_audit_trans);
3626 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003627 default:
3628 g_assert_not_reached();
3629 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01003630 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02003631 }
3632 return ret;
bellard3532fa72006-06-24 15:06:03 +00003633}
3634
ths0da46a62007-10-20 20:23:07 +00003635/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003636static abi_long do_bind(int sockfd, abi_ulong target_addr,
3637 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003638{
aurel328f7aeaf2009-01-30 19:47:57 +00003639 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003640 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003641
Blue Swirl38724252010-09-18 05:53:14 +00003642 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003643 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003644 }
aurel328f7aeaf2009-01-30 19:47:57 +00003645
aurel32607175e2009-04-15 16:11:59 +00003646 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003647
Laurent Vivier7b36f782015-10-28 21:40:44 +01003648 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003649 if (ret)
3650 return ret;
3651
bellard3532fa72006-06-24 15:06:03 +00003652 return get_errno(bind(sockfd, addr, addrlen));
3653}
3654
ths0da46a62007-10-20 20:23:07 +00003655/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003656static abi_long do_connect(int sockfd, abi_ulong target_addr,
3657 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00003658{
aurel328f7aeaf2009-01-30 19:47:57 +00003659 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03003660 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00003661
Blue Swirl38724252010-09-18 05:53:14 +00003662 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003663 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003664 }
aurel328f7aeaf2009-01-30 19:47:57 +00003665
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003666 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00003667
Laurent Vivier7b36f782015-10-28 21:40:44 +01003668 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003669 if (ret)
3670 return ret;
3671
Peter Maydell2a3c7612016-06-06 19:58:03 +01003672 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00003673}
3674
Alexander Graff19e00d2014-03-02 19:36:42 +00003675/* do_sendrecvmsg_locked() Must return target values and target errnos. */
3676static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
3677 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00003678{
balrog6de645c2008-10-28 10:26:29 +00003679 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00003680 struct msghdr msg;
Peter Maydelldab32b32016-07-15 14:57:26 +01003681 abi_ulong count;
bellard3532fa72006-06-24 15:06:03 +00003682 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00003683 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00003684
bellard3532fa72006-06-24 15:06:03 +00003685 if (msgp->msg_name) {
3686 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003687 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003688 ret = target_to_host_sockaddr(fd, msg.msg_name,
3689 tswapal(msgp->msg_name),
3690 msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003691 if (ret == -TARGET_EFAULT) {
3692 /* For connected sockets msg_name and msg_namelen must
3693 * be ignored, so returning EFAULT immediately is wrong.
3694 * Instead, pass a bad msg_name to the host kernel, and
3695 * let it decide whether to return EFAULT or not.
3696 */
3697 msg.msg_name = (void *)-1;
3698 } else if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003699 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03003700 }
bellard3532fa72006-06-24 15:06:03 +00003701 } else {
3702 msg.msg_name = NULL;
3703 msg.msg_namelen = 0;
3704 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003705 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00003706 msg.msg_control = alloca(msg.msg_controllen);
3707 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00003708
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003709 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003710 target_vec = tswapal(msgp->msg_iov);
Peter Maydell97b07972016-07-15 14:57:27 +01003711
3712 if (count > IOV_MAX) {
3713 /* sendrcvmsg returns a different errno for this condition than
3714 * readv/writev, so we must catch it here before lock_iovec() does.
3715 */
3716 ret = -TARGET_EMSGSIZE;
3717 goto out2;
3718 }
3719
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003720 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
3721 target_vec, count, send);
3722 if (vec == NULL) {
3723 ret = -host_to_target_errno(errno);
3724 goto out2;
3725 }
bellard3532fa72006-06-24 15:06:03 +00003726 msg.msg_iovlen = count;
3727 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00003728
bellard3532fa72006-06-24 15:06:03 +00003729 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003730 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003731 void *host_msg;
3732
3733 host_msg = g_malloc(msg.msg_iov->iov_len);
3734 memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len);
3735 ret = fd_trans_target_to_host_data(fd)(host_msg,
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003736 msg.msg_iov->iov_len);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003737 if (ret >= 0) {
3738 msg.msg_iov->iov_base = host_msg;
3739 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3740 }
3741 g_free(host_msg);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003742 } else {
3743 ret = target_to_host_cmsg(&msg, msgp);
Laurent Vivier7d61d892016-06-21 19:51:14 +02003744 if (ret == 0) {
3745 ret = get_errno(safe_sendmsg(fd, &msg, flags));
3746 }
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003747 }
bellard3532fa72006-06-24 15:06:03 +00003748 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003749 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00003750 if (!is_error(ret)) {
3751 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003752 if (fd_trans_host_to_target_data(fd)) {
3753 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
Laurent Vivier48dc0f22016-06-16 21:01:36 +02003754 len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003755 } else {
3756 ret = host_to_target_cmsg(msgp, &msg);
3757 }
Jing Huangca619062012-07-24 13:58:02 +00003758 if (!is_error(ret)) {
3759 msgp->msg_namelen = tswap32(msg.msg_namelen);
Peter Maydell26a6fc92016-07-15 14:57:28 +01003760 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
Jing Huangca619062012-07-24 13:58:02 +00003761 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
3762 msg.msg_name, msg.msg_namelen);
3763 if (ret) {
3764 goto out;
3765 }
3766 }
3767
balrog6de645c2008-10-28 10:26:29 +00003768 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00003769 }
balrog6de645c2008-10-28 10:26:29 +00003770 }
bellard3532fa72006-06-24 15:06:03 +00003771 }
Jing Huangca619062012-07-24 13:58:02 +00003772
3773out:
bellard3532fa72006-06-24 15:06:03 +00003774 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07003775out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00003776 return ret;
3777}
3778
3779static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
3780 int flags, int send)
3781{
3782 abi_long ret;
3783 struct target_msghdr *msgp;
3784
3785 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3786 msgp,
3787 target_msg,
3788 send ? 1 : 0)) {
3789 return -TARGET_EFAULT;
3790 }
3791 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003792 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003793 return ret;
3794}
3795
Alexander Graff19e00d2014-03-02 19:36:42 +00003796/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3797 * so it might not have this *mmsg-specific flag either.
3798 */
3799#ifndef MSG_WAITFORONE
3800#define MSG_WAITFORONE 0x10000
3801#endif
3802
3803static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3804 unsigned int vlen, unsigned int flags,
3805 int send)
3806{
3807 struct target_mmsghdr *mmsgp;
3808 abi_long ret = 0;
3809 int i;
3810
3811 if (vlen > UIO_MAXIOV) {
3812 vlen = UIO_MAXIOV;
3813 }
3814
3815 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3816 if (!mmsgp) {
3817 return -TARGET_EFAULT;
3818 }
3819
3820 for (i = 0; i < vlen; i++) {
3821 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3822 if (is_error(ret)) {
3823 break;
3824 }
3825 mmsgp[i].msg_len = tswap32(ret);
3826 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3827 if (flags & MSG_WAITFORONE) {
3828 flags |= MSG_DONTWAIT;
3829 }
3830 }
3831
3832 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3833
3834 /* Return number of datagrams sent if we sent any at all;
3835 * otherwise return the error.
3836 */
3837 if (i) {
3838 return i;
3839 }
3840 return ret;
3841}
Alexander Graff19e00d2014-03-02 19:36:42 +00003842
Peter Maydella94b4982013-02-08 04:35:04 +00003843/* do_accept4() Must return target values and target errnos. */
3844static abi_long do_accept4(int fd, abi_ulong target_addr,
3845 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003846{
bellard2f619692007-11-16 10:46:05 +00003847 socklen_t addrlen;
3848 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003849 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003850 int host_flags;
3851
3852 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003853
Peter Maydella94b4982013-02-08 04:35:04 +00003854 if (target_addr == 0) {
Peter Maydellff6dc132016-06-06 19:58:13 +01003855 return get_errno(safe_accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003856 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003857
3858 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003859 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003860 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003861
Blue Swirl38724252010-09-18 05:53:14 +00003862 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003863 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003864 }
aurel328f7aeaf2009-01-30 19:47:57 +00003865
Arnaud Patard917507b2009-06-19 10:44:45 +03003866 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3867 return -TARGET_EINVAL;
3868
bellard2f619692007-11-16 10:46:05 +00003869 addr = alloca(addrlen);
3870
Peter Maydellff6dc132016-06-06 19:58:13 +01003871 ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003872 if (!is_error(ret)) {
3873 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003874 if (put_user_u32(addrlen, target_addrlen_addr))
3875 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003876 }
3877 return ret;
3878}
3879
ths0da46a62007-10-20 20:23:07 +00003880/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003881static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003882 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003883{
bellard2f619692007-11-16 10:46:05 +00003884 socklen_t addrlen;
3885 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003886 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003887
bellard2f619692007-11-16 10:46:05 +00003888 if (get_user_u32(addrlen, target_addrlen_addr))
3889 return -TARGET_EFAULT;
3890
Blue Swirl38724252010-09-18 05:53:14 +00003891 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003892 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003893 }
aurel328f7aeaf2009-01-30 19:47:57 +00003894
Arnaud Patard917507b2009-06-19 10:44:45 +03003895 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3896 return -TARGET_EFAULT;
3897
bellard2f619692007-11-16 10:46:05 +00003898 addr = alloca(addrlen);
3899
pbrook1be9e1d2006-11-19 15:26:04 +00003900 ret = get_errno(getpeername(fd, addr, &addrlen));
3901 if (!is_error(ret)) {
3902 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003903 if (put_user_u32(addrlen, target_addrlen_addr))
3904 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003905 }
3906 return ret;
3907}
3908
ths0da46a62007-10-20 20:23:07 +00003909/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003910static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003911 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003912{
bellard2f619692007-11-16 10:46:05 +00003913 socklen_t addrlen;
3914 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003915 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003916
bellard2f619692007-11-16 10:46:05 +00003917 if (get_user_u32(addrlen, target_addrlen_addr))
3918 return -TARGET_EFAULT;
3919
Blue Swirl38724252010-09-18 05:53:14 +00003920 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003921 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003922 }
aurel328f7aeaf2009-01-30 19:47:57 +00003923
Arnaud Patard917507b2009-06-19 10:44:45 +03003924 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3925 return -TARGET_EFAULT;
3926
bellard2f619692007-11-16 10:46:05 +00003927 addr = alloca(addrlen);
3928
pbrook1be9e1d2006-11-19 15:26:04 +00003929 ret = get_errno(getsockname(fd, addr, &addrlen));
3930 if (!is_error(ret)) {
3931 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003932 if (put_user_u32(addrlen, target_addrlen_addr))
3933 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003934 }
3935 return ret;
3936}
3937
ths0da46a62007-10-20 20:23:07 +00003938/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003939static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003940 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003941{
3942 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003943 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003944
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003945 target_to_host_sock_type(&type);
3946
pbrook1be9e1d2006-11-19 15:26:04 +00003947 ret = get_errno(socketpair(domain, type, protocol, tab));
3948 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003949 if (put_user_s32(tab[0], target_tab_addr)
3950 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3951 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003952 }
3953 return ret;
3954}
3955
ths0da46a62007-10-20 20:23:07 +00003956/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003957static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3958 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003959{
3960 void *addr;
3961 void *host_msg;
Laurent Vivier7d61d892016-06-21 19:51:14 +02003962 void *copy_msg = NULL;
blueswir1992f48a2007-10-14 16:27:31 +00003963 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003964
Blue Swirl38724252010-09-18 05:53:14 +00003965 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003966 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003967 }
aurel328f7aeaf2009-01-30 19:47:57 +00003968
bellard579a97f2007-11-11 14:26:47 +00003969 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3970 if (!host_msg)
3971 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003972 if (fd_trans_target_to_host_data(fd)) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003973 copy_msg = host_msg;
3974 host_msg = g_malloc(len);
3975 memcpy(host_msg, copy_msg, len);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003976 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3977 if (ret < 0) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003978 goto fail;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003979 }
3980 }
pbrook1be9e1d2006-11-19 15:26:04 +00003981 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003982 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003983 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003984 if (ret) {
Laurent Vivier7d61d892016-06-21 19:51:14 +02003985 goto fail;
Arnaud Patard917507b2009-06-19 10:44:45 +03003986 }
Peter Maydell66687532016-06-06 19:58:04 +01003987 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003988 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003989 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003990 }
Laurent Vivier7d61d892016-06-21 19:51:14 +02003991fail:
3992 if (copy_msg) {
3993 g_free(host_msg);
3994 host_msg = copy_msg;
3995 }
pbrook1be9e1d2006-11-19 15:26:04 +00003996 unlock_user(host_msg, msg, 0);
3997 return ret;
3998}
3999
ths0da46a62007-10-20 20:23:07 +00004000/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004001static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
4002 abi_ulong target_addr,
4003 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00004004{
4005 socklen_t addrlen;
4006 void *addr;
4007 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00004008 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00004009
bellard579a97f2007-11-11 14:26:47 +00004010 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
4011 if (!host_msg)
4012 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00004013 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00004014 if (get_user_u32(addrlen, target_addrlen)) {
4015 ret = -TARGET_EFAULT;
4016 goto fail;
4017 }
Blue Swirl38724252010-09-18 05:53:14 +00004018 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00004019 ret = -TARGET_EINVAL;
4020 goto fail;
4021 }
pbrook1be9e1d2006-11-19 15:26:04 +00004022 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01004023 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
4024 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00004025 } else {
4026 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01004027 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00004028 }
4029 if (!is_error(ret)) {
Laurent Vivierc35e1f92016-06-21 19:51:15 +02004030 if (fd_trans_host_to_target_data(fd)) {
4031 ret = fd_trans_host_to_target_data(fd)(host_msg, ret);
4032 }
pbrook1be9e1d2006-11-19 15:26:04 +00004033 if (target_addr) {
4034 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00004035 if (put_user_u32(addrlen, target_addrlen)) {
4036 ret = -TARGET_EFAULT;
4037 goto fail;
4038 }
pbrook1be9e1d2006-11-19 15:26:04 +00004039 }
4040 unlock_user(host_msg, msg, len);
4041 } else {
bellard2f619692007-11-16 10:46:05 +00004042fail:
pbrook1be9e1d2006-11-19 15:26:04 +00004043 unlock_user(host_msg, msg, 0);
4044 }
4045 return ret;
4046}
4047
j_mayer32407102007-09-26 23:01:49 +00004048#ifdef TARGET_NR_socketcall
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004049/* do_socketcall() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00004050static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00004051{
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004052 static const unsigned nargs[] = { /* number of arguments per operation */
4053 [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
4054 [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
4055 [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
4056 [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
4057 [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
4058 [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
4059 [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
4060 [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
4061 [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
4062 [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
4063 [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
4064 [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
4065 [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
4066 [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4067 [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
4068 [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
4069 [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
4070 [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
4071 [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
4072 [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004073 };
4074 abi_long a[6]; /* max 6 args */
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004075 unsigned i;
bellard31e31b82003-02-18 22:55:36 +00004076
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004077 /* check the range of the first argument num */
4078 /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
4079 if (num < 1 || num > TARGET_SYS_SENDMMSG) {
4080 return -TARGET_EINVAL;
4081 }
4082 /* ensure we have space for args */
4083 if (nargs[num] > ARRAY_SIZE(a)) {
4084 return -TARGET_EINVAL;
4085 }
4086 /* collect the arguments in a[] according to nargs[] */
4087 for (i = 0; i < nargs[num]; ++i) {
4088 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
4089 return -TARGET_EFAULT;
André Hentschelb9d36eb2014-01-06 20:18:52 +01004090 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004091 }
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004092 /* now when we have the args, invoke the appropriate underlying function */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004093 switch (num) {
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004094 case TARGET_SYS_SOCKET: /* domain, type, protocol */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004095 return do_socket(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004096 case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004097 return do_bind(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004098 case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004099 return do_connect(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004100 case TARGET_SYS_LISTEN: /* sockfd, backlog */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004101 return get_errno(listen(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004102 case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004103 return do_accept4(a[0], a[1], a[2], 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004104 case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004105 return do_getsockname(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004106 case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004107 return do_getpeername(a[0], a[1], a[2]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004108 case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004109 return do_socketpair(a[0], a[1], a[2], a[3]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004110 case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004111 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004112 case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004113 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004114 case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004115 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004116 case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004117 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004118 case TARGET_SYS_SHUTDOWN: /* sockfd, how */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004119 return get_errno(shutdown(a[0], a[1]));
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004120 case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004121 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004122 case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04004123 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004124 case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
4125 return do_sendrecvmsg(a[0], a[1], a[2], 1);
4126 case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
4127 return do_sendrecvmsg(a[0], a[1], a[2], 0);
4128 case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
4129 return do_accept4(a[0], a[1], a[2], a[3]);
4130 case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
4131 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
4132 case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
4133 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
bellard31e31b82003-02-18 22:55:36 +00004134 default:
4135 gemu_log("Unsupported socketcall: %d\n", num);
Aleksandar Markovicff71a452016-09-22 18:56:57 +02004136 return -TARGET_EINVAL;
bellard31e31b82003-02-18 22:55:36 +00004137 }
bellard31e31b82003-02-18 22:55:36 +00004138}
j_mayer32407102007-09-26 23:01:49 +00004139#endif
bellard31e31b82003-02-18 22:55:36 +00004140
bellard8853f862004-02-22 14:57:26 +00004141#define N_SHM_REGIONS 32
4142
4143static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00004144 abi_ulong start;
4145 abi_ulong size;
4146 bool in_use;
bellard8853f862004-02-22 14:57:26 +00004147} shm_regions[N_SHM_REGIONS];
4148
Peter Maydell005eb2a2016-07-15 16:50:47 +01004149#ifndef TARGET_SEMID64_DS
4150/* asm-generic version of this struct */
4151struct target_semid64_ds
ths3eb6b042007-06-03 14:26:27 +00004152{
4153 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00004154 abi_ulong sem_otime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004155#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004156 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05004157#endif
blueswir1992f48a2007-10-14 16:27:31 +00004158 abi_ulong sem_ctime;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004159#if TARGET_ABI_BITS == 32
blueswir1992f48a2007-10-14 16:27:31 +00004160 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05004161#endif
blueswir1992f48a2007-10-14 16:27:31 +00004162 abi_ulong sem_nsems;
4163 abi_ulong __unused3;
4164 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00004165};
Peter Maydell005eb2a2016-07-15 16:50:47 +01004166#endif
ths3eb6b042007-06-03 14:26:27 +00004167
bellard579a97f2007-11-11 14:26:47 +00004168static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
4169 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004170{
4171 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004172 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004173
bellard579a97f2007-11-11 14:26:47 +00004174 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4175 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00004176 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004177 host_ip->__key = tswap32(target_ip->__key);
4178 host_ip->uid = tswap32(target_ip->uid);
4179 host_ip->gid = tswap32(target_ip->gid);
4180 host_ip->cuid = tswap32(target_ip->cuid);
4181 host_ip->cgid = tswap32(target_ip->cgid);
4182#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4183 host_ip->mode = tswap32(target_ip->mode);
4184#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004185 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004186#endif
4187#if defined(TARGET_PPC)
4188 host_ip->__seq = tswap32(target_ip->__seq);
4189#else
4190 host_ip->__seq = tswap16(target_ip->__seq);
4191#endif
ths3eb6b042007-06-03 14:26:27 +00004192 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004193 return 0;
ths3eb6b042007-06-03 14:26:27 +00004194}
4195
bellard579a97f2007-11-11 14:26:47 +00004196static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
4197 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00004198{
4199 struct target_ipc_perm *target_ip;
Peter Maydell005eb2a2016-07-15 16:50:47 +01004200 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004201
bellard579a97f2007-11-11 14:26:47 +00004202 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4203 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00004204 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004205 target_ip->__key = tswap32(host_ip->__key);
4206 target_ip->uid = tswap32(host_ip->uid);
4207 target_ip->gid = tswap32(host_ip->gid);
4208 target_ip->cuid = tswap32(host_ip->cuid);
4209 target_ip->cgid = tswap32(host_ip->cgid);
4210#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
4211 target_ip->mode = tswap32(host_ip->mode);
4212#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004213 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01004214#endif
4215#if defined(TARGET_PPC)
4216 target_ip->__seq = tswap32(host_ip->__seq);
4217#else
4218 target_ip->__seq = tswap16(host_ip->__seq);
4219#endif
ths3eb6b042007-06-03 14:26:27 +00004220 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004221 return 0;
ths3eb6b042007-06-03 14:26:27 +00004222}
4223
bellard579a97f2007-11-11 14:26:47 +00004224static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
4225 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004226{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004227 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004228
bellard579a97f2007-11-11 14:26:47 +00004229 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4230 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004231 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
4232 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004233 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
4234 host_sd->sem_otime = tswapal(target_sd->sem_otime);
4235 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004236 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004237 return 0;
ths3eb6b042007-06-03 14:26:27 +00004238}
4239
bellard579a97f2007-11-11 14:26:47 +00004240static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
4241 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00004242{
Peter Maydell005eb2a2016-07-15 16:50:47 +01004243 struct target_semid64_ds *target_sd;
ths3eb6b042007-06-03 14:26:27 +00004244
bellard579a97f2007-11-11 14:26:47 +00004245 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4246 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00004247 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08004248 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004249 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
4250 target_sd->sem_otime = tswapal(host_sd->sem_otime);
4251 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00004252 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004253 return 0;
ths3eb6b042007-06-03 14:26:27 +00004254}
4255
aurel32e5289082009-04-18 16:16:12 +00004256struct target_seminfo {
4257 int semmap;
4258 int semmni;
4259 int semmns;
4260 int semmnu;
4261 int semmsl;
4262 int semopm;
4263 int semume;
4264 int semusz;
4265 int semvmx;
4266 int semaem;
4267};
4268
4269static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
4270 struct seminfo *host_seminfo)
4271{
4272 struct target_seminfo *target_seminfo;
4273 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
4274 return -TARGET_EFAULT;
4275 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
4276 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
4277 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
4278 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
4279 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
4280 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
4281 __put_user(host_seminfo->semume, &target_seminfo->semume);
4282 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
4283 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
4284 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
4285 unlock_user_struct(target_seminfo, target_addr, 1);
4286 return 0;
4287}
4288
thsfa294812007-02-02 22:05:00 +00004289union semun {
4290 int val;
ths3eb6b042007-06-03 14:26:27 +00004291 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00004292 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00004293 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00004294};
4295
ths3eb6b042007-06-03 14:26:27 +00004296union target_semun {
4297 int val;
aurel32e5289082009-04-18 16:16:12 +00004298 abi_ulong buf;
4299 abi_ulong array;
4300 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00004301};
4302
aurel32e5289082009-04-18 16:16:12 +00004303static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
4304 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00004305{
aurel32e5289082009-04-18 16:16:12 +00004306 int nsems;
4307 unsigned short *array;
4308 union semun semun;
4309 struct semid_ds semid_ds;
4310 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004311
aurel32e5289082009-04-18 16:16:12 +00004312 semun.buf = &semid_ds;
4313
4314 ret = semctl(semid, 0, IPC_STAT, semun);
4315 if (ret == -1)
4316 return get_errno(ret);
4317
4318 nsems = semid_ds.sem_nsems;
4319
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304320 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00004321 if (!*host_array) {
4322 return -TARGET_ENOMEM;
4323 }
aurel32e5289082009-04-18 16:16:12 +00004324 array = lock_user(VERIFY_READ, target_addr,
4325 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00004326 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304327 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004328 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00004329 }
aurel32e5289082009-04-18 16:16:12 +00004330
4331 for(i=0; i<nsems; i++) {
4332 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004333 }
aurel32e5289082009-04-18 16:16:12 +00004334 unlock_user(array, target_addr, 0);
4335
bellard579a97f2007-11-11 14:26:47 +00004336 return 0;
ths3eb6b042007-06-03 14:26:27 +00004337}
4338
aurel32e5289082009-04-18 16:16:12 +00004339static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
4340 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00004341{
aurel32e5289082009-04-18 16:16:12 +00004342 int nsems;
4343 unsigned short *array;
4344 union semun semun;
4345 struct semid_ds semid_ds;
4346 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00004347
aurel32e5289082009-04-18 16:16:12 +00004348 semun.buf = &semid_ds;
4349
4350 ret = semctl(semid, 0, IPC_STAT, semun);
4351 if (ret == -1)
4352 return get_errno(ret);
4353
4354 nsems = semid_ds.sem_nsems;
4355
4356 array = lock_user(VERIFY_WRITE, target_addr,
4357 nsems*sizeof(unsigned short), 0);
4358 if (!array)
4359 return -TARGET_EFAULT;
4360
4361 for(i=0; i<nsems; i++) {
4362 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00004363 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304364 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00004365 unlock_user(array, target_addr, 1);
4366
bellard579a97f2007-11-11 14:26:47 +00004367 return 0;
ths3eb6b042007-06-03 14:26:27 +00004368}
4369
aurel32e5289082009-04-18 16:16:12 +00004370static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01004371 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00004372{
Stefan Weild1c002b2015-02-08 15:40:58 +01004373 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00004374 union semun arg;
4375 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05304376 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00004377 struct seminfo seminfo;
4378 abi_long ret = -TARGET_EINVAL;
4379 abi_long err;
4380 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00004381
4382 switch( cmd ) {
4383 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00004384 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05004385 /* In 64 bit cross-endian situations, we will erroneously pick up
4386 * the wrong half of the union for the "val" element. To rectify
4387 * this, the entire 8-byte structure is byteswapped, followed by
4388 * a swap of the 4 byte val field. In other cases, the data is
4389 * already in proper host byte order. */
4390 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
4391 target_su.buf = tswapal(target_su.buf);
4392 arg.val = tswap32(target_su.val);
4393 } else {
4394 arg.val = target_su.val;
4395 }
aurel32e5289082009-04-18 16:16:12 +00004396 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00004397 break;
4398 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00004399 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00004400 err = target_to_host_semarray(semid, &array, target_su.array);
4401 if (err)
4402 return err;
4403 arg.array = array;
4404 ret = get_errno(semctl(semid, semnum, cmd, arg));
4405 err = host_to_target_semarray(semid, target_su.array, &array);
4406 if (err)
4407 return err;
ths3eb6b042007-06-03 14:26:27 +00004408 break;
4409 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00004410 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00004411 case SEM_STAT:
4412 err = target_to_host_semid_ds(&dsarg, target_su.buf);
4413 if (err)
4414 return err;
4415 arg.buf = &dsarg;
4416 ret = get_errno(semctl(semid, semnum, cmd, arg));
4417 err = host_to_target_semid_ds(target_su.buf, &dsarg);
4418 if (err)
4419 return err;
ths3eb6b042007-06-03 14:26:27 +00004420 break;
aurel32e5289082009-04-18 16:16:12 +00004421 case IPC_INFO:
4422 case SEM_INFO:
4423 arg.__buf = &seminfo;
4424 ret = get_errno(semctl(semid, semnum, cmd, arg));
4425 err = host_to_target_seminfo(target_su.__buf, &seminfo);
4426 if (err)
4427 return err;
4428 break;
4429 case IPC_RMID:
4430 case GETPID:
4431 case GETNCNT:
4432 case GETZCNT:
4433 ret = get_errno(semctl(semid, semnum, cmd, NULL));
4434 break;
ths3eb6b042007-06-03 14:26:27 +00004435 }
4436
4437 return ret;
4438}
4439
aurel32e5289082009-04-18 16:16:12 +00004440struct target_sembuf {
4441 unsigned short sem_num;
4442 short sem_op;
4443 short sem_flg;
4444};
4445
4446static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
4447 abi_ulong target_addr,
4448 unsigned nsops)
4449{
4450 struct target_sembuf *target_sembuf;
4451 int i;
4452
4453 target_sembuf = lock_user(VERIFY_READ, target_addr,
4454 nsops*sizeof(struct target_sembuf), 1);
4455 if (!target_sembuf)
4456 return -TARGET_EFAULT;
4457
4458 for(i=0; i<nsops; i++) {
4459 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
4460 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
4461 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
4462 }
4463
4464 unlock_user(target_sembuf, target_addr, 0);
4465
4466 return 0;
4467}
4468
4469static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
4470{
4471 struct sembuf sops[nsops];
4472
4473 if (target_to_host_sembuf(sops, ptr, nsops))
4474 return -TARGET_EFAULT;
4475
Peter Maydellffb7ee72016-06-06 19:58:12 +01004476 return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
aurel32e5289082009-04-18 16:16:12 +00004477}
4478
ths1bc012f2007-06-03 14:27:49 +00004479struct target_msqid_ds
4480{
aurel321c54ff92008-10-13 21:08:44 +00004481 struct target_ipc_perm msg_perm;
4482 abi_ulong msg_stime;
4483#if TARGET_ABI_BITS == 32
4484 abi_ulong __unused1;
4485#endif
4486 abi_ulong msg_rtime;
4487#if TARGET_ABI_BITS == 32
4488 abi_ulong __unused2;
4489#endif
4490 abi_ulong msg_ctime;
4491#if TARGET_ABI_BITS == 32
4492 abi_ulong __unused3;
4493#endif
4494 abi_ulong __msg_cbytes;
4495 abi_ulong msg_qnum;
4496 abi_ulong msg_qbytes;
4497 abi_ulong msg_lspid;
4498 abi_ulong msg_lrpid;
4499 abi_ulong __unused4;
4500 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00004501};
4502
bellard579a97f2007-11-11 14:26:47 +00004503static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
4504 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00004505{
4506 struct target_msqid_ds *target_md;
4507
bellard579a97f2007-11-11 14:26:47 +00004508 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
4509 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004510 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
4511 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004512 host_md->msg_stime = tswapal(target_md->msg_stime);
4513 host_md->msg_rtime = tswapal(target_md->msg_rtime);
4514 host_md->msg_ctime = tswapal(target_md->msg_ctime);
4515 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
4516 host_md->msg_qnum = tswapal(target_md->msg_qnum);
4517 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
4518 host_md->msg_lspid = tswapal(target_md->msg_lspid);
4519 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004520 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00004521 return 0;
ths1bc012f2007-06-03 14:27:49 +00004522}
4523
bellard579a97f2007-11-11 14:26:47 +00004524static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
4525 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00004526{
4527 struct target_msqid_ds *target_md;
4528
bellard579a97f2007-11-11 14:26:47 +00004529 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
4530 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004531 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
4532 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004533 target_md->msg_stime = tswapal(host_md->msg_stime);
4534 target_md->msg_rtime = tswapal(host_md->msg_rtime);
4535 target_md->msg_ctime = tswapal(host_md->msg_ctime);
4536 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
4537 target_md->msg_qnum = tswapal(host_md->msg_qnum);
4538 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
4539 target_md->msg_lspid = tswapal(host_md->msg_lspid);
4540 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00004541 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00004542 return 0;
ths1bc012f2007-06-03 14:27:49 +00004543}
4544
aurel321c54ff92008-10-13 21:08:44 +00004545struct target_msginfo {
4546 int msgpool;
4547 int msgmap;
4548 int msgmax;
4549 int msgmnb;
4550 int msgmni;
4551 int msgssz;
4552 int msgtql;
4553 unsigned short int msgseg;
4554};
4555
4556static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
4557 struct msginfo *host_msginfo)
4558{
4559 struct target_msginfo *target_msginfo;
4560 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
4561 return -TARGET_EFAULT;
4562 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
4563 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
4564 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
4565 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
4566 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
4567 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
4568 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
4569 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
4570 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00004571 return 0;
aurel321c54ff92008-10-13 21:08:44 +00004572}
4573
4574static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00004575{
4576 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00004577 struct msginfo msginfo;
4578 abi_long ret = -TARGET_EINVAL;
4579
4580 cmd &= 0xff;
4581
4582 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00004583 case IPC_STAT:
4584 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00004585 case MSG_STAT:
4586 if (target_to_host_msqid_ds(&dsarg,ptr))
4587 return -TARGET_EFAULT;
4588 ret = get_errno(msgctl(msgid, cmd, &dsarg));
4589 if (host_to_target_msqid_ds(ptr,&dsarg))
4590 return -TARGET_EFAULT;
4591 break;
4592 case IPC_RMID:
4593 ret = get_errno(msgctl(msgid, cmd, NULL));
4594 break;
4595 case IPC_INFO:
4596 case MSG_INFO:
4597 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
4598 if (host_to_target_msginfo(ptr, &msginfo))
4599 return -TARGET_EFAULT;
4600 break;
ths1bc012f2007-06-03 14:27:49 +00004601 }
aurel321c54ff92008-10-13 21:08:44 +00004602
ths1bc012f2007-06-03 14:27:49 +00004603 return ret;
4604}
4605
4606struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00004607 abi_long mtype;
4608 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00004609};
4610
blueswir1992f48a2007-10-14 16:27:31 +00004611static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05004612 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004613{
4614 struct target_msgbuf *target_mb;
4615 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004616 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004617
Tom Mustaedcc5f92014-08-12 13:53:37 -05004618 if (msgsz < 0) {
4619 return -TARGET_EINVAL;
4620 }
4621
bellard579a97f2007-11-11 14:26:47 +00004622 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
4623 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304624 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08004625 if (!host_mb) {
4626 unlock_user_struct(target_mb, msgp, 0);
4627 return -TARGET_ENOMEM;
4628 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004629 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00004630 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01004631 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304632 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004633 unlock_user_struct(target_mb, msgp, 0);
4634
4635 return ret;
4636}
4637
blueswir1992f48a2007-10-14 16:27:31 +00004638static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01004639 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00004640 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00004641{
4642 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00004643 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00004644 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00004645 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00004646
Peter Maydell99874f62016-05-20 19:00:56 +01004647 if (msgsz < 0) {
4648 return -TARGET_EINVAL;
4649 }
4650
bellard579a97f2007-11-11 14:26:47 +00004651 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
4652 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00004653
Peter Maydell415d8472016-05-20 19:00:57 +01004654 host_mb = g_try_malloc(msgsz + sizeof(long));
4655 if (!host_mb) {
4656 ret = -TARGET_ENOMEM;
4657 goto end;
4658 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01004659 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00004660
bellard579a97f2007-11-11 14:26:47 +00004661 if (ret > 0) {
4662 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
4663 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
4664 if (!target_mtext) {
4665 ret = -TARGET_EFAULT;
4666 goto end;
4667 }
aurel321c54ff92008-10-13 21:08:44 +00004668 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00004669 unlock_user(target_mtext, target_mtext_addr, ret);
4670 }
aurel321c54ff92008-10-13 21:08:44 +00004671
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004672 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00004673
bellard579a97f2007-11-11 14:26:47 +00004674end:
4675 if (target_mb)
4676 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02004677 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00004678 return ret;
4679}
4680
Riku Voipio88a8c982009-04-03 10:42:00 +03004681static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
4682 abi_ulong target_addr)
4683{
4684 struct target_shmid_ds *target_sd;
4685
4686 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
4687 return -TARGET_EFAULT;
4688 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
4689 return -TARGET_EFAULT;
4690 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4691 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
4692 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4693 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4694 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4695 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4696 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4697 unlock_user_struct(target_sd, target_addr, 0);
4698 return 0;
4699}
4700
4701static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
4702 struct shmid_ds *host_sd)
4703{
4704 struct target_shmid_ds *target_sd;
4705
4706 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
4707 return -TARGET_EFAULT;
4708 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
4709 return -TARGET_EFAULT;
4710 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
4711 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
4712 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
4713 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
4714 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
4715 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
4716 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
4717 unlock_user_struct(target_sd, target_addr, 1);
4718 return 0;
4719}
4720
4721struct target_shminfo {
4722 abi_ulong shmmax;
4723 abi_ulong shmmin;
4724 abi_ulong shmmni;
4725 abi_ulong shmseg;
4726 abi_ulong shmall;
4727};
4728
4729static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
4730 struct shminfo *host_shminfo)
4731{
4732 struct target_shminfo *target_shminfo;
4733 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
4734 return -TARGET_EFAULT;
4735 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
4736 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
4737 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
4738 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
4739 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
4740 unlock_user_struct(target_shminfo, target_addr, 1);
4741 return 0;
4742}
4743
4744struct target_shm_info {
4745 int used_ids;
4746 abi_ulong shm_tot;
4747 abi_ulong shm_rss;
4748 abi_ulong shm_swp;
4749 abi_ulong swap_attempts;
4750 abi_ulong swap_successes;
4751};
4752
4753static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
4754 struct shm_info *host_shm_info)
4755{
4756 struct target_shm_info *target_shm_info;
4757 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
4758 return -TARGET_EFAULT;
4759 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
4760 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
4761 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
4762 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
4763 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
4764 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
4765 unlock_user_struct(target_shm_info, target_addr, 1);
4766 return 0;
4767}
4768
4769static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
4770{
4771 struct shmid_ds dsarg;
4772 struct shminfo shminfo;
4773 struct shm_info shm_info;
4774 abi_long ret = -TARGET_EINVAL;
4775
4776 cmd &= 0xff;
4777
4778 switch(cmd) {
4779 case IPC_STAT:
4780 case IPC_SET:
4781 case SHM_STAT:
4782 if (target_to_host_shmid_ds(&dsarg, buf))
4783 return -TARGET_EFAULT;
4784 ret = get_errno(shmctl(shmid, cmd, &dsarg));
4785 if (host_to_target_shmid_ds(buf, &dsarg))
4786 return -TARGET_EFAULT;
4787 break;
4788 case IPC_INFO:
4789 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4790 if (host_to_target_shminfo(buf, &shminfo))
4791 return -TARGET_EFAULT;
4792 break;
4793 case SHM_INFO:
4794 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4795 if (host_to_target_shm_info(buf, &shm_info))
4796 return -TARGET_EFAULT;
4797 break;
4798 case IPC_RMID:
4799 case SHM_LOCK:
4800 case SHM_UNLOCK:
4801 ret = get_errno(shmctl(shmid, cmd, NULL));
4802 break;
4803 }
4804
4805 return ret;
4806}
4807
Peter Maydellee8e7612016-07-11 16:48:11 +01004808#ifndef TARGET_FORCE_SHMLBA
4809/* For most architectures, SHMLBA is the same as the page size;
4810 * some architectures have larger values, in which case they should
4811 * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
4812 * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
4813 * and defining its own value for SHMLBA.
4814 *
4815 * The kernel also permits SHMLBA to be set by the architecture to a
4816 * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
4817 * this means that addresses are rounded to the large size if
4818 * SHM_RND is set but addresses not aligned to that size are not rejected
4819 * as long as they are at least page-aligned. Since the only architecture
4820 * which uses this is ia64 this code doesn't provide for that oddity.
4821 */
4822static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
4823{
4824 return TARGET_PAGE_SIZE;
4825}
4826#endif
4827
4828static inline abi_ulong do_shmat(CPUArchState *cpu_env,
4829 int shmid, abi_ulong shmaddr, int shmflg)
Riku Voipio88a8c982009-04-03 10:42:00 +03004830{
4831 abi_long raddr;
4832 void *host_raddr;
4833 struct shmid_ds shm_info;
4834 int i,ret;
Peter Maydellee8e7612016-07-11 16:48:11 +01004835 abi_ulong shmlba;
Riku Voipio88a8c982009-04-03 10:42:00 +03004836
4837 /* find out the length of the shared memory segment */
4838 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4839 if (is_error(ret)) {
4840 /* can't get length, bail out */
4841 return ret;
4842 }
4843
Peter Maydellee8e7612016-07-11 16:48:11 +01004844 shmlba = target_shmlba(cpu_env);
4845
4846 if (shmaddr & (shmlba - 1)) {
4847 if (shmflg & SHM_RND) {
4848 shmaddr &= ~(shmlba - 1);
4849 } else {
4850 return -TARGET_EINVAL;
4851 }
4852 }
4853
Riku Voipio88a8c982009-04-03 10:42:00 +03004854 mmap_lock();
4855
4856 if (shmaddr)
4857 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4858 else {
4859 abi_ulong mmap_start;
4860
4861 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4862
4863 if (mmap_start == -1) {
4864 errno = ENOMEM;
4865 host_raddr = (void *)-1;
4866 } else
4867 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4868 }
4869
4870 if (host_raddr == (void *)-1) {
4871 mmap_unlock();
4872 return get_errno((long)host_raddr);
4873 }
4874 raddr=h2g((unsigned long)host_raddr);
4875
4876 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4877 PAGE_VALID | PAGE_READ |
4878 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4879
4880 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004881 if (!shm_regions[i].in_use) {
4882 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004883 shm_regions[i].start = raddr;
4884 shm_regions[i].size = shm_info.shm_segsz;
4885 break;
4886 }
4887 }
4888
4889 mmap_unlock();
4890 return raddr;
4891
4892}
4893
4894static inline abi_long do_shmdt(abi_ulong shmaddr)
4895{
4896 int i;
4897
4898 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004899 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4900 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004901 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004902 break;
4903 }
4904 }
4905
4906 return get_errno(shmdt(g2h(shmaddr)));
4907}
4908
aurel321c54ff92008-10-13 21:08:44 +00004909#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004910/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004911/* do_ipc() must return target values and target errnos. */
Peter Maydellee8e7612016-07-11 16:48:11 +01004912static abi_long do_ipc(CPUArchState *cpu_env,
4913 unsigned int call, abi_long first,
Tom Musta37ed0952014-08-12 13:53:35 -05004914 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004915 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004916{
4917 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004918 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004919
4920 version = call >> 16;
4921 call &= 0xffff;
4922
4923 switch (call) {
thsfa294812007-02-02 22:05:00 +00004924 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004925 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004926 break;
4927
4928 case IPCOP_semget:
4929 ret = get_errno(semget(first, second, third));
4930 break;
4931
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004932 case IPCOP_semctl: {
4933 /* The semun argument to semctl is passed by value, so dereference the
4934 * ptr argument. */
4935 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004936 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004937 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004938 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004939 }
thsd96372e2007-02-02 22:05:44 +00004940
aurel321c54ff92008-10-13 21:08:44 +00004941 case IPCOP_msgget:
4942 ret = get_errno(msgget(first, second));
4943 break;
thsd96372e2007-02-02 22:05:44 +00004944
aurel321c54ff92008-10-13 21:08:44 +00004945 case IPCOP_msgsnd:
4946 ret = do_msgsnd(first, ptr, second, third);
4947 break;
thsd96372e2007-02-02 22:05:44 +00004948
aurel321c54ff92008-10-13 21:08:44 +00004949 case IPCOP_msgctl:
4950 ret = do_msgctl(first, second, ptr);
4951 break;
thsd96372e2007-02-02 22:05:44 +00004952
aurel321c54ff92008-10-13 21:08:44 +00004953 case IPCOP_msgrcv:
4954 switch (version) {
4955 case 0:
4956 {
4957 struct target_ipc_kludge {
4958 abi_long msgp;
4959 abi_long msgtyp;
4960 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004961
aurel321c54ff92008-10-13 21:08:44 +00004962 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4963 ret = -TARGET_EFAULT;
4964 break;
ths1bc012f2007-06-03 14:27:49 +00004965 }
aurel321c54ff92008-10-13 21:08:44 +00004966
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004967 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004968
4969 unlock_user_struct(tmp, ptr, 0);
4970 break;
4971 }
4972 default:
4973 ret = do_msgrcv(first, ptr, second, fifth, third);
4974 }
4975 break;
thsd96372e2007-02-02 22:05:44 +00004976
bellard8853f862004-02-22 14:57:26 +00004977 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004978 switch (version) {
4979 default:
bellard5a4a8982007-11-11 17:39:18 +00004980 {
4981 abi_ulong raddr;
Peter Maydellee8e7612016-07-11 16:48:11 +01004982 raddr = do_shmat(cpu_env, first, ptr, second);
Riku Voipio88a8c982009-04-03 10:42:00 +03004983 if (is_error(raddr))
4984 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004985 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004986 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004987 break;
4988 }
4989 case 1:
4990 ret = -TARGET_EINVAL;
4991 break;
bellard5a4a8982007-11-11 17:39:18 +00004992 }
bellard8853f862004-02-22 14:57:26 +00004993 break;
4994 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004995 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004996 break;
4997
4998 case IPCOP_shmget:
4999 /* IPC_* flag values are the same on all linux platforms */
5000 ret = get_errno(shmget(first, second, third));
5001 break;
5002
5003 /* IPC_* and SHM_* command values are the same on all linux platforms */
5004 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01005005 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00005006 break;
5007 default:
j_mayer32407102007-09-26 23:01:49 +00005008 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00005009 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00005010 break;
5011 }
5012 return ret;
5013}
j_mayer32407102007-09-26 23:01:49 +00005014#endif
bellard8853f862004-02-22 14:57:26 +00005015
bellard31e31b82003-02-18 22:55:36 +00005016/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00005017
Blue Swirl001faf32009-05-13 17:53:17 +00005018#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00005019#define STRUCT_SPECIAL(name) STRUCT_ ## name,
5020enum {
5021#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02005022STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00005023};
5024#undef STRUCT
5025#undef STRUCT_SPECIAL
5026
Blue Swirl001faf32009-05-13 17:53:17 +00005027#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00005028#define STRUCT_SPECIAL(name)
5029#include "syscall_types.h"
5030#undef STRUCT
5031#undef STRUCT_SPECIAL
5032
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005033typedef struct IOCTLEntry IOCTLEntry;
5034
5035typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005036 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005037
5038struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08005039 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00005040 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00005041 const char *name;
5042 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005043 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00005044 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005045};
bellard31e31b82003-02-18 22:55:36 +00005046
5047#define IOC_R 0x0001
5048#define IOC_W 0x0002
5049#define IOC_RW (IOC_R | IOC_W)
5050
5051#define MAX_STRUCT_SIZE 4096
5052
Peter Maydelldace20d2011-01-10 13:11:24 +00005053#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00005054/* So fiemap access checks don't overflow on 32 bit systems.
5055 * This is very slightly smaller than the limit imposed by
5056 * the underlying kernel.
5057 */
5058#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
5059 / sizeof(struct fiemap_extent))
5060
5061static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005062 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00005063{
5064 /* The parameter for this ioctl is a struct fiemap followed
5065 * by an array of struct fiemap_extent whose size is set
5066 * in fiemap->fm_extent_count. The array is filled in by the
5067 * ioctl.
5068 */
5069 int target_size_in, target_size_out;
5070 struct fiemap *fm;
5071 const argtype *arg_type = ie->arg_type;
5072 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
5073 void *argptr, *p;
5074 abi_long ret;
5075 int i, extent_size = thunk_type_size(extent_arg_type, 0);
5076 uint32_t outbufsz;
5077 int free_fm = 0;
5078
5079 assert(arg_type[0] == TYPE_PTR);
5080 assert(ie->access == IOC_RW);
5081 arg_type++;
5082 target_size_in = thunk_type_size(arg_type, 0);
5083 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
5084 if (!argptr) {
5085 return -TARGET_EFAULT;
5086 }
5087 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5088 unlock_user(argptr, arg, 0);
5089 fm = (struct fiemap *)buf_temp;
5090 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
5091 return -TARGET_EINVAL;
5092 }
5093
5094 outbufsz = sizeof (*fm) +
5095 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
5096
5097 if (outbufsz > MAX_STRUCT_SIZE) {
5098 /* We can't fit all the extents into the fixed size buffer.
5099 * Allocate one that is large enough and use it instead.
5100 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305101 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00005102 if (!fm) {
5103 return -TARGET_ENOMEM;
5104 }
5105 memcpy(fm, buf_temp, sizeof(struct fiemap));
5106 free_fm = 1;
5107 }
Peter Maydell49ca6f32016-06-06 19:58:14 +01005108 ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
Peter Maydell285da2b2011-01-06 15:04:18 +00005109 if (!is_error(ret)) {
5110 target_size_out = target_size_in;
5111 /* An extent_count of 0 means we were only counting the extents
5112 * so there are no structs to copy
5113 */
5114 if (fm->fm_extent_count != 0) {
5115 target_size_out += fm->fm_mapped_extents * extent_size;
5116 }
5117 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
5118 if (!argptr) {
5119 ret = -TARGET_EFAULT;
5120 } else {
5121 /* Convert the struct fiemap */
5122 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
5123 if (fm->fm_extent_count != 0) {
5124 p = argptr + target_size_in;
5125 /* ...and then all the struct fiemap_extents */
5126 for (i = 0; i < fm->fm_mapped_extents; i++) {
5127 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
5128 THUNK_TARGET);
5129 p += extent_size;
5130 }
5131 }
5132 unlock_user(argptr, arg, target_size_out);
5133 }
5134 }
5135 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05305136 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00005137 }
5138 return ret;
5139}
Peter Maydelldace20d2011-01-10 13:11:24 +00005140#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00005141
Laurent Vivier059c2f22011-03-30 00:12:12 +02005142static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005143 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02005144{
5145 const argtype *arg_type = ie->arg_type;
5146 int target_size;
5147 void *argptr;
5148 int ret;
5149 struct ifconf *host_ifconf;
5150 uint32_t outbufsz;
5151 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
5152 int target_ifreq_size;
5153 int nb_ifreq;
5154 int free_buf = 0;
5155 int i;
5156 int target_ifc_len;
5157 abi_long target_ifc_buf;
5158 int host_ifc_len;
5159 char *host_ifc_buf;
5160
5161 assert(arg_type[0] == TYPE_PTR);
5162 assert(ie->access == IOC_RW);
5163
5164 arg_type++;
5165 target_size = thunk_type_size(arg_type, 0);
5166
5167 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5168 if (!argptr)
5169 return -TARGET_EFAULT;
5170 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5171 unlock_user(argptr, arg, 0);
5172
5173 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
5174 target_ifc_len = host_ifconf->ifc_len;
5175 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
5176
5177 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
5178 nb_ifreq = target_ifc_len / target_ifreq_size;
5179 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
5180
5181 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
5182 if (outbufsz > MAX_STRUCT_SIZE) {
5183 /* We can't fit all the extents into the fixed size buffer.
5184 * Allocate one that is large enough and use it instead.
5185 */
5186 host_ifconf = malloc(outbufsz);
5187 if (!host_ifconf) {
5188 return -TARGET_ENOMEM;
5189 }
5190 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
5191 free_buf = 1;
5192 }
5193 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
5194
5195 host_ifconf->ifc_len = host_ifc_len;
5196 host_ifconf->ifc_buf = host_ifc_buf;
5197
Peter Maydell49ca6f32016-06-06 19:58:14 +01005198 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
Laurent Vivier059c2f22011-03-30 00:12:12 +02005199 if (!is_error(ret)) {
5200 /* convert host ifc_len to target ifc_len */
5201
5202 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
5203 target_ifc_len = nb_ifreq * target_ifreq_size;
5204 host_ifconf->ifc_len = target_ifc_len;
5205
5206 /* restore target ifc_buf */
5207
5208 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
5209
5210 /* copy struct ifconf to target user */
5211
5212 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5213 if (!argptr)
5214 return -TARGET_EFAULT;
5215 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
5216 unlock_user(argptr, arg, target_size);
5217
5218 /* copy ifreq[] to target user */
5219
5220 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
5221 for (i = 0; i < nb_ifreq ; i++) {
5222 thunk_convert(argptr + i * target_ifreq_size,
5223 host_ifc_buf + i * sizeof(struct ifreq),
5224 ifreq_arg_type, THUNK_TARGET);
5225 }
5226 unlock_user(argptr, target_ifc_buf, target_ifc_len);
5227 }
5228
5229 if (free_buf) {
5230 free(host_ifconf);
5231 }
5232
5233 return ret;
5234}
5235
Alexander Graf56e904e2012-01-31 18:42:06 +01005236static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005237 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01005238{
5239 void *argptr;
5240 struct dm_ioctl *host_dm;
5241 abi_long guest_data;
5242 uint32_t guest_data_size;
5243 int target_size;
5244 const argtype *arg_type = ie->arg_type;
5245 abi_long ret;
5246 void *big_buf = NULL;
5247 char *host_data;
5248
5249 arg_type++;
5250 target_size = thunk_type_size(arg_type, 0);
5251 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5252 if (!argptr) {
5253 ret = -TARGET_EFAULT;
5254 goto out;
5255 }
5256 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5257 unlock_user(argptr, arg, 0);
5258
5259 /* buf_temp is too small, so fetch things into a bigger buffer */
5260 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
5261 memcpy(big_buf, buf_temp, target_size);
5262 buf_temp = big_buf;
5263 host_dm = big_buf;
5264
5265 guest_data = arg + host_dm->data_start;
5266 if ((guest_data - arg) < 0) {
Peter Maydellf9757b12016-07-12 13:02:14 +01005267 ret = -TARGET_EINVAL;
Alexander Graf56e904e2012-01-31 18:42:06 +01005268 goto out;
5269 }
5270 guest_data_size = host_dm->data_size - host_dm->data_start;
5271 host_data = (char*)host_dm + host_dm->data_start;
5272
5273 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
Peter Maydell32112152016-07-12 13:02:13 +01005274 if (!argptr) {
5275 ret = -TARGET_EFAULT;
5276 goto out;
5277 }
5278
Alexander Graf56e904e2012-01-31 18:42:06 +01005279 switch (ie->host_cmd) {
5280 case DM_REMOVE_ALL:
5281 case DM_LIST_DEVICES:
5282 case DM_DEV_CREATE:
5283 case DM_DEV_REMOVE:
5284 case DM_DEV_SUSPEND:
5285 case DM_DEV_STATUS:
5286 case DM_DEV_WAIT:
5287 case DM_TABLE_STATUS:
5288 case DM_TABLE_CLEAR:
5289 case DM_TABLE_DEPS:
5290 case DM_LIST_VERSIONS:
5291 /* no input data */
5292 break;
5293 case DM_DEV_RENAME:
5294 case DM_DEV_SET_GEOMETRY:
5295 /* data contains only strings */
5296 memcpy(host_data, argptr, guest_data_size);
5297 break;
5298 case DM_TARGET_MSG:
5299 memcpy(host_data, argptr, guest_data_size);
5300 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
5301 break;
5302 case DM_TABLE_LOAD:
5303 {
5304 void *gspec = argptr;
5305 void *cur_data = host_data;
5306 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5307 int spec_size = thunk_type_size(arg_type, 0);
5308 int i;
5309
5310 for (i = 0; i < host_dm->target_count; i++) {
5311 struct dm_target_spec *spec = cur_data;
5312 uint32_t next;
5313 int slen;
5314
5315 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
5316 slen = strlen((char*)gspec + spec_size) + 1;
5317 next = spec->next;
5318 spec->next = sizeof(*spec) + slen;
5319 strcpy((char*)&spec[1], gspec + spec_size);
5320 gspec += next;
5321 cur_data += spec->next;
5322 }
5323 break;
5324 }
5325 default:
5326 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08005327 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005328 goto out;
5329 }
5330 unlock_user(argptr, guest_data, 0);
5331
Peter Maydell49ca6f32016-06-06 19:58:14 +01005332 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Alexander Graf56e904e2012-01-31 18:42:06 +01005333 if (!is_error(ret)) {
5334 guest_data = arg + host_dm->data_start;
5335 guest_data_size = host_dm->data_size - host_dm->data_start;
5336 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
5337 switch (ie->host_cmd) {
5338 case DM_REMOVE_ALL:
5339 case DM_DEV_CREATE:
5340 case DM_DEV_REMOVE:
5341 case DM_DEV_RENAME:
5342 case DM_DEV_SUSPEND:
5343 case DM_DEV_STATUS:
5344 case DM_TABLE_LOAD:
5345 case DM_TABLE_CLEAR:
5346 case DM_TARGET_MSG:
5347 case DM_DEV_SET_GEOMETRY:
5348 /* no return data */
5349 break;
5350 case DM_LIST_DEVICES:
5351 {
5352 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
5353 uint32_t remaining_data = guest_data_size;
5354 void *cur_data = argptr;
5355 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
5356 int nl_size = 12; /* can't use thunk_size due to alignment */
5357
5358 while (1) {
5359 uint32_t next = nl->next;
5360 if (next) {
5361 nl->next = nl_size + (strlen(nl->name) + 1);
5362 }
5363 if (remaining_data < nl->next) {
5364 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5365 break;
5366 }
5367 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
5368 strcpy(cur_data + nl_size, nl->name);
5369 cur_data += nl->next;
5370 remaining_data -= nl->next;
5371 if (!next) {
5372 break;
5373 }
5374 nl = (void*)nl + next;
5375 }
5376 break;
5377 }
5378 case DM_DEV_WAIT:
5379 case DM_TABLE_STATUS:
5380 {
5381 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
5382 void *cur_data = argptr;
5383 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
5384 int spec_size = thunk_type_size(arg_type, 0);
5385 int i;
5386
5387 for (i = 0; i < host_dm->target_count; i++) {
5388 uint32_t next = spec->next;
5389 int slen = strlen((char*)&spec[1]) + 1;
5390 spec->next = (cur_data - argptr) + spec_size + slen;
5391 if (guest_data_size < spec->next) {
5392 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5393 break;
5394 }
5395 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
5396 strcpy(cur_data + spec_size, (char*)&spec[1]);
5397 cur_data = argptr + spec->next;
5398 spec = (void*)host_dm + host_dm->data_start + next;
5399 }
5400 break;
5401 }
5402 case DM_TABLE_DEPS:
5403 {
5404 void *hdata = (void*)host_dm + host_dm->data_start;
5405 int count = *(uint32_t*)hdata;
5406 uint64_t *hdev = hdata + 8;
5407 uint64_t *gdev = argptr + 8;
5408 int i;
5409
5410 *(uint32_t*)argptr = tswap32(count);
5411 for (i = 0; i < count; i++) {
5412 *gdev = tswap64(*hdev);
5413 gdev++;
5414 hdev++;
5415 }
5416 break;
5417 }
5418 case DM_LIST_VERSIONS:
5419 {
5420 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
5421 uint32_t remaining_data = guest_data_size;
5422 void *cur_data = argptr;
5423 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
5424 int vers_size = thunk_type_size(arg_type, 0);
5425
5426 while (1) {
5427 uint32_t next = vers->next;
5428 if (next) {
5429 vers->next = vers_size + (strlen(vers->name) + 1);
5430 }
5431 if (remaining_data < vers->next) {
5432 host_dm->flags |= DM_BUFFER_FULL_FLAG;
5433 break;
5434 }
5435 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
5436 strcpy(cur_data + vers_size, vers->name);
5437 cur_data += vers->next;
5438 remaining_data -= vers->next;
5439 if (!next) {
5440 break;
5441 }
5442 vers = (void*)vers + next;
5443 }
5444 break;
5445 }
5446 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08005447 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01005448 ret = -TARGET_EINVAL;
5449 goto out;
5450 }
5451 unlock_user(argptr, guest_data, guest_data_size);
5452
5453 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5454 if (!argptr) {
5455 ret = -TARGET_EFAULT;
5456 goto out;
5457 }
5458 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5459 unlock_user(argptr, arg, target_size);
5460 }
5461out:
Stefan Weilad11ad72012-09-04 22:14:19 +02005462 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01005463 return ret;
5464}
5465
Alexander Grafa59b5e32014-08-22 13:15:50 +02005466static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005467 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02005468{
5469 void *argptr;
5470 int target_size;
5471 const argtype *arg_type = ie->arg_type;
5472 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
5473 abi_long ret;
5474
5475 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
5476 struct blkpg_partition host_part;
5477
5478 /* Read and convert blkpg */
5479 arg_type++;
5480 target_size = thunk_type_size(arg_type, 0);
5481 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5482 if (!argptr) {
5483 ret = -TARGET_EFAULT;
5484 goto out;
5485 }
5486 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5487 unlock_user(argptr, arg, 0);
5488
5489 switch (host_blkpg->op) {
5490 case BLKPG_ADD_PARTITION:
5491 case BLKPG_DEL_PARTITION:
5492 /* payload is struct blkpg_partition */
5493 break;
5494 default:
5495 /* Unknown opcode */
5496 ret = -TARGET_EINVAL;
5497 goto out;
5498 }
5499
5500 /* Read and convert blkpg->data */
5501 arg = (abi_long)(uintptr_t)host_blkpg->data;
5502 target_size = thunk_type_size(part_arg_type, 0);
5503 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5504 if (!argptr) {
5505 ret = -TARGET_EFAULT;
5506 goto out;
5507 }
5508 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
5509 unlock_user(argptr, arg, 0);
5510
5511 /* Swizzle the data pointer to our local copy and call! */
5512 host_blkpg->data = &host_part;
Peter Maydell49ca6f32016-06-06 19:58:14 +01005513 ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
Alexander Grafa59b5e32014-08-22 13:15:50 +02005514
5515out:
5516 return ret;
5517}
5518
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005519static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005520 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005521{
5522 const argtype *arg_type = ie->arg_type;
5523 const StructEntry *se;
5524 const argtype *field_types;
5525 const int *dst_offsets, *src_offsets;
5526 int target_size;
5527 void *argptr;
5528 abi_ulong *target_rt_dev_ptr;
5529 unsigned long *host_rt_dev_ptr;
5530 abi_long ret;
5531 int i;
5532
5533 assert(ie->access == IOC_W);
5534 assert(*arg_type == TYPE_PTR);
5535 arg_type++;
5536 assert(*arg_type == TYPE_STRUCT);
5537 target_size = thunk_type_size(arg_type, 0);
5538 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5539 if (!argptr) {
5540 return -TARGET_EFAULT;
5541 }
5542 arg_type++;
5543 assert(*arg_type == (int)STRUCT_rtentry);
5544 se = struct_entries + *arg_type++;
5545 assert(se->convert[0] == NULL);
5546 /* convert struct here to be able to catch rt_dev string */
5547 field_types = se->field_types;
5548 dst_offsets = se->field_offsets[THUNK_HOST];
5549 src_offsets = se->field_offsets[THUNK_TARGET];
5550 for (i = 0; i < se->nb_fields; i++) {
5551 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
5552 assert(*field_types == TYPE_PTRVOID);
5553 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
5554 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
5555 if (*target_rt_dev_ptr != 0) {
5556 *host_rt_dev_ptr = (unsigned long)lock_user_string(
5557 tswapal(*target_rt_dev_ptr));
5558 if (!*host_rt_dev_ptr) {
5559 unlock_user(argptr, arg, 0);
5560 return -TARGET_EFAULT;
5561 }
5562 } else {
5563 *host_rt_dev_ptr = 0;
5564 }
5565 field_types++;
5566 continue;
5567 }
5568 field_types = thunk_convert(buf_temp + dst_offsets[i],
5569 argptr + src_offsets[i],
5570 field_types, THUNK_HOST);
5571 }
5572 unlock_user(argptr, arg, 0);
5573
Peter Maydell49ca6f32016-06-06 19:58:14 +01005574 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
Laurent Vivier7ff7b662013-07-02 14:04:12 +01005575 if (*host_rt_dev_ptr != 0) {
5576 unlock_user((void *)*host_rt_dev_ptr,
5577 *target_rt_dev_ptr, 0);
5578 }
5579 return ret;
5580}
5581
Paul Burtonca56f5b2014-06-22 11:25:47 +01005582static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02005583 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01005584{
5585 int sig = target_to_host_signal(arg);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005586 return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
Paul Burtonca56f5b2014-06-22 11:25:47 +01005587}
5588
blueswir19f106a72008-10-05 10:52:52 +00005589static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00005590#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005591 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
5592#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
5593 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
Helge Deller8cb762f2016-12-06 16:24:03 +01005594#define IOCTL_IGNORE(cmd) \
5595 { TARGET_ ## cmd, 0, #cmd },
bellard31e31b82003-02-18 22:55:36 +00005596#include "ioctls.h"
5597 { 0, 0, },
5598};
5599
pbrook53a59602006-03-25 19:31:22 +00005600/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00005601/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02005602static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00005603{
5604 const IOCTLEntry *ie;
5605 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00005606 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005607 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00005608 int target_size;
5609 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00005610
5611 ie = ioctl_entries;
5612 for(;;) {
5613 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00005614 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00005615 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005616 }
5617 if (ie->target_cmd == cmd)
5618 break;
5619 ie++;
5620 }
5621 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00005622#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00005623 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00005624#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005625 if (ie->do_ioctl) {
5626 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
Helge Deller8cb762f2016-12-06 16:24:03 +01005627 } else if (!ie->host_cmd) {
5628 /* Some architectures define BSD ioctls in their headers
5629 that are not implemented in Linux. */
5630 return -TARGET_ENOSYS;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00005631 }
5632
bellard31e31b82003-02-18 22:55:36 +00005633 switch(arg_type[0]) {
5634 case TYPE_NULL:
5635 /* no argument */
Peter Maydell49ca6f32016-06-06 19:58:14 +01005636 ret = get_errno(safe_ioctl(fd, ie->host_cmd));
bellard31e31b82003-02-18 22:55:36 +00005637 break;
5638 case TYPE_PTRVOID:
5639 case TYPE_INT:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005640 ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
bellard31e31b82003-02-18 22:55:36 +00005641 break;
5642 case TYPE_PTR:
5643 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00005644 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00005645 switch(ie->access) {
5646 case IOC_R:
Peter Maydell49ca6f32016-06-06 19:58:14 +01005647 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005648 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005649 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5650 if (!argptr)
5651 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005652 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5653 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005654 }
5655 break;
5656 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00005657 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5658 if (!argptr)
5659 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005660 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5661 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005662 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005663 break;
5664 default:
5665 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00005666 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
5667 if (!argptr)
5668 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005669 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
5670 unlock_user(argptr, arg, 0);
Peter Maydell49ca6f32016-06-06 19:58:14 +01005671 ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
bellard31e31b82003-02-18 22:55:36 +00005672 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00005673 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
5674 if (!argptr)
5675 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005676 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
5677 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00005678 }
5679 break;
5680 }
5681 break;
5682 default:
j_mayer32407102007-09-26 23:01:49 +00005683 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
5684 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00005685 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00005686 break;
5687 }
5688 return ret;
5689}
5690
blueswir1b39bc502008-10-05 10:51:10 +00005691static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005692 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
5693 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
5694 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
5695 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
5696 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
5697 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
5698 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
5699 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
5700 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
5701 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
5702 { TARGET_IXON, TARGET_IXON, IXON, IXON },
5703 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
5704 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
5705 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
5706 { 0, 0, 0, 0 }
5707};
5708
blueswir1b39bc502008-10-05 10:51:10 +00005709static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005710 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
5711 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
5712 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
5713 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
5714 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
5715 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
5716 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
5717 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
5718 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
5719 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
5720 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
5721 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
5722 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
5723 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
5724 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
5725 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
5726 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
5727 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
5728 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
5729 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
5730 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
5731 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
5732 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
5733 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
5734 { 0, 0, 0, 0 }
5735};
5736
blueswir1b39bc502008-10-05 10:51:10 +00005737static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005738 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
5739 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
5740 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
5741 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
5742 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
5743 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
5744 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
5745 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
5746 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
5747 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
5748 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
5749 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
5750 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
5751 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
5752 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
5753 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
5754 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
5755 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
5756 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
5757 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
5758 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
5759 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
5760 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
5761 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
5762 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
5763 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
5764 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
5765 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
5766 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
5767 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
5768 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
5769 { 0, 0, 0, 0 }
5770};
5771
blueswir1b39bc502008-10-05 10:51:10 +00005772static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00005773 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
5774 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
5775 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
5776 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
5777 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
5778 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
5779 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
5780 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
5781 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
5782 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
5783 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
5784 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
5785 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
5786 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
5787 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
5788 { 0, 0, 0, 0 }
5789};
5790
5791static void target_to_host_termios (void *dst, const void *src)
5792{
5793 struct host_termios *host = dst;
5794 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00005795
ths5fafdf22007-09-16 21:08:06 +00005796 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005797 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005798 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005799 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005800 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005801 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00005802 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005803 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
5804 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00005805
Arnaud Patard44607122009-04-21 17:39:08 +03005806 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00005807 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
5808 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00005809 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00005810 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00005811 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00005812 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00005813 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00005814 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00005815 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00005816 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
5817 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00005818 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
5819 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
5820 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
5821 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
5822 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00005823 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00005824}
ths3b46e622007-09-17 08:09:54 +00005825
bellard31e31b82003-02-18 22:55:36 +00005826static void host_to_target_termios (void *dst, const void *src)
5827{
5828 struct target_termios *target = dst;
5829 const struct host_termios *host = src;
5830
ths5fafdf22007-09-16 21:08:06 +00005831 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00005832 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005833 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005834 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005835 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005836 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005837 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005838 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5839 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005840
Arnaud Patard44607122009-04-21 17:39:08 +03005841 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005842 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5843 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5844 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5845 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5846 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5847 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5848 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5849 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5850 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5851 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5852 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5853 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5854 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5855 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5856 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5857 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5858 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5859}
5860
blueswir18e853dc2008-10-05 10:49:32 +00005861static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005862 .convert = { host_to_target_termios, target_to_host_termios },
5863 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5864 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5865};
5866
bellard5286db72003-06-05 00:57:30 +00005867static bitmask_transtbl mmap_flags_tbl[] = {
5868 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5869 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5870 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5871 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5872 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5873 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5874 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5875 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005876 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5877 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005878 { 0, 0, 0, 0 }
5879};
5880
bellard2ab83ea2003-06-15 19:56:46 +00005881#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005882
5883/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005884static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005885
bellard03acab62007-11-11 14:57:14 +00005886static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005887{
5888 int size;
pbrook53a59602006-03-25 19:31:22 +00005889 void *p;
bellard6dbad632003-03-16 18:05:05 +00005890
5891 if (!ldt_table)
5892 return 0;
5893 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5894 if (size > bytecount)
5895 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005896 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5897 if (!p)
bellard03acab62007-11-11 14:57:14 +00005898 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005899 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005900 memcpy(p, ldt_table, size);
5901 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005902 return size;
5903}
5904
5905/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005906static abi_long write_ldt(CPUX86State *env,
5907 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005908{
5909 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005910 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005911 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005912 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005913 uint32_t *lp, entry_1, entry_2;
5914
5915 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005916 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005917 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005918 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005919 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005920 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005921 ldt_info.limit = tswap32(target_ldt_info->limit);
5922 ldt_info.flags = tswap32(target_ldt_info->flags);
5923 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005924
bellard6dbad632003-03-16 18:05:05 +00005925 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005926 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005927 seg_32bit = ldt_info.flags & 1;
5928 contents = (ldt_info.flags >> 1) & 3;
5929 read_exec_only = (ldt_info.flags >> 3) & 1;
5930 limit_in_pages = (ldt_info.flags >> 4) & 1;
5931 seg_not_present = (ldt_info.flags >> 5) & 1;
5932 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005933#ifdef TARGET_ABI32
5934 lm = 0;
5935#else
5936 lm = (ldt_info.flags >> 7) & 1;
5937#endif
bellard6dbad632003-03-16 18:05:05 +00005938 if (contents == 3) {
5939 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005940 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005941 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005942 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005943 }
5944 /* allocate the LDT */
5945 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005946 env->ldt.base = target_mmap(0,
5947 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5948 PROT_READ|PROT_WRITE,
5949 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5950 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005951 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005952 memset(g2h(env->ldt.base), 0,
5953 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005954 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005955 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005956 }
5957
5958 /* NOTE: same code as Linux kernel */
5959 /* Allow LDTs to be cleared by the user. */
5960 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5961 if (oldmode ||
5962 (contents == 0 &&
5963 read_exec_only == 1 &&
5964 seg_32bit == 0 &&
5965 limit_in_pages == 0 &&
5966 seg_not_present == 1 &&
5967 useable == 0 )) {
5968 entry_1 = 0;
5969 entry_2 = 0;
5970 goto install;
5971 }
5972 }
ths3b46e622007-09-17 08:09:54 +00005973
bellard6dbad632003-03-16 18:05:05 +00005974 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5975 (ldt_info.limit & 0x0ffff);
5976 entry_2 = (ldt_info.base_addr & 0xff000000) |
5977 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5978 (ldt_info.limit & 0xf0000) |
5979 ((read_exec_only ^ 1) << 9) |
5980 (contents << 10) |
5981 ((seg_not_present ^ 1) << 15) |
5982 (seg_32bit << 22) |
5983 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005984 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005985 0x7000;
5986 if (!oldmode)
5987 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005988
bellard6dbad632003-03-16 18:05:05 +00005989 /* Install the new entry ... */
5990install:
5991 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5992 lp[0] = tswap32(entry_1);
5993 lp[1] = tswap32(entry_2);
5994 return 0;
5995}
5996
5997/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005998static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5999 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00006000{
bellard03acab62007-11-11 14:57:14 +00006001 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00006002
bellard6dbad632003-03-16 18:05:05 +00006003 switch (func) {
6004 case 0:
6005 ret = read_ldt(ptr, bytecount);
6006 break;
6007 case 1:
6008 ret = write_ldt(env, ptr, bytecount, 1);
6009 break;
6010 case 0x11:
6011 ret = write_ldt(env, ptr, bytecount, 0);
6012 break;
bellard03acab62007-11-11 14:57:14 +00006013 default:
6014 ret = -TARGET_ENOSYS;
6015 break;
bellard6dbad632003-03-16 18:05:05 +00006016 }
6017 return ret;
6018}
bellard1b6b0292003-03-22 17:31:38 +00006019
blueswir14583f582008-08-24 10:35:55 +00006020#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01006021abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006022{
6023 uint64_t *gdt_table = g2h(env->gdt.base);
6024 struct target_modify_ldt_ldt_s ldt_info;
6025 struct target_modify_ldt_ldt_s *target_ldt_info;
6026 int seg_32bit, contents, read_exec_only, limit_in_pages;
6027 int seg_not_present, useable, lm;
6028 uint32_t *lp, entry_1, entry_2;
6029 int i;
6030
6031 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6032 if (!target_ldt_info)
6033 return -TARGET_EFAULT;
6034 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006035 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00006036 ldt_info.limit = tswap32(target_ldt_info->limit);
6037 ldt_info.flags = tswap32(target_ldt_info->flags);
6038 if (ldt_info.entry_number == -1) {
6039 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
6040 if (gdt_table[i] == 0) {
6041 ldt_info.entry_number = i;
6042 target_ldt_info->entry_number = tswap32(i);
6043 break;
6044 }
6045 }
6046 }
6047 unlock_user_struct(target_ldt_info, ptr, 1);
6048
6049 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
6050 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
6051 return -TARGET_EINVAL;
6052 seg_32bit = ldt_info.flags & 1;
6053 contents = (ldt_info.flags >> 1) & 3;
6054 read_exec_only = (ldt_info.flags >> 3) & 1;
6055 limit_in_pages = (ldt_info.flags >> 4) & 1;
6056 seg_not_present = (ldt_info.flags >> 5) & 1;
6057 useable = (ldt_info.flags >> 6) & 1;
6058#ifdef TARGET_ABI32
6059 lm = 0;
6060#else
6061 lm = (ldt_info.flags >> 7) & 1;
6062#endif
6063
6064 if (contents == 3) {
6065 if (seg_not_present == 0)
6066 return -TARGET_EINVAL;
6067 }
6068
6069 /* NOTE: same code as Linux kernel */
6070 /* Allow LDTs to be cleared by the user. */
6071 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
6072 if ((contents == 0 &&
6073 read_exec_only == 1 &&
6074 seg_32bit == 0 &&
6075 limit_in_pages == 0 &&
6076 seg_not_present == 1 &&
6077 useable == 0 )) {
6078 entry_1 = 0;
6079 entry_2 = 0;
6080 goto install;
6081 }
6082 }
6083
6084 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
6085 (ldt_info.limit & 0x0ffff);
6086 entry_2 = (ldt_info.base_addr & 0xff000000) |
6087 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
6088 (ldt_info.limit & 0xf0000) |
6089 ((read_exec_only ^ 1) << 9) |
6090 (contents << 10) |
6091 ((seg_not_present ^ 1) << 15) |
6092 (seg_32bit << 22) |
6093 (limit_in_pages << 23) |
6094 (useable << 20) |
6095 (lm << 21) |
6096 0x7000;
6097
6098 /* Install the new entry ... */
6099install:
6100 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
6101 lp[0] = tswap32(entry_1);
6102 lp[1] = tswap32(entry_2);
6103 return 0;
6104}
6105
blueswir18fcd3692008-08-17 20:26:25 +00006106static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00006107{
6108 struct target_modify_ldt_ldt_s *target_ldt_info;
6109 uint64_t *gdt_table = g2h(env->gdt.base);
6110 uint32_t base_addr, limit, flags;
6111 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
6112 int seg_not_present, useable, lm;
6113 uint32_t *lp, entry_1, entry_2;
6114
6115 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
6116 if (!target_ldt_info)
6117 return -TARGET_EFAULT;
6118 idx = tswap32(target_ldt_info->entry_number);
6119 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
6120 idx > TARGET_GDT_ENTRY_TLS_MAX) {
6121 unlock_user_struct(target_ldt_info, ptr, 1);
6122 return -TARGET_EINVAL;
6123 }
6124 lp = (uint32_t *)(gdt_table + idx);
6125 entry_1 = tswap32(lp[0]);
6126 entry_2 = tswap32(lp[1]);
6127
6128 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
6129 contents = (entry_2 >> 10) & 3;
6130 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
6131 seg_32bit = (entry_2 >> 22) & 1;
6132 limit_in_pages = (entry_2 >> 23) & 1;
6133 useable = (entry_2 >> 20) & 1;
6134#ifdef TARGET_ABI32
6135 lm = 0;
6136#else
6137 lm = (entry_2 >> 21) & 1;
6138#endif
6139 flags = (seg_32bit << 0) | (contents << 1) |
6140 (read_exec_only << 3) | (limit_in_pages << 4) |
6141 (seg_not_present << 5) | (useable << 6) | (lm << 7);
6142 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
6143 base_addr = (entry_1 >> 16) |
6144 (entry_2 & 0xff000000) |
6145 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006146 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00006147 target_ldt_info->limit = tswap32(limit);
6148 target_ldt_info->flags = tswap32(flags);
6149 unlock_user_struct(target_ldt_info, ptr, 1);
6150 return 0;
6151}
blueswir14583f582008-08-24 10:35:55 +00006152#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00006153
bellardd2fd1af2007-11-14 18:08:56 +00006154#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01006155abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00006156{
Juan Quintela1add8692011-06-16 17:37:09 +01006157 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00006158 abi_ulong val;
6159 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01006160
bellardd2fd1af2007-11-14 18:08:56 +00006161 switch(code) {
6162 case TARGET_ARCH_SET_GS:
6163 case TARGET_ARCH_SET_FS:
6164 if (code == TARGET_ARCH_SET_GS)
6165 idx = R_GS;
6166 else
6167 idx = R_FS;
6168 cpu_x86_load_seg(env, idx, 0);
6169 env->segs[idx].base = addr;
6170 break;
6171 case TARGET_ARCH_GET_GS:
6172 case TARGET_ARCH_GET_FS:
6173 if (code == TARGET_ARCH_GET_GS)
6174 idx = R_GS;
6175 else
6176 idx = R_FS;
6177 val = env->segs[idx].base;
6178 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01006179 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00006180 break;
6181 default:
6182 ret = -TARGET_EINVAL;
6183 break;
6184 }
Juan Quintela1add8692011-06-16 17:37:09 +01006185 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00006186}
6187#endif
6188
bellard2ab83ea2003-06-15 19:56:46 +00006189#endif /* defined(TARGET_I386) */
6190
Riku Voipio05098a92011-03-04 15:27:29 +02006191#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00006192
pbrookd865bab2008-06-07 22:12:17 +00006193
6194static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
6195typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01006196 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00006197 pthread_mutex_t mutex;
6198 pthread_cond_t cond;
6199 pthread_t thread;
6200 uint32_t tid;
6201 abi_ulong child_tidptr;
6202 abi_ulong parent_tidptr;
6203 sigset_t sigmask;
6204} new_thread_info;
6205
6206static void *clone_func(void *arg)
6207{
6208 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006209 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01006210 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006211 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00006212
Emilio G. Cota70903762015-08-23 20:23:41 -04006213 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00006214 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01006215 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02006216 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02006217 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006218 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01006219 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006220 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00006221 if (info->child_tidptr)
6222 put_user_u32(info->tid, info->child_tidptr);
6223 if (info->parent_tidptr)
6224 put_user_u32(info->tid, info->parent_tidptr);
6225 /* Enable signals. */
6226 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
6227 /* Signal to the parent that we're ready. */
6228 pthread_mutex_lock(&info->mutex);
6229 pthread_cond_broadcast(&info->cond);
6230 pthread_mutex_unlock(&info->mutex);
6231 /* Wait until the parent has finshed initializing the tls state. */
6232 pthread_mutex_lock(&clone_lock);
6233 pthread_mutex_unlock(&clone_lock);
6234 cpu_loop(env);
6235 /* never exits */
6236 return NULL;
6237}
bellard1b6b0292003-03-22 17:31:38 +00006238
ths0da46a62007-10-20 20:23:07 +00006239/* do_fork() Must return host values and target errnos (unlike most
6240 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01006241static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00006242 abi_ulong parent_tidptr, target_ulong newtls,
6243 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00006244{
Andreas Färber0429a972013-08-26 18:14:44 +02006245 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00006246 int ret;
bellard5cd43932003-03-29 16:54:36 +00006247 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02006248 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01006249 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00006250 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00006251
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006252 flags &= ~CLONE_IGNORED_FLAGS;
6253
balrog436d1242008-09-21 02:39:45 +00006254 /* Emulate vfork() with fork() */
6255 if (flags & CLONE_VFORK)
6256 flags &= ~(CLONE_VFORK | CLONE_VM);
6257
bellard1b6b0292003-03-22 17:31:38 +00006258 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02006259 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006260 new_thread_info info;
6261 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01006262
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006263 if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
6264 (flags & CLONE_INVALID_THREAD_FLAGS)) {
6265 return -TARGET_EINVAL;
6266 }
6267
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02006268 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00006269 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00006270 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00006271 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00006272 /* Init regs that differ from the parent. */
6273 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02006274 new_cpu = ENV_GET_CPU(new_env);
6275 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03006276 ts->bprm = parent_ts->bprm;
6277 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01006278 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00006279
Peter Maydell7cfbd382016-08-02 18:41:26 +01006280 if (flags & CLONE_CHILD_CLEARTID) {
pbrookc2764712009-03-07 15:24:59 +00006281 ts->child_tidptr = child_tidptr;
6282 }
6283
Peter Maydell7cfbd382016-08-02 18:41:26 +01006284 if (flags & CLONE_SETTLS) {
pbrookd865bab2008-06-07 22:12:17 +00006285 cpu_set_tls (new_env, newtls);
Peter Maydell7cfbd382016-08-02 18:41:26 +01006286 }
pbrookd865bab2008-06-07 22:12:17 +00006287
6288 /* Grab a mutex so that thread setup appears atomic. */
6289 pthread_mutex_lock(&clone_lock);
6290
6291 memset(&info, 0, sizeof(info));
6292 pthread_mutex_init(&info.mutex, NULL);
6293 pthread_mutex_lock(&info.mutex);
6294 pthread_cond_init(&info.cond, NULL);
6295 info.env = new_env;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006296 if (flags & CLONE_CHILD_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006297 info.child_tidptr = child_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006298 }
6299 if (flags & CLONE_PARENT_SETTID) {
pbrookd865bab2008-06-07 22:12:17 +00006300 info.parent_tidptr = parent_tidptr;
Peter Maydell7cfbd382016-08-02 18:41:26 +01006301 }
pbrookd865bab2008-06-07 22:12:17 +00006302
6303 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07006304 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
6305 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00006306 /* It is not safe to deliver signals until the child has finished
6307 initializing, so temporarily block all signals. */
6308 sigfillset(&sigmask);
6309 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
6310
Alex Bennéeb67cb682016-10-05 11:13:04 -07006311 /* If this is our first additional thread, we need to ensure we
6312 * generate code for parallel execution and flush old translations.
6313 */
6314 if (!parallel_cpus) {
6315 parallel_cpus = true;
6316 tb_flush(cpu);
6317 }
6318
pbrookd865bab2008-06-07 22:12:17 +00006319 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00006320 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00006321
6322 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
6323 pthread_attr_destroy(&attr);
6324 if (ret == 0) {
6325 /* Wait for the child to initialize. */
6326 pthread_cond_wait(&info.cond, &info.mutex);
6327 ret = info.tid;
pbrookd865bab2008-06-07 22:12:17 +00006328 } else {
6329 ret = -1;
6330 }
6331 pthread_mutex_unlock(&info.mutex);
6332 pthread_cond_destroy(&info.cond);
6333 pthread_mutex_destroy(&info.mutex);
6334 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00006335 } else {
6336 /* if no CLONE_VM, we consider it is a fork */
Peter Maydell5ea2fc82016-08-02 18:41:27 +01006337 if (flags & CLONE_INVALID_FORK_FLAGS) {
6338 return -TARGET_EINVAL;
6339 }
6340
6341 /* We can't support custom termination signals */
6342 if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01006343 return -TARGET_EINVAL;
6344 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01006345
6346 if (block_signals()) {
6347 return -TARGET_ERESTARTSYS;
6348 }
6349
pbrookd865bab2008-06-07 22:12:17 +00006350 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00006351 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00006352 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00006353 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02006354 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00006355 cpu_clone_regs(env, newsp);
6356 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00006357 /* There is a race condition here. The parent process could
6358 theoretically read the TID in the child process before the child
6359 tid is set. This would require using either ptrace
6360 (not implemented) or having *_tidptr to point at a shared memory
6361 mapping. We can't repeat the spinlock hack used above because
6362 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00006363 if (flags & CLONE_CHILD_SETTID)
6364 put_user_u32(gettid(), child_tidptr);
6365 if (flags & CLONE_PARENT_SETTID)
6366 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02006367 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00006368 if (flags & CLONE_SETTLS)
6369 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00006370 if (flags & CLONE_CHILD_CLEARTID)
6371 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00006372 } else {
6373 fork_end(0);
6374 }
bellard1b6b0292003-03-22 17:31:38 +00006375 }
6376 return ret;
6377}
6378
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006379/* warning : doesn't handle linux specific flags... */
6380static int target_to_host_fcntl_cmd(int cmd)
6381{
6382 switch(cmd) {
6383 case TARGET_F_DUPFD:
6384 case TARGET_F_GETFD:
6385 case TARGET_F_SETFD:
6386 case TARGET_F_GETFL:
6387 case TARGET_F_SETFL:
6388 return cmd;
6389 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006390 return F_GETLK64;
6391 case TARGET_F_SETLK:
6392 return F_SETLK64;
6393 case TARGET_F_SETLKW:
6394 return F_SETLKW64;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006395 case TARGET_F_GETOWN:
6396 return F_GETOWN;
6397 case TARGET_F_SETOWN:
6398 return F_SETOWN;
6399 case TARGET_F_GETSIG:
6400 return F_GETSIG;
6401 case TARGET_F_SETSIG:
6402 return F_SETSIG;
6403#if TARGET_ABI_BITS == 32
6404 case TARGET_F_GETLK64:
6405 return F_GETLK64;
6406 case TARGET_F_SETLK64:
6407 return F_SETLK64;
6408 case TARGET_F_SETLKW64:
6409 return F_SETLKW64;
6410#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006411 case TARGET_F_SETLEASE:
6412 return F_SETLEASE;
6413 case TARGET_F_GETLEASE:
6414 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04006415#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006416 case TARGET_F_DUPFD_CLOEXEC:
6417 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04006418#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006419 case TARGET_F_NOTIFY:
6420 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006421#ifdef F_GETOWN_EX
6422 case TARGET_F_GETOWN_EX:
6423 return F_GETOWN_EX;
6424#endif
6425#ifdef F_SETOWN_EX
6426 case TARGET_F_SETOWN_EX:
6427 return F_SETOWN_EX;
6428#endif
Peter Maydellddf31aa2016-06-30 17:33:49 +01006429#ifdef F_SETPIPE_SZ
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006430 case TARGET_F_SETPIPE_SZ:
6431 return F_SETPIPE_SZ;
6432 case TARGET_F_GETPIPE_SZ:
6433 return F_GETPIPE_SZ;
Peter Maydellddf31aa2016-06-30 17:33:49 +01006434#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006435 default:
6436 return -TARGET_EINVAL;
6437 }
6438 return -TARGET_EINVAL;
6439}
6440
Laurent Vivier2ba7f732013-01-10 21:42:48 +01006441#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
6442static const bitmask_transtbl flock_tbl[] = {
6443 TRANSTBL_CONVERT(F_RDLCK),
6444 TRANSTBL_CONVERT(F_WRLCK),
6445 TRANSTBL_CONVERT(F_UNLCK),
6446 TRANSTBL_CONVERT(F_EXLCK),
6447 TRANSTBL_CONVERT(F_SHLCK),
6448 { 0, 0, 0, 0 }
6449};
6450
Peter Maydell213d3e92016-06-13 11:22:05 +01006451static inline abi_long copy_from_user_flock(struct flock64 *fl,
6452 abi_ulong target_flock_addr)
6453{
6454 struct target_flock *target_fl;
6455 short l_type;
6456
6457 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6458 return -TARGET_EFAULT;
6459 }
6460
6461 __get_user(l_type, &target_fl->l_type);
6462 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6463 __get_user(fl->l_whence, &target_fl->l_whence);
6464 __get_user(fl->l_start, &target_fl->l_start);
6465 __get_user(fl->l_len, &target_fl->l_len);
6466 __get_user(fl->l_pid, &target_fl->l_pid);
6467 unlock_user_struct(target_fl, target_flock_addr, 0);
6468 return 0;
6469}
6470
6471static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
6472 const struct flock64 *fl)
6473{
6474 struct target_flock *target_fl;
6475 short l_type;
6476
6477 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6478 return -TARGET_EFAULT;
6479 }
6480
6481 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6482 __put_user(l_type, &target_fl->l_type);
6483 __put_user(fl->l_whence, &target_fl->l_whence);
6484 __put_user(fl->l_start, &target_fl->l_start);
6485 __put_user(fl->l_len, &target_fl->l_len);
6486 __put_user(fl->l_pid, &target_fl->l_pid);
6487 unlock_user_struct(target_fl, target_flock_addr, 1);
6488 return 0;
6489}
6490
6491typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
6492typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
6493
6494#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
6495static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
6496 abi_ulong target_flock_addr)
6497{
6498 struct target_eabi_flock64 *target_fl;
6499 short l_type;
6500
6501 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6502 return -TARGET_EFAULT;
6503 }
6504
6505 __get_user(l_type, &target_fl->l_type);
6506 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6507 __get_user(fl->l_whence, &target_fl->l_whence);
6508 __get_user(fl->l_start, &target_fl->l_start);
6509 __get_user(fl->l_len, &target_fl->l_len);
6510 __get_user(fl->l_pid, &target_fl->l_pid);
6511 unlock_user_struct(target_fl, target_flock_addr, 0);
6512 return 0;
6513}
6514
6515static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
6516 const struct flock64 *fl)
6517{
6518 struct target_eabi_flock64 *target_fl;
6519 short l_type;
6520
6521 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6522 return -TARGET_EFAULT;
6523 }
6524
6525 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6526 __put_user(l_type, &target_fl->l_type);
6527 __put_user(fl->l_whence, &target_fl->l_whence);
6528 __put_user(fl->l_start, &target_fl->l_start);
6529 __put_user(fl->l_len, &target_fl->l_len);
6530 __put_user(fl->l_pid, &target_fl->l_pid);
6531 unlock_user_struct(target_fl, target_flock_addr, 1);
6532 return 0;
6533}
6534#endif
6535
6536static inline abi_long copy_from_user_flock64(struct flock64 *fl,
6537 abi_ulong target_flock_addr)
6538{
6539 struct target_flock64 *target_fl;
6540 short l_type;
6541
6542 if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
6543 return -TARGET_EFAULT;
6544 }
6545
6546 __get_user(l_type, &target_fl->l_type);
6547 fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
6548 __get_user(fl->l_whence, &target_fl->l_whence);
6549 __get_user(fl->l_start, &target_fl->l_start);
6550 __get_user(fl->l_len, &target_fl->l_len);
6551 __get_user(fl->l_pid, &target_fl->l_pid);
6552 unlock_user_struct(target_fl, target_flock_addr, 0);
6553 return 0;
6554}
6555
6556static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
6557 const struct flock64 *fl)
6558{
6559 struct target_flock64 *target_fl;
6560 short l_type;
6561
6562 if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
6563 return -TARGET_EFAULT;
6564 }
6565
6566 l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
6567 __put_user(l_type, &target_fl->l_type);
6568 __put_user(fl->l_whence, &target_fl->l_whence);
6569 __put_user(fl->l_start, &target_fl->l_start);
6570 __put_user(fl->l_len, &target_fl->l_len);
6571 __put_user(fl->l_pid, &target_fl->l_pid);
6572 unlock_user_struct(target_fl, target_flock_addr, 1);
6573 return 0;
6574}
6575
blueswir1992f48a2007-10-14 16:27:31 +00006576static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00006577{
ths43f238d2007-01-05 20:55:49 +00006578 struct flock64 fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006579#ifdef F_GETOWN_EX
6580 struct f_owner_ex fox;
6581 struct target_f_owner_ex *target_fox;
6582#endif
blueswir1992f48a2007-10-14 16:27:31 +00006583 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006584 int host_cmd = target_to_host_fcntl_cmd(cmd);
6585
6586 if (host_cmd == -TARGET_EINVAL)
6587 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00006588
bellard7775e9e2003-05-14 22:46:48 +00006589 switch(cmd) {
6590 case TARGET_F_GETLK:
Peter Maydell213d3e92016-06-13 11:22:05 +01006591 ret = copy_from_user_flock(&fl64, arg);
6592 if (ret) {
6593 return ret;
6594 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006595 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006596 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006597 ret = copy_to_user_flock(arg, &fl64);
bellard7775e9e2003-05-14 22:46:48 +00006598 }
6599 break;
ths3b46e622007-09-17 08:09:54 +00006600
bellard7775e9e2003-05-14 22:46:48 +00006601 case TARGET_F_SETLK:
6602 case TARGET_F_SETLKW:
Peter Maydell213d3e92016-06-13 11:22:05 +01006603 ret = copy_from_user_flock(&fl64, arg);
6604 if (ret) {
6605 return ret;
6606 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006607 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006608 break;
ths3b46e622007-09-17 08:09:54 +00006609
bellard7775e9e2003-05-14 22:46:48 +00006610 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006611 ret = copy_from_user_flock64(&fl64, arg);
6612 if (ret) {
6613 return ret;
6614 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006615 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00006616 if (ret == 0) {
Peter Maydell213d3e92016-06-13 11:22:05 +01006617 ret = copy_to_user_flock64(arg, &fl64);
ths43f238d2007-01-05 20:55:49 +00006618 }
bellard9ee1fa22007-11-11 15:11:19 +00006619 break;
bellard7775e9e2003-05-14 22:46:48 +00006620 case TARGET_F_SETLK64:
6621 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +01006622 ret = copy_from_user_flock64(&fl64, arg);
6623 if (ret) {
6624 return ret;
6625 }
Peter Maydell435da5e2016-06-13 11:22:05 +01006626 ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00006627 break;
6628
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006629 case TARGET_F_GETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006630 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00006631 if (ret >= 0) {
6632 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
6633 }
bellardffa65c32004-01-04 23:57:22 +00006634 break;
6635
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006636 case TARGET_F_SETFL:
Peter Maydell435da5e2016-06-13 11:22:05 +01006637 ret = get_errno(safe_fcntl(fd, host_cmd,
6638 target_to_host_bitmask(arg,
6639 fcntl_flags_tbl)));
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006640 break;
6641
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006642#ifdef F_GETOWN_EX
6643 case TARGET_F_GETOWN_EX:
Peter Maydell435da5e2016-06-13 11:22:05 +01006644 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006645 if (ret >= 0) {
6646 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
6647 return -TARGET_EFAULT;
6648 target_fox->type = tswap32(fox.type);
6649 target_fox->pid = tswap32(fox.pid);
6650 unlock_user_struct(target_fox, arg, 1);
6651 }
6652 break;
6653#endif
6654
6655#ifdef F_SETOWN_EX
6656 case TARGET_F_SETOWN_EX:
6657 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
6658 return -TARGET_EFAULT;
6659 fox.type = tswap32(target_fox->type);
6660 fox.pid = tswap32(target_fox->pid);
6661 unlock_user_struct(target_fox, arg, 0);
Peter Maydell435da5e2016-06-13 11:22:05 +01006662 ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
Andreas Schwab8d5d3002014-03-07 15:24:08 +01006663 break;
6664#endif
6665
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02006666 case TARGET_F_SETOWN:
6667 case TARGET_F_GETOWN:
6668 case TARGET_F_SETSIG:
6669 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02006670 case TARGET_F_SETLEASE:
6671 case TARGET_F_GETLEASE:
Peter Maydell7e3b92e2016-06-20 15:50:37 +01006672 case TARGET_F_SETPIPE_SZ:
6673 case TARGET_F_GETPIPE_SZ:
Peter Maydell435da5e2016-06-13 11:22:05 +01006674 ret = get_errno(safe_fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00006675 break;
6676
bellard7775e9e2003-05-14 22:46:48 +00006677 default:
Peter Maydell435da5e2016-06-13 11:22:05 +01006678 ret = get_errno(safe_fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00006679 break;
6680 }
6681 return ret;
6682}
6683
bellard67867302003-11-23 17:05:30 +00006684#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00006685
bellard67867302003-11-23 17:05:30 +00006686static inline int high2lowuid(int uid)
6687{
6688 if (uid > 65535)
6689 return 65534;
6690 else
6691 return uid;
6692}
6693
6694static inline int high2lowgid(int gid)
6695{
6696 if (gid > 65535)
6697 return 65534;
6698 else
6699 return gid;
6700}
6701
6702static inline int low2highuid(int uid)
6703{
6704 if ((int16_t)uid == -1)
6705 return -1;
6706 else
6707 return uid;
6708}
6709
6710static inline int low2highgid(int gid)
6711{
6712 if ((int16_t)gid == -1)
6713 return -1;
6714 else
6715 return gid;
6716}
Riku Voipio0c866a72011-04-18 15:23:06 +03006717static inline int tswapid(int id)
6718{
6719 return tswap16(id);
6720}
Peter Maydell76ca3102014-03-02 19:36:41 +00006721
6722#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
6723
Riku Voipio0c866a72011-04-18 15:23:06 +03006724#else /* !USE_UID16 */
6725static inline int high2lowuid(int uid)
6726{
6727 return uid;
6728}
6729static inline int high2lowgid(int gid)
6730{
6731 return gid;
6732}
6733static inline int low2highuid(int uid)
6734{
6735 return uid;
6736}
6737static inline int low2highgid(int gid)
6738{
6739 return gid;
6740}
6741static inline int tswapid(int id)
6742{
6743 return tswap32(id);
6744}
Peter Maydell76ca3102014-03-02 19:36:41 +00006745
6746#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
6747
bellard67867302003-11-23 17:05:30 +00006748#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00006749
Peter Maydellfd6f7792016-03-01 16:33:02 +00006750/* We must do direct syscalls for setting UID/GID, because we want to
6751 * implement the Linux system call semantics of "change only for this thread",
6752 * not the libc/POSIX semantics of "change for all threads in process".
6753 * (See http://ewontfix.com/17/ for more details.)
6754 * We use the 32-bit version of the syscalls if present; if it is not
6755 * then either the host architecture supports 32-bit UIDs natively with
6756 * the standard syscall, or the 16-bit UID is the best we can do.
6757 */
6758#ifdef __NR_setuid32
6759#define __NR_sys_setuid __NR_setuid32
6760#else
6761#define __NR_sys_setuid __NR_setuid
6762#endif
6763#ifdef __NR_setgid32
6764#define __NR_sys_setgid __NR_setgid32
6765#else
6766#define __NR_sys_setgid __NR_setgid
6767#endif
6768#ifdef __NR_setresuid32
6769#define __NR_sys_setresuid __NR_setresuid32
6770#else
6771#define __NR_sys_setresuid __NR_setresuid
6772#endif
6773#ifdef __NR_setresgid32
6774#define __NR_sys_setresgid __NR_setresgid32
6775#else
6776#define __NR_sys_setresgid __NR_setresgid
6777#endif
6778
6779_syscall1(int, sys_setuid, uid_t, uid)
6780_syscall1(int, sys_setgid, gid_t, gid)
6781_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
6782_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
6783
bellard31e31b82003-02-18 22:55:36 +00006784void syscall_init(void)
6785{
bellard2ab83ea2003-06-15 19:56:46 +00006786 IOCTLEntry *ie;
6787 const argtype *arg_type;
6788 int size;
thsb92c47c2007-11-01 00:07:38 +00006789 int i;
bellard2ab83ea2003-06-15 19:56:46 +00006790
Alexander Graf8be656b2015-05-06 23:47:32 +02006791 thunk_init(STRUCT_MAX);
6792
Blue Swirl001faf32009-05-13 17:53:17 +00006793#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00006794#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00006795#include "syscall_types.h"
6796#undef STRUCT
6797#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00006798
Peter Maydelldd6e9572012-07-23 08:07:22 +00006799 /* Build target_to_host_errno_table[] table from
6800 * host_to_target_errno_table[]. */
6801 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
6802 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
6803 }
6804
bellard2ab83ea2003-06-15 19:56:46 +00006805 /* we patch the ioctl size if necessary. We rely on the fact that
6806 no ioctl has all the bits at '1' in the size field */
6807 ie = ioctl_entries;
6808 while (ie->target_cmd != 0) {
6809 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
6810 TARGET_IOC_SIZEMASK) {
6811 arg_type = ie->arg_type;
6812 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00006813 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00006814 ie->target_cmd);
6815 exit(1);
6816 }
6817 arg_type++;
6818 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00006819 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00006820 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
6821 (size << TARGET_IOC_SIZESHIFT);
6822 }
thsb92c47c2007-11-01 00:07:38 +00006823
bellard2ab83ea2003-06-15 19:56:46 +00006824 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00006825#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6826 (defined(__x86_64__) && defined(TARGET_X86_64))
6827 if (unlikely(ie->target_cmd != ie->host_cmd)) {
6828 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
6829 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00006830 }
6831#endif
6832 ie++;
6833 }
bellard31e31b82003-02-18 22:55:36 +00006834}
bellardc573ff62004-01-04 15:51:36 +00006835
blueswir1992f48a2007-10-14 16:27:31 +00006836#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00006837static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
6838{
thsaf325d32008-06-10 15:29:15 +00006839#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00006840 return ((uint64_t)word0 << 32) | word1;
6841#else
6842 return ((uint64_t)word1 << 32) | word0;
6843#endif
6844}
blueswir1992f48a2007-10-14 16:27:31 +00006845#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00006846static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
6847{
6848 return word0;
6849}
blueswir1992f48a2007-10-14 16:27:31 +00006850#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00006851
6852#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00006853static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
6854 abi_long arg2,
6855 abi_long arg3,
6856 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006857{
Riku Voipio48e515d2011-07-12 15:40:51 +03006858 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006859 arg2 = arg3;
6860 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006861 }
pbrookce4defa2006-02-09 16:49:55 +00006862 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
6863}
6864#endif
6865
6866#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00006867static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
6868 abi_long arg2,
6869 abi_long arg3,
6870 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00006871{
Riku Voipio48e515d2011-07-12 15:40:51 +03006872 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00006873 arg2 = arg3;
6874 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03006875 }
pbrookce4defa2006-02-09 16:49:55 +00006876 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
6877}
6878#endif
6879
bellard579a97f2007-11-11 14:26:47 +00006880static inline abi_long target_to_host_timespec(struct timespec *host_ts,
6881 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00006882{
6883 struct target_timespec *target_ts;
6884
bellard579a97f2007-11-11 14:26:47 +00006885 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
6886 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006887 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
6888 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006889 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00006890 return 0;
pbrook53a59602006-03-25 19:31:22 +00006891}
6892
bellard579a97f2007-11-11 14:26:47 +00006893static inline abi_long host_to_target_timespec(abi_ulong target_addr,
6894 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00006895{
6896 struct target_timespec *target_ts;
6897
bellard579a97f2007-11-11 14:26:47 +00006898 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
6899 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01006900 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
6901 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00006902 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00006903 return 0;
pbrook53a59602006-03-25 19:31:22 +00006904}
6905
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11006906static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
6907 abi_ulong target_addr)
6908{
6909 struct target_itimerspec *target_itspec;
6910
6911 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
6912 return -TARGET_EFAULT;
6913 }
6914
6915 host_itspec->it_interval.tv_sec =
6916 tswapal(target_itspec->it_interval.tv_sec);
6917 host_itspec->it_interval.tv_nsec =
6918 tswapal(target_itspec->it_interval.tv_nsec);
6919 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
6920 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
6921
6922 unlock_user_struct(target_itspec, target_addr, 1);
6923 return 0;
6924}
6925
6926static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
6927 struct itimerspec *host_its)
6928{
6929 struct target_itimerspec *target_itspec;
6930
6931 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
6932 return -TARGET_EFAULT;
6933 }
6934
6935 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
6936 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
6937
6938 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
6939 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
6940
6941 unlock_user_struct(target_itspec, target_addr, 0);
6942 return 0;
6943}
6944
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02006945static inline abi_long target_to_host_timex(struct timex *host_tx,
6946 abi_long target_addr)
6947{
6948 struct target_timex *target_tx;
6949
6950 if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
6951 return -TARGET_EFAULT;
6952 }
6953
6954 __get_user(host_tx->modes, &target_tx->modes);
6955 __get_user(host_tx->offset, &target_tx->offset);
6956 __get_user(host_tx->freq, &target_tx->freq);
6957 __get_user(host_tx->maxerror, &target_tx->maxerror);
6958 __get_user(host_tx->esterror, &target_tx->esterror);
6959 __get_user(host_tx->status, &target_tx->status);
6960 __get_user(host_tx->constant, &target_tx->constant);
6961 __get_user(host_tx->precision, &target_tx->precision);
6962 __get_user(host_tx->tolerance, &target_tx->tolerance);
6963 __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6964 __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
6965 __get_user(host_tx->tick, &target_tx->tick);
6966 __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
6967 __get_user(host_tx->jitter, &target_tx->jitter);
6968 __get_user(host_tx->shift, &target_tx->shift);
6969 __get_user(host_tx->stabil, &target_tx->stabil);
6970 __get_user(host_tx->jitcnt, &target_tx->jitcnt);
6971 __get_user(host_tx->calcnt, &target_tx->calcnt);
6972 __get_user(host_tx->errcnt, &target_tx->errcnt);
6973 __get_user(host_tx->stbcnt, &target_tx->stbcnt);
6974 __get_user(host_tx->tai, &target_tx->tai);
6975
6976 unlock_user_struct(target_tx, target_addr, 0);
6977 return 0;
6978}
6979
6980static inline abi_long host_to_target_timex(abi_long target_addr,
6981 struct timex *host_tx)
6982{
6983 struct target_timex *target_tx;
6984
6985 if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
6986 return -TARGET_EFAULT;
6987 }
6988
6989 __put_user(host_tx->modes, &target_tx->modes);
6990 __put_user(host_tx->offset, &target_tx->offset);
6991 __put_user(host_tx->freq, &target_tx->freq);
6992 __put_user(host_tx->maxerror, &target_tx->maxerror);
6993 __put_user(host_tx->esterror, &target_tx->esterror);
6994 __put_user(host_tx->status, &target_tx->status);
6995 __put_user(host_tx->constant, &target_tx->constant);
6996 __put_user(host_tx->precision, &target_tx->precision);
6997 __put_user(host_tx->tolerance, &target_tx->tolerance);
6998 __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec);
6999 __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec);
7000 __put_user(host_tx->tick, &target_tx->tick);
7001 __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
7002 __put_user(host_tx->jitter, &target_tx->jitter);
7003 __put_user(host_tx->shift, &target_tx->shift);
7004 __put_user(host_tx->stabil, &target_tx->stabil);
7005 __put_user(host_tx->jitcnt, &target_tx->jitcnt);
7006 __put_user(host_tx->calcnt, &target_tx->calcnt);
7007 __put_user(host_tx->errcnt, &target_tx->errcnt);
7008 __put_user(host_tx->stbcnt, &target_tx->stbcnt);
7009 __put_user(host_tx->tai, &target_tx->tai);
7010
7011 unlock_user_struct(target_tx, target_addr, 1);
7012 return 0;
7013}
7014
7015
Peter Maydellc0659762014-08-09 15:42:32 +01007016static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
7017 abi_ulong target_addr)
7018{
7019 struct target_sigevent *target_sevp;
7020
7021 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
7022 return -TARGET_EFAULT;
7023 }
7024
7025 /* This union is awkward on 64 bit systems because it has a 32 bit
7026 * integer and a pointer in it; we follow the conversion approach
7027 * used for handling sigval types in signal.c so the guest should get
7028 * the correct value back even if we did a 64 bit byteswap and it's
7029 * using the 32 bit integer.
7030 */
7031 host_sevp->sigev_value.sival_ptr =
7032 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
7033 host_sevp->sigev_signo =
7034 target_to_host_signal(tswap32(target_sevp->sigev_signo));
7035 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
7036 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
7037
7038 unlock_user_struct(target_sevp, target_addr, 1);
7039 return 0;
7040}
7041
Tom Musta6f6a4032014-08-12 13:53:42 -05007042#if defined(TARGET_NR_mlockall)
7043static inline int target_to_host_mlockall_arg(int arg)
7044{
7045 int result = 0;
7046
7047 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
7048 result |= MCL_CURRENT;
7049 }
7050 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
7051 result |= MCL_FUTURE;
7052 }
7053 return result;
7054}
7055#endif
7056
balrog6a24a772008-09-20 02:23:36 +00007057static inline abi_long host_to_target_stat64(void *cpu_env,
7058 abi_ulong target_addr,
7059 struct stat *host_st)
7060{
Alexander Graf09701192013-09-03 20:12:15 +01007061#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00007062 if (((CPUARMState *)cpu_env)->eabi) {
7063 struct target_eabi_stat64 *target_st;
7064
7065 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7066 return -TARGET_EFAULT;
7067 memset(target_st, 0, sizeof(struct target_eabi_stat64));
7068 __put_user(host_st->st_dev, &target_st->st_dev);
7069 __put_user(host_st->st_ino, &target_st->st_ino);
7070#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7071 __put_user(host_st->st_ino, &target_st->__st_ino);
7072#endif
7073 __put_user(host_st->st_mode, &target_st->st_mode);
7074 __put_user(host_st->st_nlink, &target_st->st_nlink);
7075 __put_user(host_st->st_uid, &target_st->st_uid);
7076 __put_user(host_st->st_gid, &target_st->st_gid);
7077 __put_user(host_st->st_rdev, &target_st->st_rdev);
7078 __put_user(host_st->st_size, &target_st->st_size);
7079 __put_user(host_st->st_blksize, &target_st->st_blksize);
7080 __put_user(host_st->st_blocks, &target_st->st_blocks);
7081 __put_user(host_st->st_atime, &target_st->target_st_atime);
7082 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7083 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7084 unlock_user_struct(target_st, target_addr, 1);
7085 } else
7086#endif
7087 {
Stefan Weil20d155b2013-10-30 22:52:24 +01007088#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00007089 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01007090#else
7091 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00007092#endif
balrog6a24a772008-09-20 02:23:36 +00007093
7094 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
7095 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00007096 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00007097 __put_user(host_st->st_dev, &target_st->st_dev);
7098 __put_user(host_st->st_ino, &target_st->st_ino);
7099#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
7100 __put_user(host_st->st_ino, &target_st->__st_ino);
7101#endif
7102 __put_user(host_st->st_mode, &target_st->st_mode);
7103 __put_user(host_st->st_nlink, &target_st->st_nlink);
7104 __put_user(host_st->st_uid, &target_st->st_uid);
7105 __put_user(host_st->st_gid, &target_st->st_gid);
7106 __put_user(host_st->st_rdev, &target_st->st_rdev);
7107 /* XXX: better use of kernel struct */
7108 __put_user(host_st->st_size, &target_st->st_size);
7109 __put_user(host_st->st_blksize, &target_st->st_blksize);
7110 __put_user(host_st->st_blocks, &target_st->st_blocks);
7111 __put_user(host_st->st_atime, &target_st->target_st_atime);
7112 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
7113 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
7114 unlock_user_struct(target_st, target_addr, 1);
7115 }
7116
7117 return 0;
7118}
balrog6a24a772008-09-20 02:23:36 +00007119
pbrookbd0c5662008-05-29 14:34:11 +00007120/* ??? Using host futex calls even when target atomic operations
7121 are not really atomic probably breaks things. However implementing
7122 futexes locally would make futexes shared between multiple processes
7123 tricky. However they're probably useless because guest atomic
7124 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00007125static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
7126 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00007127{
7128 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07007129 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00007130
7131 /* ??? We assume FUTEX_* constants are the same on both host
7132 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03007133#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07007134 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007135#else
Nathan Froyda16aae02009-08-03 08:43:29 -07007136 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03007137#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07007138 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00007139 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07007140 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00007141 if (timeout) {
7142 pts = &ts;
7143 target_to_host_timespec(pts, timeout);
7144 } else {
7145 pts = NULL;
7146 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01007147 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07007148 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00007149 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007150 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007151 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01007152 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00007153 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00007154 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07007155 case FUTEX_WAKE_OP:
7156 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
7157 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
7158 But the prototype takes a `struct timespec *'; insert casts
7159 to satisfy the compiler. We do not need to tswap TIMEOUT
7160 since it's not compared to guest memory. */
7161 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01007162 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
7163 g2h(uaddr2),
7164 (base_op == FUTEX_CMP_REQUEUE
7165 ? tswap32(val3)
7166 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00007167 default:
7168 return -TARGET_ENOSYS;
7169 }
7170}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007171#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7172static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
7173 abi_long handle, abi_long mount_id,
7174 abi_long flags)
7175{
7176 struct file_handle *target_fh;
7177 struct file_handle *fh;
7178 int mid = 0;
7179 abi_long ret;
7180 char *name;
7181 unsigned int size, total_size;
7182
7183 if (get_user_s32(size, handle)) {
7184 return -TARGET_EFAULT;
7185 }
7186
7187 name = lock_user_string(pathname);
7188 if (!name) {
7189 return -TARGET_EFAULT;
7190 }
7191
7192 total_size = sizeof(struct file_handle) + size;
7193 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
7194 if (!target_fh) {
7195 unlock_user(name, pathname, 0);
7196 return -TARGET_EFAULT;
7197 }
7198
7199 fh = g_malloc0(total_size);
7200 fh->handle_bytes = size;
7201
7202 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
7203 unlock_user(name, pathname, 0);
7204
7205 /* man name_to_handle_at(2):
7206 * Other than the use of the handle_bytes field, the caller should treat
7207 * the file_handle structure as an opaque data type
7208 */
7209
7210 memcpy(target_fh, fh, total_size);
7211 target_fh->handle_bytes = tswap32(fh->handle_bytes);
7212 target_fh->handle_type = tswap32(fh->handle_type);
7213 g_free(fh);
7214 unlock_user(target_fh, handle, total_size);
7215
7216 if (put_user_s32(mid, mount_id)) {
7217 return -TARGET_EFAULT;
7218 }
7219
7220 return ret;
7221
7222}
7223#endif
7224
7225#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7226static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
7227 abi_long flags)
7228{
7229 struct file_handle *target_fh;
7230 struct file_handle *fh;
7231 unsigned int size, total_size;
7232 abi_long ret;
7233
7234 if (get_user_s32(size, handle)) {
7235 return -TARGET_EFAULT;
7236 }
7237
7238 total_size = sizeof(struct file_handle) + size;
7239 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
7240 if (!target_fh) {
7241 return -TARGET_EFAULT;
7242 }
7243
Thomas Huthe9d49d52015-10-09 17:56:38 +02007244 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007245 fh->handle_bytes = size;
7246 fh->handle_type = tswap32(target_fh->handle_type);
7247
7248 ret = get_errno(open_by_handle_at(mount_fd, fh,
7249 target_to_host_bitmask(flags, fcntl_flags_tbl)));
7250
7251 g_free(fh);
7252
7253 unlock_user(target_fh, handle, total_size);
7254
7255 return ret;
7256}
7257#endif
pbrookbd0c5662008-05-29 14:34:11 +00007258
Laurent Viviere36800c2015-10-02 14:48:09 +02007259#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
7260
7261/* signalfd siginfo conversion */
7262
7263static void
7264host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
7265 const struct signalfd_siginfo *info)
7266{
7267 int sig = host_to_target_signal(info->ssi_signo);
7268
7269 /* linux/signalfd.h defines a ssi_addr_lsb
7270 * not defined in sys/signalfd.h but used by some kernels
7271 */
7272
7273#ifdef BUS_MCEERR_AO
7274 if (tinfo->ssi_signo == SIGBUS &&
7275 (tinfo->ssi_code == BUS_MCEERR_AR ||
7276 tinfo->ssi_code == BUS_MCEERR_AO)) {
7277 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
7278 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
7279 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
7280 }
7281#endif
7282
7283 tinfo->ssi_signo = tswap32(sig);
7284 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
7285 tinfo->ssi_code = tswap32(info->ssi_code);
7286 tinfo->ssi_pid = tswap32(info->ssi_pid);
7287 tinfo->ssi_uid = tswap32(info->ssi_uid);
7288 tinfo->ssi_fd = tswap32(info->ssi_fd);
7289 tinfo->ssi_tid = tswap32(info->ssi_tid);
7290 tinfo->ssi_band = tswap32(info->ssi_band);
7291 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
7292 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
7293 tinfo->ssi_status = tswap32(info->ssi_status);
7294 tinfo->ssi_int = tswap32(info->ssi_int);
7295 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
7296 tinfo->ssi_utime = tswap64(info->ssi_utime);
7297 tinfo->ssi_stime = tswap64(info->ssi_stime);
7298 tinfo->ssi_addr = tswap64(info->ssi_addr);
7299}
7300
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007301static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02007302{
7303 int i;
7304
7305 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
7306 host_to_target_signalfd_siginfo(buf + i, buf + i);
7307 }
7308
7309 return len;
7310}
7311
7312static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007313 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02007314};
7315
7316static abi_long do_signalfd4(int fd, abi_long mask, int flags)
7317{
7318 int host_flags;
7319 target_sigset_t *target_mask;
7320 sigset_t host_mask;
7321 abi_long ret;
7322
7323 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
7324 return -TARGET_EINVAL;
7325 }
7326 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
7327 return -TARGET_EFAULT;
7328 }
7329
7330 target_to_host_sigset(&host_mask, target_mask);
7331
7332 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
7333
7334 ret = get_errno(signalfd(fd, &host_mask, host_flags));
7335 if (ret >= 0) {
7336 fd_trans_register(ret, &target_signalfd_trans);
7337 }
7338
7339 unlock_user_struct(target_mask, mask, 0);
7340
7341 return ret;
7342}
7343#endif
7344
pbrook1d9d8b52009-04-16 15:17:02 +00007345/* Map host to target signal numbers for the wait family of syscalls.
7346 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07007347int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00007348{
7349 if (WIFSIGNALED(status)) {
7350 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
7351 }
7352 if (WIFSTOPPED(status)) {
7353 return (host_to_target_signal(WSTOPSIG(status)) << 8)
7354 | (status & 0xff);
7355 }
7356 return status;
7357}
7358
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007359static int open_self_cmdline(void *cpu_env, int fd)
7360{
Andreas Schwab58de8b92017-03-20 12:31:55 +01007361 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7362 struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
7363 int i;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007364
Andreas Schwab58de8b92017-03-20 12:31:55 +01007365 for (i = 0; i < bprm->argc; i++) {
7366 size_t len = strlen(bprm->argv[i]) + 1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007367
Andreas Schwab58de8b92017-03-20 12:31:55 +01007368 if (write(fd, bprm->argv[i], len) != len) {
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007369 return -1;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007370 }
7371 }
7372
Andreas Schwab58de8b92017-03-20 12:31:55 +01007373 return 0;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007374}
7375
Alexander Graf36c08d42011-11-02 20:23:24 +01007376static int open_self_maps(void *cpu_env, int fd)
7377{
Andreas Färber0429a972013-08-26 18:14:44 +02007378 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7379 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007380 FILE *fp;
7381 char *line = NULL;
7382 size_t len = 0;
7383 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01007384
Alexander Graf1a49ef22012-05-01 16:30:28 +01007385 fp = fopen("/proc/self/maps", "r");
7386 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007387 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01007388 }
7389
7390 while ((read = getline(&line, &len, fp)) != -1) {
7391 int fields, dev_maj, dev_min, inode;
7392 uint64_t min, max, offset;
7393 char flag_r, flag_w, flag_x, flag_p;
7394 char path[512] = "";
7395 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
7396 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
7397 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
7398
7399 if ((fields < 10) || (fields > 11)) {
7400 continue;
7401 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007402 if (h2g_valid(min)) {
7403 int flags = page_get_flags(h2g(min));
7404 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
7405 if (page_check_range(h2g(min), max - min, flags) == -1) {
7406 continue;
7407 }
7408 if (h2g(min) == ts->info->stack_limit) {
7409 pstrcpy(path, sizeof(path), " [stack]");
7410 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01007411 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02007412 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04007413 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01007414 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02007415 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01007416 }
7417 }
7418
7419 free(line);
7420 fclose(fp);
7421
Alexander Graf36c08d42011-11-02 20:23:24 +01007422 return 0;
7423}
7424
Alexander Graf480b8e72011-11-02 20:23:25 +01007425static int open_self_stat(void *cpu_env, int fd)
7426{
Andreas Färber0429a972013-08-26 18:14:44 +02007427 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7428 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01007429 abi_ulong start_stack = ts->info->start_stack;
7430 int i;
7431
7432 for (i = 0; i < 44; i++) {
7433 char buf[128];
7434 int len;
7435 uint64_t val = 0;
7436
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007437 if (i == 0) {
7438 /* pid */
7439 val = getpid();
7440 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7441 } else if (i == 1) {
7442 /* app name */
7443 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
7444 } else if (i == 27) {
7445 /* stack bottom */
7446 val = start_stack;
7447 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
7448 } else {
7449 /* for the rest, there is MasterCard */
7450 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01007451 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00007452
Alexander Graf480b8e72011-11-02 20:23:25 +01007453 len = strlen(buf);
7454 if (write(fd, buf, len) != len) {
7455 return -1;
7456 }
7457 }
7458
7459 return 0;
7460}
7461
Alexander Graf257450e2011-11-02 20:23:26 +01007462static int open_self_auxv(void *cpu_env, int fd)
7463{
Andreas Färber0429a972013-08-26 18:14:44 +02007464 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
7465 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01007466 abi_ulong auxv = ts->info->saved_auxv;
7467 abi_ulong len = ts->info->auxv_len;
7468 char *ptr;
7469
7470 /*
7471 * Auxiliary vector is stored in target process stack.
7472 * read in whole auxv vector and copy it to file
7473 */
7474 ptr = lock_user(VERIFY_READ, auxv, len, 0);
7475 if (ptr != NULL) {
7476 while (len > 0) {
7477 ssize_t r;
7478 r = write(fd, ptr, len);
7479 if (r <= 0) {
7480 break;
7481 }
7482 len -= r;
7483 ptr += r;
7484 }
7485 lseek(fd, 0, SEEK_SET);
7486 unlock_user(ptr, auxv, len);
7487 }
7488
7489 return 0;
7490}
7491
Andreas Schwab463d8e72013-07-02 14:04:12 +01007492static int is_proc_myself(const char *filename, const char *entry)
7493{
7494 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
7495 filename += strlen("/proc/");
7496 if (!strncmp(filename, "self/", strlen("self/"))) {
7497 filename += strlen("self/");
7498 } else if (*filename >= '1' && *filename <= '9') {
7499 char myself[80];
7500 snprintf(myself, sizeof(myself), "%d/", getpid());
7501 if (!strncmp(filename, myself, strlen(myself))) {
7502 filename += strlen(myself);
7503 } else {
7504 return 0;
7505 }
7506 } else {
7507 return 0;
7508 }
7509 if (!strcmp(filename, entry)) {
7510 return 1;
7511 }
7512 }
7513 return 0;
7514}
7515
Laurent Vivierde6b9932013-08-30 01:46:40 +02007516#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7517static int is_proc(const char *filename, const char *entry)
7518{
7519 return strcmp(filename, entry) == 0;
7520}
7521
7522static int open_net_route(void *cpu_env, int fd)
7523{
7524 FILE *fp;
7525 char *line = NULL;
7526 size_t len = 0;
7527 ssize_t read;
7528
7529 fp = fopen("/proc/net/route", "r");
7530 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007531 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02007532 }
7533
7534 /* read header */
7535
7536 read = getline(&line, &len, fp);
7537 dprintf(fd, "%s", line);
7538
7539 /* read routes */
7540
7541 while ((read = getline(&line, &len, fp)) != -1) {
7542 char iface[16];
7543 uint32_t dest, gw, mask;
7544 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
7545 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7546 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
7547 &mask, &mtu, &window, &irtt);
7548 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
7549 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
7550 metric, tswap32(mask), mtu, window, irtt);
7551 }
7552
7553 free(line);
7554 fclose(fp);
7555
7556 return 0;
7557}
7558#endif
7559
Riku Voipio0b2effd2014-08-06 10:36:37 +03007560static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01007561{
7562 struct fake_open {
7563 const char *filename;
7564 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02007565 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01007566 };
7567 const struct fake_open *fake_open;
7568 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007569 { "maps", open_self_maps, is_proc_myself },
7570 { "stat", open_self_stat, is_proc_myself },
7571 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02007572 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02007573#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
7574 { "/proc/net/route", open_net_route, is_proc },
7575#endif
7576 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01007577 };
7578
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007579 if (is_proc_myself(pathname, "exe")) {
7580 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007581 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03007582 }
7583
Alexander Graf3be14d02011-11-02 20:23:23 +01007584 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02007585 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01007586 break;
7587 }
7588 }
7589
7590 if (fake_open->filename) {
7591 const char *tmpdir;
7592 char filename[PATH_MAX];
7593 int fd, r;
7594
7595 /* create temporary file to map stat to */
7596 tmpdir = getenv("TMPDIR");
7597 if (!tmpdir)
7598 tmpdir = "/tmp";
7599 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
7600 fd = mkstemp(filename);
7601 if (fd < 0) {
7602 return fd;
7603 }
7604 unlink(filename);
7605
7606 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007607 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01007608 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01007609 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01007610 return r;
7611 }
7612 lseek(fd, 0, SEEK_SET);
7613
7614 return fd;
7615 }
7616
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01007617 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01007618}
7619
Alexander Grafaecc8862014-11-10 21:33:03 +01007620#define TIMER_MAGIC 0x0caf0000
7621#define TIMER_MAGIC_MASK 0xffff0000
7622
7623/* Convert QEMU provided timer ID back to internal 16bit index format */
7624static target_timer_t get_timer_id(abi_long arg)
7625{
7626 target_timer_t timerid = arg;
7627
7628 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
7629 return -TARGET_EINVAL;
7630 }
7631
7632 timerid &= 0xffff;
7633
7634 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
7635 return -TARGET_EINVAL;
7636 }
7637
7638 return timerid;
7639}
7640
Laurent Vivier562a20b2017-03-01 10:37:48 +01007641static abi_long swap_data_eventfd(void *buf, size_t len)
7642{
7643 uint64_t *counter = buf;
7644 int i;
7645
7646 if (len < sizeof(uint64_t)) {
7647 return -EINVAL;
7648 }
7649
7650 for (i = 0; i < len; i += sizeof(uint64_t)) {
7651 *counter = tswap64(*counter);
7652 counter++;
7653 }
7654
7655 return len;
7656}
7657
7658static TargetFdTrans target_eventfd_trans = {
7659 .host_to_target_data = swap_data_eventfd,
7660 .target_to_host_data = swap_data_eventfd,
7661};
7662
Laurent Vivierc4e316c2017-03-02 01:54:48 +01007663#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
7664 (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
7665 defined(__NR_inotify_init1))
7666static abi_long host_to_target_data_inotify(void *buf, size_t len)
7667{
7668 struct inotify_event *ev;
7669 int i;
7670 uint32_t name_len;
7671
7672 for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
7673 ev = (struct inotify_event *)((char *)buf + i);
7674 name_len = ev->len;
7675
7676 ev->wd = tswap32(ev->wd);
7677 ev->mask = tswap32(ev->mask);
7678 ev->cookie = tswap32(ev->cookie);
7679 ev->len = tswap32(name_len);
7680 }
7681
7682 return len;
7683}
7684
7685static TargetFdTrans target_inotify_trans = {
7686 .host_to_target_data = host_to_target_data_inotify,
7687};
7688#endif
7689
ths0da46a62007-10-20 20:23:07 +00007690/* do_syscall() should always have a single exit point at the end so
7691 that actions, such as logging of syscall results, can be performed.
7692 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00007693abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
7694 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01007695 abi_long arg5, abi_long arg6, abi_long arg7,
7696 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00007697{
Andreas Färber182735e2013-05-29 22:29:20 +02007698 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00007699 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00007700 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00007701 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00007702 void *p;
ths3b46e622007-09-17 08:09:54 +00007703
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01007704#if defined(DEBUG_ERESTARTSYS)
7705 /* Debug-only code for exercising the syscall-restart code paths
7706 * in the per-architecture cpu main loops: restart every syscall
7707 * the guest makes once before letting it through.
7708 */
7709 {
7710 static int flag;
7711
7712 flag = !flag;
7713 if (flag) {
7714 return -TARGET_ERESTARTSYS;
7715 }
7716 }
7717#endif
7718
bellard72f03902003-02-18 23:33:18 +00007719#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00007720 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00007721#endif
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +02007722 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
thsb92c47c2007-11-01 00:07:38 +00007723 if(do_strace)
7724 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
7725
bellard31e31b82003-02-18 22:55:36 +00007726 switch(num) {
7727 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02007728 /* In old applications this may be used to implement _exit(2).
7729 However in threaded applictions it is used for thread termination,
7730 and _exit_group is used for application termination.
7731 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01007732
7733 if (block_signals()) {
7734 ret = -TARGET_ERESTARTSYS;
7735 break;
7736 }
7737
Alex Bennéedd1f6342016-09-30 22:31:01 +01007738 cpu_list_lock();
7739
Andreas Färberbdc44642013-06-24 23:50:24 +02007740 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02007741 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00007742
Andreas Färber9b056fc2013-06-24 23:53:10 +02007743 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02007744 QTAILQ_REMOVE(&cpus, cpu, node);
Alex Bennéedd1f6342016-09-30 22:31:01 +01007745
Andreas Färber9b056fc2013-06-24 23:53:10 +02007746 cpu_list_unlock();
Alex Bennéedd1f6342016-09-30 22:31:01 +01007747
Andreas Färber0429a972013-08-26 18:14:44 +02007748 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02007749 if (ts->child_tidptr) {
7750 put_user_u32(0, ts->child_tidptr);
7751 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
7752 NULL, NULL, 0);
7753 }
Andreas Färbera2247f82013-06-09 19:47:04 +02007754 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02007755 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02007756 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04007757 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02007758 pthread_exit(NULL);
7759 }
Alex Bennéedd1f6342016-09-30 22:31:01 +01007760
7761 cpu_list_unlock();
Juan Quintela9788c9c2009-07-27 16:13:02 +02007762#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00007763 _mcleanup();
7764#endif
bellarde9009672005-04-26 20:42:36 +00007765 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00007766 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00007767 ret = 0; /* avoid warning */
7768 break;
7769 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00007770 if (arg3 == 0)
7771 ret = 0;
7772 else {
7773 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7774 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01007775 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007776 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01007777 fd_trans_host_to_target_data(arg1)) {
7778 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02007779 }
aurel3238d840e2009-01-30 19:48:17 +00007780 unlock_user(p, arg2, ret);
7781 }
bellard31e31b82003-02-18 22:55:36 +00007782 break;
7783 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00007784 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7785 goto efault;
Laurent Vivier04b9bcf2017-03-01 10:37:47 +01007786 if (fd_trans_target_to_host_data(arg1)) {
7787 void *copy = g_malloc(arg3);
7788 memcpy(copy, p, arg3);
7789 ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
7790 if (ret >= 0) {
7791 ret = get_errno(safe_write(arg1, copy, ret));
7792 }
7793 g_free(copy);
7794 } else {
7795 ret = get_errno(safe_write(arg1, p, arg3));
7796 }
pbrook53a59602006-03-25 19:31:22 +00007797 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00007798 break;
Chen Gang704eff62015-08-21 05:37:33 +08007799#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00007800 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00007801 if (!(p = lock_user_string(arg1)))
7802 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007803 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
7804 target_to_host_bitmask(arg2, fcntl_flags_tbl),
7805 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007806 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007807 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007808 break;
Chen Gang704eff62015-08-21 05:37:33 +08007809#endif
ths82424832007-09-24 09:21:55 +00007810 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00007811 if (!(p = lock_user_string(arg2)))
7812 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03007813 ret = get_errno(do_openat(cpu_env, arg1, p,
7814 target_to_host_bitmask(arg3, fcntl_flags_tbl),
7815 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02007816 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00007817 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00007818 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007819#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7820 case TARGET_NR_name_to_handle_at:
7821 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
7822 break;
7823#endif
7824#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
7825 case TARGET_NR_open_by_handle_at:
7826 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007827 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02007828 break;
7829#endif
bellard31e31b82003-02-18 22:55:36 +00007830 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02007831 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00007832 ret = get_errno(close(arg1));
7833 break;
7834 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00007835 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00007836 break;
Chen Gang704eff62015-08-21 05:37:33 +08007837#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00007838 case TARGET_NR_fork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +01007839 ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007840 break;
Chen Gang704eff62015-08-21 05:37:33 +08007841#endif
thse5febef2007-04-01 18:31:35 +00007842#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00007843 case TARGET_NR_waitpid:
7844 {
pbrook53a59602006-03-25 19:31:22 +00007845 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007846 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01007847 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00007848 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00007849 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007850 }
7851 break;
thse5febef2007-04-01 18:31:35 +00007852#endif
pbrookf0cbb612008-05-30 18:20:05 +00007853#ifdef TARGET_NR_waitid
7854 case TARGET_NR_waitid:
7855 {
7856 siginfo_t info;
7857 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01007858 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00007859 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007860 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00007861 goto efault;
7862 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05007863 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00007864 }
7865 }
7866 break;
7867#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007868#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007869 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00007870 if (!(p = lock_user_string(arg1)))
7871 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007872 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007873 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00007874 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007875 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007876#endif
Chen Gang704eff62015-08-21 05:37:33 +08007877#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00007878 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00007879 {
7880 void * p2;
7881 p = lock_user_string(arg1);
7882 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007883 if (!p || !p2)
7884 ret = -TARGET_EFAULT;
7885 else
7886 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007887 unlock_user(p2, arg2, 0);
7888 unlock_user(p, arg1, 0);
7889 }
bellard31e31b82003-02-18 22:55:36 +00007890 break;
Chen Gang704eff62015-08-21 05:37:33 +08007891#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007892#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00007893 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00007894 {
7895 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00007896 if (!arg2 || !arg4)
7897 goto efault;
ths64f0ce42007-09-24 09:25:06 +00007898 p = lock_user_string(arg2);
7899 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007900 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007901 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00007902 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007903 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00007904 unlock_user(p, arg2, 0);
7905 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00007906 }
7907 break;
7908#endif
Chen Gang704eff62015-08-21 05:37:33 +08007909#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00007910 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00007911 if (!(p = lock_user_string(arg1)))
7912 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007913 ret = get_errno(unlink(p));
7914 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007915 break;
Chen Gang704eff62015-08-21 05:37:33 +08007916#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007917#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00007918 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00007919 if (!(p = lock_user_string(arg2)))
7920 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007921 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007922 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00007923 break;
balrogb7d35e62007-12-12 00:40:24 +00007924#endif
bellard31e31b82003-02-18 22:55:36 +00007925 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00007926 {
7927 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00007928 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00007929 abi_ulong gp;
7930 abi_ulong guest_argp;
7931 abi_ulong guest_envp;
7932 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00007933 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007934 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00007935
bellardf7341ff2003-03-30 21:00:25 +00007936 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00007937 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00007938 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007939 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007940 goto efault;
ths03aa1972007-12-02 06:28:08 +00007941 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007942 break;
bellard7854b052003-03-29 17:22:23 +00007943 argc++;
bellard2f619692007-11-16 10:46:05 +00007944 }
bellardf7341ff2003-03-30 21:00:25 +00007945 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00007946 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00007947 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00007948 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00007949 goto efault;
ths03aa1972007-12-02 06:28:08 +00007950 if (!addr)
bellard2f619692007-11-16 10:46:05 +00007951 break;
bellard7854b052003-03-29 17:22:23 +00007952 envc++;
bellard2f619692007-11-16 10:46:05 +00007953 }
bellard7854b052003-03-29 17:22:23 +00007954
Prasad J Panditb936cb52017-03-07 12:51:47 +05307955 argp = g_new0(char *, argc + 1);
7956 envp = g_new0(char *, envc + 1);
bellard7854b052003-03-29 17:22:23 +00007957
pbrookda94d262008-05-30 18:24:00 +00007958 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007959 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007960 if (get_user_ual(addr, gp))
7961 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007962 if (!addr)
7963 break;
bellard2f619692007-11-16 10:46:05 +00007964 if (!(*q = lock_user_string(addr)))
7965 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007966 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007967 }
bellardf7341ff2003-03-30 21:00:25 +00007968 *q = NULL;
7969
pbrookda94d262008-05-30 18:24:00 +00007970 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00007971 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00007972 if (get_user_ual(addr, gp))
7973 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00007974 if (!addr)
7975 break;
bellard2f619692007-11-16 10:46:05 +00007976 if (!(*q = lock_user_string(addr)))
7977 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01007978 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00007979 }
bellardf7341ff2003-03-30 21:00:25 +00007980 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00007981
bellard2f619692007-11-16 10:46:05 +00007982 if (!(p = lock_user_string(arg1)))
7983 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01007984 /* Although execve() is not an interruptible syscall it is
7985 * a special case where we must use the safe_syscall wrapper:
7986 * if we allow a signal to happen before we make the host
7987 * syscall then we will 'lose' it, because at the point of
7988 * execve the process leaves QEMU's control. So we use the
7989 * safe syscall wrapper to ensure that we either take the
7990 * signal as a guest signal, or else it does not happen
7991 * before the execve completes and makes it the other
7992 * program's problem.
7993 */
7994 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00007995 unlock_user(p, arg1, 0);
7996
bellard2f619692007-11-16 10:46:05 +00007997 goto execve_end;
7998
7999 execve_efault:
8000 ret = -TARGET_EFAULT;
8001
8002 execve_end:
pbrook53a59602006-03-25 19:31:22 +00008003 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008004 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008005 if (get_user_ual(addr, gp)
8006 || !addr)
8007 break;
pbrook53a59602006-03-25 19:31:22 +00008008 unlock_user(*q, addr, 0);
8009 }
8010 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00008011 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00008012 if (get_user_ual(addr, gp)
8013 || !addr)
8014 break;
pbrook53a59602006-03-25 19:31:22 +00008015 unlock_user(*q, addr, 0);
8016 }
Prasad J Panditb936cb52017-03-07 12:51:47 +05308017
8018 g_free(argp);
8019 g_free(envp);
bellard7854b052003-03-29 17:22:23 +00008020 }
bellard31e31b82003-02-18 22:55:36 +00008021 break;
8022 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00008023 if (!(p = lock_user_string(arg1)))
8024 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008025 ret = get_errno(chdir(p));
8026 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008027 break;
bellarda315a142005-01-30 22:59:18 +00008028#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00008029 case TARGET_NR_time:
8030 {
pbrook53a59602006-03-25 19:31:22 +00008031 time_t host_time;
8032 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00008033 if (!is_error(ret)
8034 && arg1
8035 && put_user_sal(host_time, arg1))
8036 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008037 }
8038 break;
bellarda315a142005-01-30 22:59:18 +00008039#endif
Chen Gang704eff62015-08-21 05:37:33 +08008040#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00008041 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00008042 if (!(p = lock_user_string(arg1)))
8043 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008044 ret = get_errno(mknod(p, arg2, arg3));
8045 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008046 break;
Chen Gang704eff62015-08-21 05:37:33 +08008047#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008048#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00008049 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00008050 if (!(p = lock_user_string(arg2)))
8051 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008052 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00008053 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00008054 break;
8055#endif
Chen Gang704eff62015-08-21 05:37:33 +08008056#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00008057 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00008058 if (!(p = lock_user_string(arg1)))
8059 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008060 ret = get_errno(chmod(p, arg2));
8061 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008062 break;
Chen Gang704eff62015-08-21 05:37:33 +08008063#endif
bellardebc05482003-09-30 21:08:41 +00008064#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00008065 case TARGET_NR_break:
8066 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008067#endif
8068#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00008069 case TARGET_NR_oldstat:
8070 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008071#endif
bellard31e31b82003-02-18 22:55:36 +00008072 case TARGET_NR_lseek:
8073 ret = get_errno(lseek(arg1, arg2, arg3));
8074 break;
Richard Henderson92317332010-05-03 10:07:53 -07008075#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
8076 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00008077 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07008078 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00008079 ret = get_errno(getpid());
8080 break;
Richard Henderson92317332010-05-03 10:07:53 -07008081#endif
8082#ifdef TARGET_NR_getpid
8083 case TARGET_NR_getpid:
8084 ret = get_errno(getpid());
8085 break;
8086#endif
bellard31e31b82003-02-18 22:55:36 +00008087 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01008088 {
8089 /* need to look at the data field */
8090 void *p2, *p3;
8091
8092 if (arg1) {
8093 p = lock_user_string(arg1);
8094 if (!p) {
8095 goto efault;
8096 }
8097 } else {
8098 p = NULL;
8099 }
8100
8101 p2 = lock_user_string(arg2);
8102 if (!p2) {
8103 if (arg1) {
8104 unlock_user(p, arg1, 0);
8105 }
8106 goto efault;
8107 }
8108
8109 if (arg3) {
8110 p3 = lock_user_string(arg3);
8111 if (!p3) {
8112 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008113 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01008114 }
8115 unlock_user(p2, arg2, 0);
8116 goto efault;
8117 }
8118 } else {
8119 p3 = NULL;
8120 }
8121
8122 /* FIXME - arg5 should be locked, but it isn't clear how to
8123 * do that since it's not guaranteed to be a NULL-terminated
8124 * string.
8125 */
8126 if (!arg5) {
8127 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
8128 } else {
8129 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
8130 }
8131 ret = get_errno(ret);
8132
8133 if (arg1) {
8134 unlock_user(p, arg1, 0);
8135 }
8136 unlock_user(p2, arg2, 0);
8137 if (arg3) {
8138 unlock_user(p3, arg3, 0);
8139 }
8140 }
8141 break;
thse5febef2007-04-01 18:31:35 +00008142#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00008143 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00008144 if (!(p = lock_user_string(arg1)))
8145 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008146 ret = get_errno(umount(p));
8147 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008148 break;
thse5febef2007-04-01 18:31:35 +00008149#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008150#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008151 case TARGET_NR_stime:
8152 {
pbrook53a59602006-03-25 19:31:22 +00008153 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00008154 if (get_user_sal(host_time, arg1))
8155 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008156 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00008157 }
8158 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008159#endif
bellard31e31b82003-02-18 22:55:36 +00008160 case TARGET_NR_ptrace:
8161 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00008162#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008163 case TARGET_NR_alarm:
8164 ret = alarm(arg1);
8165 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008166#endif
bellardebc05482003-09-30 21:08:41 +00008167#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00008168 case TARGET_NR_oldfstat:
8169 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008170#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008171#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008172 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01008173 if (!block_signals()) {
8174 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
8175 }
8176 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00008177 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008178#endif
thse5febef2007-04-01 18:31:35 +00008179#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00008180 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00008181 {
pbrook53a59602006-03-25 19:31:22 +00008182 struct utimbuf tbuf, *host_tbuf;
8183 struct target_utimbuf *target_tbuf;
8184 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008185 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
8186 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008187 tbuf.actime = tswapal(target_tbuf->actime);
8188 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00008189 unlock_user_struct(target_tbuf, arg2, 0);
8190 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00008191 } else {
pbrook53a59602006-03-25 19:31:22 +00008192 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00008193 }
bellard579a97f2007-11-11 14:26:47 +00008194 if (!(p = lock_user_string(arg1)))
8195 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008196 ret = get_errno(utime(p, host_tbuf));
8197 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00008198 }
8199 break;
thse5febef2007-04-01 18:31:35 +00008200#endif
Chen Gang704eff62015-08-21 05:37:33 +08008201#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00008202 case TARGET_NR_utimes:
8203 {
bellard978a66f2004-12-06 22:58:05 +00008204 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00008205 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00008206 if (copy_from_user_timeval(&tv[0], arg2)
8207 || copy_from_user_timeval(&tv[1],
8208 arg2 + sizeof(struct target_timeval)))
8209 goto efault;
bellard978a66f2004-12-06 22:58:05 +00008210 tvp = tv;
8211 } else {
8212 tvp = NULL;
8213 }
bellard579a97f2007-11-11 14:26:47 +00008214 if (!(p = lock_user_string(arg1)))
8215 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008216 ret = get_errno(utimes(p, tvp));
8217 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00008218 }
8219 break;
Chen Gang704eff62015-08-21 05:37:33 +08008220#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008221#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00008222 case TARGET_NR_futimesat:
8223 {
8224 struct timeval *tvp, tv[2];
8225 if (arg3) {
8226 if (copy_from_user_timeval(&tv[0], arg3)
8227 || copy_from_user_timeval(&tv[1],
8228 arg3 + sizeof(struct target_timeval)))
8229 goto efault;
8230 tvp = tv;
8231 } else {
8232 tvp = NULL;
8233 }
8234 if (!(p = lock_user_string(arg2)))
8235 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008236 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00008237 unlock_user(p, arg2, 0);
8238 }
8239 break;
8240#endif
bellardebc05482003-09-30 21:08:41 +00008241#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00008242 case TARGET_NR_stty:
8243 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008244#endif
8245#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00008246 case TARGET_NR_gtty:
8247 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008248#endif
Chen Gang704eff62015-08-21 05:37:33 +08008249#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00008250 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00008251 if (!(p = lock_user_string(arg1)))
8252 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02008253 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00008254 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008255 break;
Chen Gang704eff62015-08-21 05:37:33 +08008256#endif
ths92a34c12007-09-24 09:27:49 +00008257#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
8258 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00008259 if (!(p = lock_user_string(arg2)))
8260 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008261 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008262 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00008263 break;
8264#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008265#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008266 case TARGET_NR_nice:
8267 ret = get_errno(nice(arg1));
8268 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008269#endif
bellardebc05482003-09-30 21:08:41 +00008270#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00008271 case TARGET_NR_ftime:
8272 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008273#endif
bellard31e31b82003-02-18 22:55:36 +00008274 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00008275 sync();
8276 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00008277 break;
Aleksandar Markovic5a03cd02016-10-10 13:23:30 +02008278#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
8279 case TARGET_NR_syncfs:
8280 ret = get_errno(syncfs(arg1));
8281 break;
8282#endif
bellard31e31b82003-02-18 22:55:36 +00008283 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01008284 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00008285 break;
Chen Gang704eff62015-08-21 05:37:33 +08008286#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00008287 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00008288 {
8289 void *p2;
8290 p = lock_user_string(arg1);
8291 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008292 if (!p || !p2)
8293 ret = -TARGET_EFAULT;
8294 else
8295 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008296 unlock_user(p2, arg2, 0);
8297 unlock_user(p, arg1, 0);
8298 }
bellard31e31b82003-02-18 22:55:36 +00008299 break;
Chen Gang704eff62015-08-21 05:37:33 +08008300#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008301#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00008302 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00008303 {
bellard579a97f2007-11-11 14:26:47 +00008304 void *p2;
ths722183f2007-09-24 09:24:37 +00008305 p = lock_user_string(arg2);
8306 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00008307 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008308 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00008309 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008310 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00008311 unlock_user(p2, arg4, 0);
8312 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00008313 }
8314 break;
8315#endif
Chen Gang704eff62015-08-21 05:37:33 +08008316#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00008318 if (!(p = lock_user_string(arg1)))
8319 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008320 ret = get_errno(mkdir(p, arg2));
8321 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008322 break;
Chen Gang704eff62015-08-21 05:37:33 +08008323#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008324#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00008325 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00008326 if (!(p = lock_user_string(arg2)))
8327 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008328 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00008329 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00008330 break;
8331#endif
Chen Gang704eff62015-08-21 05:37:33 +08008332#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00008333 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00008334 if (!(p = lock_user_string(arg1)))
8335 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008336 ret = get_errno(rmdir(p));
8337 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008338 break;
Chen Gang704eff62015-08-21 05:37:33 +08008339#endif
bellard31e31b82003-02-18 22:55:36 +00008340 case TARGET_NR_dup:
8341 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02008342 if (ret >= 0) {
8343 fd_trans_dup(arg1, ret);
8344 }
bellard31e31b82003-02-18 22:55:36 +00008345 break;
Chen Gang704eff62015-08-21 05:37:33 +08008346#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00008347 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07008348 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00008349 break;
Chen Gang704eff62015-08-21 05:37:33 +08008350#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03008351#ifdef TARGET_NR_pipe2
8352 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07008353 ret = do_pipe(cpu_env, arg1,
8354 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03008355 break;
8356#endif
bellard31e31b82003-02-18 22:55:36 +00008357 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00008358 {
pbrook53a59602006-03-25 19:31:22 +00008359 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00008360 struct tms tms;
8361 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00008362 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00008363 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
8364 if (!tmsp)
8365 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008366 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
8367 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
8368 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
8369 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00008370 }
bellardc596ed12003-07-13 17:32:31 +00008371 if (!is_error(ret))
8372 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00008373 }
8374 break;
bellardebc05482003-09-30 21:08:41 +00008375#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00008376 case TARGET_NR_prof:
8377 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008378#endif
thse5febef2007-04-01 18:31:35 +00008379#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00008380 case TARGET_NR_signal:
8381 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008382#endif
bellard31e31b82003-02-18 22:55:36 +00008383 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00008384 if (arg1 == 0) {
8385 ret = get_errno(acct(NULL));
8386 } else {
8387 if (!(p = lock_user_string(arg1)))
8388 goto efault;
8389 ret = get_errno(acct(path(p)));
8390 unlock_user(p, arg1, 0);
8391 }
pbrook24836682006-04-16 14:14:53 +00008392 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10008393#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00008394 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00008395 if (!(p = lock_user_string(arg1)))
8396 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008397 ret = get_errno(umount2(p, arg2));
8398 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008399 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008400#endif
bellardebc05482003-09-30 21:08:41 +00008401#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00008402 case TARGET_NR_lock:
8403 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008404#endif
bellard31e31b82003-02-18 22:55:36 +00008405 case TARGET_NR_ioctl:
8406 ret = do_ioctl(arg1, arg2, arg3);
8407 break;
8408 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00008409 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00008410 break;
bellardebc05482003-09-30 21:08:41 +00008411#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00008412 case TARGET_NR_mpx:
8413 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008414#endif
bellard31e31b82003-02-18 22:55:36 +00008415 case TARGET_NR_setpgid:
8416 ret = get_errno(setpgid(arg1, arg2));
8417 break;
bellardebc05482003-09-30 21:08:41 +00008418#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00008419 case TARGET_NR_ulimit:
8420 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008421#endif
8422#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00008423 case TARGET_NR_oldolduname:
8424 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008425#endif
bellard31e31b82003-02-18 22:55:36 +00008426 case TARGET_NR_umask:
8427 ret = get_errno(umask(arg1));
8428 break;
8429 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00008430 if (!(p = lock_user_string(arg1)))
8431 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008432 ret = get_errno(chroot(p));
8433 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008434 break;
Chen Gang704eff62015-08-21 05:37:33 +08008435#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00008436 case TARGET_NR_ustat:
8437 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08008438#endif
8439#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00008440 case TARGET_NR_dup2:
8441 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02008442 if (ret >= 0) {
8443 fd_trans_dup(arg1, arg2);
8444 }
bellard31e31b82003-02-18 22:55:36 +00008445 break;
Chen Gang704eff62015-08-21 05:37:33 +08008446#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03008447#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
8448 case TARGET_NR_dup3:
8449 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02008450 if (ret >= 0) {
8451 fd_trans_dup(arg1, arg2);
8452 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03008453 break;
8454#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008455#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008456 case TARGET_NR_getppid:
8457 ret = get_errno(getppid());
8458 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008459#endif
Chen Gang704eff62015-08-21 05:37:33 +08008460#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00008461 case TARGET_NR_getpgrp:
8462 ret = get_errno(getpgrp());
8463 break;
Chen Gang704eff62015-08-21 05:37:33 +08008464#endif
bellard31e31b82003-02-18 22:55:36 +00008465 case TARGET_NR_setsid:
8466 ret = get_errno(setsid());
8467 break;
thse5febef2007-04-01 18:31:35 +00008468#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00008469 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00008470 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008471#if defined(TARGET_ALPHA)
8472 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00008473 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00008474 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008475 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8476 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008477 act._sa_handler = old_act->_sa_handler;
8478 target_siginitset(&act.sa_mask, old_act->sa_mask);
8479 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08008480 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00008481 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008482 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00008483 }
8484 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00008485 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008486 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8487 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008488 old_act->_sa_handler = oact._sa_handler;
8489 old_act->sa_mask = oact.sa_mask.sig[0];
8490 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00008491 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00008492 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008493#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00008494 struct target_sigaction act, oact, *pact, *old_act;
8495
8496 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00008497 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8498 goto efault;
bellard106ec872006-06-27 21:08:10 +00008499 act._sa_handler = old_act->_sa_handler;
8500 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
8501 act.sa_flags = old_act->sa_flags;
8502 unlock_user_struct(old_act, arg2, 0);
8503 pact = &act;
8504 } else {
8505 pact = NULL;
8506 }
8507
8508 ret = get_errno(do_sigaction(arg1, pact, &oact));
8509
8510 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00008511 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8512 goto efault;
bellard106ec872006-06-27 21:08:10 +00008513 old_act->_sa_handler = oact._sa_handler;
8514 old_act->sa_flags = oact.sa_flags;
8515 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
8516 old_act->sa_mask.sig[1] = 0;
8517 old_act->sa_mask.sig[2] = 0;
8518 old_act->sa_mask.sig[3] = 0;
8519 unlock_user_struct(old_act, arg3, 1);
8520 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008521#else
8522 struct target_old_sigaction *old_act;
8523 struct target_sigaction act, oact, *pact;
8524 if (arg2) {
8525 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
8526 goto efault;
8527 act._sa_handler = old_act->_sa_handler;
8528 target_siginitset(&act.sa_mask, old_act->sa_mask);
8529 act.sa_flags = old_act->sa_flags;
8530 act.sa_restorer = old_act->sa_restorer;
8531 unlock_user_struct(old_act, arg2, 0);
8532 pact = &act;
8533 } else {
8534 pact = NULL;
8535 }
8536 ret = get_errno(do_sigaction(arg1, pact, &oact));
8537 if (!is_error(ret) && arg3) {
8538 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
8539 goto efault;
8540 old_act->_sa_handler = oact._sa_handler;
8541 old_act->sa_mask = oact.sa_mask.sig[0];
8542 old_act->sa_flags = oact.sa_flags;
8543 old_act->sa_restorer = oact.sa_restorer;
8544 unlock_user_struct(old_act, arg3, 1);
8545 }
ths388bb212007-05-13 13:58:00 +00008546#endif
bellard31e31b82003-02-18 22:55:36 +00008547 }
8548 break;
thse5febef2007-04-01 18:31:35 +00008549#endif
bellard66fb9762003-03-23 01:06:05 +00008550 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00008551 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08008552#if defined(TARGET_ALPHA)
8553 struct target_sigaction act, oact, *pact = 0;
8554 struct target_rt_sigaction *rt_act;
Peter Maydellc8157012016-06-30 14:23:24 +01008555
8556 if (arg4 != sizeof(target_sigset_t)) {
8557 ret = -TARGET_EINVAL;
8558 break;
8559 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08008560 if (arg2) {
8561 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
8562 goto efault;
8563 act._sa_handler = rt_act->_sa_handler;
8564 act.sa_mask = rt_act->sa_mask;
8565 act.sa_flags = rt_act->sa_flags;
8566 act.sa_restorer = arg5;
8567 unlock_user_struct(rt_act, arg2, 0);
8568 pact = &act;
8569 }
8570 ret = get_errno(do_sigaction(arg1, pact, &oact));
8571 if (!is_error(ret) && arg3) {
8572 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
8573 goto efault;
8574 rt_act->_sa_handler = oact._sa_handler;
8575 rt_act->sa_mask = oact.sa_mask;
8576 rt_act->sa_flags = oact.sa_flags;
8577 unlock_user_struct(rt_act, arg3, 1);
8578 }
8579#else
pbrook53a59602006-03-25 19:31:22 +00008580 struct target_sigaction *act;
8581 struct target_sigaction *oact;
8582
Peter Maydellc8157012016-06-30 14:23:24 +01008583 if (arg4 != sizeof(target_sigset_t)) {
8584 ret = -TARGET_EINVAL;
8585 break;
8586 }
bellard579a97f2007-11-11 14:26:47 +00008587 if (arg2) {
8588 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
8589 goto efault;
8590 } else
pbrook53a59602006-03-25 19:31:22 +00008591 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00008592 if (arg3) {
8593 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
8594 ret = -TARGET_EFAULT;
8595 goto rt_sigaction_fail;
8596 }
8597 } else
pbrook53a59602006-03-25 19:31:22 +00008598 oact = NULL;
8599 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00008600 rt_sigaction_fail:
8601 if (act)
pbrook53a59602006-03-25 19:31:22 +00008602 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008603 if (oact)
pbrook53a59602006-03-25 19:31:22 +00008604 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08008605#endif
pbrook53a59602006-03-25 19:31:22 +00008606 }
bellard66fb9762003-03-23 01:06:05 +00008607 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008608#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008609 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00008610 {
8611 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008612 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008613 ret = do_sigprocmask(0, NULL, &cur_set);
8614 if (!ret) {
8615 host_to_target_old_sigset(&target_set, &cur_set);
8616 ret = target_set;
8617 }
bellard66fb9762003-03-23 01:06:05 +00008618 }
8619 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008620#endif
8621#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008622 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00008623 {
8624 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00008625 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008626 /* We only have one word of the new mask so we must read
8627 * the rest of it with do_sigprocmask() and OR in this word.
8628 * We are guaranteed that a do_sigprocmask() that only queries
8629 * the signal mask will not fail.
8630 */
8631 ret = do_sigprocmask(0, NULL, &cur_set);
8632 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00008633 target_to_host_old_sigset(&set, &target_set);
8634 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008635 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
8636 if (!ret) {
8637 host_to_target_old_sigset(&target_set, &oset);
8638 ret = target_set;
8639 }
bellard66fb9762003-03-23 01:06:05 +00008640 }
8641 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008642#endif
thse5febef2007-04-01 18:31:35 +00008643#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00008644 case TARGET_NR_sigprocmask:
8645 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008646#if defined(TARGET_ALPHA)
8647 sigset_t set, oldset;
8648 abi_ulong mask;
8649 int how;
8650
8651 switch (arg1) {
8652 case TARGET_SIG_BLOCK:
8653 how = SIG_BLOCK;
8654 break;
8655 case TARGET_SIG_UNBLOCK:
8656 how = SIG_UNBLOCK;
8657 break;
8658 case TARGET_SIG_SETMASK:
8659 how = SIG_SETMASK;
8660 break;
8661 default:
8662 ret = -TARGET_EINVAL;
8663 goto fail;
8664 }
8665 mask = arg2;
8666 target_to_host_old_sigset(&set, &mask);
8667
Peter Maydell3d3efba2016-05-27 15:51:49 +01008668 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07008669 if (!is_error(ret)) {
8670 host_to_target_old_sigset(&mask, &oldset);
8671 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07008672 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07008673 }
8674#else
bellard66fb9762003-03-23 01:06:05 +00008675 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07008676 int how;
ths3b46e622007-09-17 08:09:54 +00008677
pbrook53a59602006-03-25 19:31:22 +00008678 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07008679 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00008680 case TARGET_SIG_BLOCK:
8681 how = SIG_BLOCK;
8682 break;
8683 case TARGET_SIG_UNBLOCK:
8684 how = SIG_UNBLOCK;
8685 break;
8686 case TARGET_SIG_SETMASK:
8687 how = SIG_SETMASK;
8688 break;
8689 default:
ths0da46a62007-10-20 20:23:07 +00008690 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008691 goto fail;
8692 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008693 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008694 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008695 target_to_host_old_sigset(&set, p);
8696 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008697 set_ptr = &set;
8698 } else {
8699 how = 0;
8700 set_ptr = NULL;
8701 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008702 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008703 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008704 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008705 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008706 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008707 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008708 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07008709#endif
bellard66fb9762003-03-23 01:06:05 +00008710 }
8711 break;
thse5febef2007-04-01 18:31:35 +00008712#endif
bellard66fb9762003-03-23 01:06:05 +00008713 case TARGET_NR_rt_sigprocmask:
8714 {
8715 int how = arg1;
8716 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00008717
Peter Maydellc8157012016-06-30 14:23:24 +01008718 if (arg4 != sizeof(target_sigset_t)) {
8719 ret = -TARGET_EINVAL;
8720 break;
8721 }
8722
pbrook53a59602006-03-25 19:31:22 +00008723 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008724 switch(how) {
8725 case TARGET_SIG_BLOCK:
8726 how = SIG_BLOCK;
8727 break;
8728 case TARGET_SIG_UNBLOCK:
8729 how = SIG_UNBLOCK;
8730 break;
8731 case TARGET_SIG_SETMASK:
8732 how = SIG_SETMASK;
8733 break;
8734 default:
ths0da46a62007-10-20 20:23:07 +00008735 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00008736 goto fail;
8737 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008738 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008739 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008740 target_to_host_sigset(&set, p);
8741 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00008742 set_ptr = &set;
8743 } else {
8744 how = 0;
8745 set_ptr = NULL;
8746 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01008747 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00008748 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008749 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008750 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008751 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05008752 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008753 }
8754 }
8755 break;
thse5febef2007-04-01 18:31:35 +00008756#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00008757 case TARGET_NR_sigpending:
8758 {
8759 sigset_t set;
8760 ret = get_errno(sigpending(&set));
8761 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008762 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008764 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008765 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008766 }
8767 }
8768 break;
thse5febef2007-04-01 18:31:35 +00008769#endif
bellard66fb9762003-03-23 01:06:05 +00008770 case TARGET_NR_rt_sigpending:
8771 {
8772 sigset_t set;
Peter Maydellc8157012016-06-30 14:23:24 +01008773
8774 /* Yes, this check is >, not != like most. We follow the kernel's
8775 * logic and it does it like this because it implements
8776 * NR_sigpending through the same code path, and in that case
8777 * the old_sigset_t is smaller in size.
8778 */
8779 if (arg2 > sizeof(target_sigset_t)) {
8780 ret = -TARGET_EINVAL;
8781 break;
8782 }
8783
bellard66fb9762003-03-23 01:06:05 +00008784 ret = get_errno(sigpending(&set));
8785 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05008786 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00008787 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008788 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05008789 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00008790 }
8791 }
8792 break;
thse5febef2007-04-01 18:31:35 +00008793#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00008794 case TARGET_NR_sigsuspend:
8795 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008796 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07008797#if defined(TARGET_ALPHA)
8798 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008799 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008800#else
Anthony Liguoric227f092009-10-01 16:12:16 -05008801 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008802 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008803 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008804 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07008805#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01008806 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8807 SIGSET_T_SIZE));
8808 if (ret != -TARGET_ERESTARTSYS) {
8809 ts->in_sigsuspend = 1;
8810 }
bellard66fb9762003-03-23 01:06:05 +00008811 }
8812 break;
thse5febef2007-04-01 18:31:35 +00008813#endif
bellard66fb9762003-03-23 01:06:05 +00008814 case TARGET_NR_rt_sigsuspend:
8815 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01008816 TaskState *ts = cpu->opaque;
Peter Maydellc8157012016-06-30 14:23:24 +01008817
8818 if (arg2 != sizeof(target_sigset_t)) {
8819 ret = -TARGET_EINVAL;
8820 break;
8821 }
Anthony Liguoric227f092009-10-01 16:12:16 -05008822 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008823 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01008824 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00008825 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01008826 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
8827 SIGSET_T_SIZE));
8828 if (ret != -TARGET_ERESTARTSYS) {
8829 ts->in_sigsuspend = 1;
8830 }
bellard66fb9762003-03-23 01:06:05 +00008831 }
8832 break;
8833 case TARGET_NR_rt_sigtimedwait:
8834 {
bellard66fb9762003-03-23 01:06:05 +00008835 sigset_t set;
8836 struct timespec uts, *puts;
8837 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00008838
Peter Maydellc8157012016-06-30 14:23:24 +01008839 if (arg4 != sizeof(target_sigset_t)) {
8840 ret = -TARGET_EINVAL;
8841 break;
8842 }
8843
Anthony Liguoric227f092009-10-01 16:12:16 -05008844 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00008845 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008846 target_to_host_sigset(&set, p);
8847 unlock_user(p, arg1, 0);
8848 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00008849 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00008850 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00008851 } else {
8852 puts = NULL;
8853 }
Peter Maydellb3f82332016-06-06 19:58:08 +01008854 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
8855 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01008856 if (!is_error(ret)) {
8857 if (arg2) {
8858 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
8859 0);
8860 if (!p) {
8861 goto efault;
8862 }
8863 host_to_target_siginfo(p, &uinfo);
8864 unlock_user(p, arg2, sizeof(target_siginfo_t));
8865 }
8866 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00008867 }
8868 }
8869 break;
8870 case TARGET_NR_rt_sigqueueinfo:
8871 {
8872 siginfo_t uinfo;
Peter Maydell4debae62016-06-20 15:50:36 +01008873
8874 p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
8875 if (!p) {
bellard579a97f2007-11-11 14:26:47 +00008876 goto efault;
Peter Maydell4debae62016-06-20 15:50:36 +01008877 }
pbrook53a59602006-03-25 19:31:22 +00008878 target_to_host_siginfo(&uinfo, p);
8879 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00008880 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
8881 }
8882 break;
thse5febef2007-04-01 18:31:35 +00008883#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00008884 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008885 if (block_signals()) {
8886 ret = -TARGET_ERESTARTSYS;
8887 } else {
8888 ret = do_sigreturn(cpu_env);
8889 }
bellard66fb9762003-03-23 01:06:05 +00008890 break;
thse5febef2007-04-01 18:31:35 +00008891#endif
bellard66fb9762003-03-23 01:06:05 +00008892 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01008893 if (block_signals()) {
8894 ret = -TARGET_ERESTARTSYS;
8895 } else {
8896 ret = do_rt_sigreturn(cpu_env);
8897 }
bellard66fb9762003-03-23 01:06:05 +00008898 break;
bellard31e31b82003-02-18 22:55:36 +00008899 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00008900 if (!(p = lock_user_string(arg1)))
8901 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008902 ret = get_errno(sethostname(p, arg2));
8903 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008904 break;
8905 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00008906 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008907 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008908 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008909 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00008910 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
8911 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008912 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
8913 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008914 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00008915 ret = get_errno(setrlimit(resource, &rlim));
8916 }
8917 break;
bellard31e31b82003-02-18 22:55:36 +00008918 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00008919 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008920 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00008921 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00008922 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00008923
bellard9de5e442003-03-23 16:49:39 +00008924 ret = get_errno(getrlimit(resource, &rlim));
8925 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008926 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8927 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008928 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8929 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008930 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00008931 }
8932 }
8933 break;
bellard31e31b82003-02-18 22:55:36 +00008934 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00008935 {
8936 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00008937 ret = get_errno(getrusage(arg1, &rusage));
8938 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02008939 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00008940 }
8941 }
8942 break;
bellard31e31b82003-02-18 22:55:36 +00008943 case TARGET_NR_gettimeofday:
8944 {
bellard31e31b82003-02-18 22:55:36 +00008945 struct timeval tv;
8946 ret = get_errno(gettimeofday(&tv, NULL));
8947 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00008948 if (copy_to_user_timeval(arg1, &tv))
8949 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008950 }
8951 }
8952 break;
8953 case TARGET_NR_settimeofday:
8954 {
Paul Burtonb67d8032014-06-22 11:25:41 +01008955 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01008956 struct timezone tz, *ptz = NULL;
8957
Paul Burtonb67d8032014-06-22 11:25:41 +01008958 if (arg1) {
8959 if (copy_from_user_timeval(&tv, arg1)) {
8960 goto efault;
8961 }
8962 ptv = &tv;
8963 }
Paul Burtonef4467e2014-06-22 11:25:40 +01008964
8965 if (arg2) {
8966 if (copy_from_user_timezone(&tz, arg2)) {
8967 goto efault;
8968 }
8969 ptz = &tz;
8970 }
8971
Paul Burtonb67d8032014-06-22 11:25:41 +01008972 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00008973 }
8974 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008975#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00008976 case TARGET_NR_select:
Laurent Vivier5457dc92016-07-08 01:17:27 +02008977#if defined(TARGET_WANT_NI_OLD_SELECT)
8978 /* some architectures used to have old_select here
8979 * but now ENOSYS it.
8980 */
8981 ret = -TARGET_ENOSYS;
8982#elif defined(TARGET_WANT_OLD_SYS_SELECT)
8983 ret = do_old_select(arg1);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008984#else
Laurent Vivier5457dc92016-07-08 01:17:27 +02008985 ret = do_select(arg1, arg2, arg3, arg4, arg5);
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008986#endif
bellardf2674e32003-07-09 12:26:09 +00008987 break;
bellard048f6b42005-11-26 18:47:20 +00008988#endif
Riku Voipio9e423822010-05-07 12:28:05 +00008989#ifdef TARGET_NR_pselect6
8990 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04008991 {
8992 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
8993 fd_set rfds, wfds, efds;
8994 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
8995 struct timespec ts, *ts_ptr;
8996
8997 /*
8998 * The 6th arg is actually two args smashed together,
8999 * so we cannot use the C library.
9000 */
9001 sigset_t set;
9002 struct {
9003 sigset_t *set;
9004 size_t size;
9005 } sig, *sig_ptr;
9006
9007 abi_ulong arg_sigset, arg_sigsize, *arg7;
9008 target_sigset_t *target_sigset;
9009
9010 n = arg1;
9011 rfd_addr = arg2;
9012 wfd_addr = arg3;
9013 efd_addr = arg4;
9014 ts_addr = arg5;
9015
9016 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
9017 if (ret) {
9018 goto fail;
9019 }
9020 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
9021 if (ret) {
9022 goto fail;
9023 }
9024 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
9025 if (ret) {
9026 goto fail;
9027 }
9028
9029 /*
9030 * This takes a timespec, and not a timeval, so we cannot
9031 * use the do_select() helper ...
9032 */
9033 if (ts_addr) {
9034 if (target_to_host_timespec(&ts, ts_addr)) {
9035 goto efault;
9036 }
9037 ts_ptr = &ts;
9038 } else {
9039 ts_ptr = NULL;
9040 }
9041
9042 /* Extract the two packed args for the sigset */
9043 if (arg6) {
9044 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01009045 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04009046
9047 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
9048 if (!arg7) {
9049 goto efault;
9050 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009051 arg_sigset = tswapal(arg7[0]);
9052 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04009053 unlock_user(arg7, arg6, 0);
9054
9055 if (arg_sigset) {
9056 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01009057 if (arg_sigsize != sizeof(*target_sigset)) {
9058 /* Like the kernel, we enforce correct size sigsets */
9059 ret = -TARGET_EINVAL;
9060 goto fail;
9061 }
Mike Frysinger055e0902011-06-03 17:01:49 -04009062 target_sigset = lock_user(VERIFY_READ, arg_sigset,
9063 sizeof(*target_sigset), 1);
9064 if (!target_sigset) {
9065 goto efault;
9066 }
9067 target_to_host_sigset(&set, target_sigset);
9068 unlock_user(target_sigset, arg_sigset, 0);
9069 } else {
9070 sig.set = NULL;
9071 }
9072 } else {
9073 sig_ptr = NULL;
9074 }
9075
Peter Maydell6df9d382016-05-12 18:47:51 +01009076 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
9077 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04009078
9079 if (!is_error(ret)) {
9080 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
9081 goto efault;
9082 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
9083 goto efault;
9084 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
9085 goto efault;
9086
9087 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
9088 goto efault;
9089 }
9090 }
9091 break;
Riku Voipio9e423822010-05-07 12:28:05 +00009092#endif
Chen Gang704eff62015-08-21 05:37:33 +08009093#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00009094 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00009095 {
9096 void *p2;
9097 p = lock_user_string(arg1);
9098 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009099 if (!p || !p2)
9100 ret = -TARGET_EFAULT;
9101 else
9102 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00009103 unlock_user(p2, arg2, 0);
9104 unlock_user(p, arg1, 0);
9105 }
bellard31e31b82003-02-18 22:55:36 +00009106 break;
Chen Gang704eff62015-08-21 05:37:33 +08009107#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009108#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00009109 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00009110 {
bellard579a97f2007-11-11 14:26:47 +00009111 void *p2;
thsf0b62432007-09-24 09:25:40 +00009112 p = lock_user_string(arg1);
9113 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00009114 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00009115 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00009116 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01009117 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00009118 unlock_user(p2, arg3, 0);
9119 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00009120 }
9121 break;
9122#endif
bellardebc05482003-09-30 21:08:41 +00009123#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00009124 case TARGET_NR_oldlstat:
9125 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009126#endif
Chen Gang704eff62015-08-21 05:37:33 +08009127#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00009128 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00009129 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01009130 void *p2;
pbrook53a59602006-03-25 19:31:22 +00009131 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00009132 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009133 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00009134 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09009135 } else if (!arg3) {
9136 /* Short circuit this for the magic exe check. */
9137 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01009138 } else if (is_proc_myself((const char *)p, "exe")) {
9139 char real[PATH_MAX], *temp;
9140 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09009141 /* Return value is # of bytes that we wrote to the buffer. */
9142 if (temp == NULL) {
9143 ret = get_errno(-1);
9144 } else {
9145 /* Don't worry about sign mismatch as earlier mapping
9146 * logic would have thrown a bad address error. */
9147 ret = MIN(strlen(real), arg3);
9148 /* We cannot NUL terminate the string. */
9149 memcpy(p2, real, ret);
9150 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01009151 } else {
9152 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00009153 }
pbrook53a59602006-03-25 19:31:22 +00009154 unlock_user(p2, arg2, ret);
9155 unlock_user(p, arg1, 0);
9156 }
bellard31e31b82003-02-18 22:55:36 +00009157 break;
Chen Gang704eff62015-08-21 05:37:33 +08009158#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009159#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00009160 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00009161 {
bellard579a97f2007-11-11 14:26:47 +00009162 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00009163 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00009164 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01009165 if (!p || !p2) {
9166 ret = -TARGET_EFAULT;
9167 } else if (is_proc_myself((const char *)p, "exe")) {
9168 char real[PATH_MAX], *temp;
9169 temp = realpath(exec_path, real);
9170 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
9171 snprintf((char *)p2, arg4, "%s", real);
9172 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01009173 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01009174 }
bellard579a97f2007-11-11 14:26:47 +00009175 unlock_user(p2, arg3, ret);
9176 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00009177 }
9178 break;
9179#endif
thse5febef2007-04-01 18:31:35 +00009180#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00009181 case TARGET_NR_uselib:
9182 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009183#endif
9184#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00009185 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00009186 if (!(p = lock_user_string(arg1)))
9187 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009188 ret = get_errno(swapon(p, arg2));
9189 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009190 break;
thse5febef2007-04-01 18:31:35 +00009191#endif
bellard31e31b82003-02-18 22:55:36 +00009192 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00009193 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
9194 /* arg4 must be ignored in all other cases */
9195 p = lock_user_string(arg4);
9196 if (!p) {
9197 goto efault;
9198 }
9199 ret = get_errno(reboot(arg1, arg2, arg3, p));
9200 unlock_user(p, arg4, 0);
9201 } else {
9202 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
9203 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02009204 break;
thse5febef2007-04-01 18:31:35 +00009205#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00009206 case TARGET_NR_readdir:
9207 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009208#endif
9209#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00009210 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01009211#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
9212 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009213 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
9214 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00009215 {
blueswir1992f48a2007-10-14 16:27:31 +00009216 abi_ulong *v;
9217 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00009218 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
9219 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009220 v1 = tswapal(v[0]);
9221 v2 = tswapal(v[1]);
9222 v3 = tswapal(v[2]);
9223 v4 = tswapal(v[3]);
9224 v5 = tswapal(v[4]);
9225 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00009226 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00009227 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00009228 target_to_host_bitmask(v4, mmap_flags_tbl),
9229 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00009230 }
bellard31e31b82003-02-18 22:55:36 +00009231#else
ths5fafdf22007-09-16 21:08:06 +00009232 ret = get_errno(target_mmap(arg1, arg2, arg3,
9233 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00009234 arg5,
9235 arg6));
bellard31e31b82003-02-18 22:55:36 +00009236#endif
bellard6fb883e2003-07-09 17:12:39 +00009237 break;
thse5febef2007-04-01 18:31:35 +00009238#endif
bellarda315a142005-01-30 22:59:18 +00009239#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00009240 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00009241#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00009242#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00009243#endif
ths5fafdf22007-09-16 21:08:06 +00009244 ret = get_errno(target_mmap(arg1, arg2, arg3,
9245 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00009246 arg5,
bellardc573ff62004-01-04 15:51:36 +00009247 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00009248 break;
bellarda315a142005-01-30 22:59:18 +00009249#endif
bellard31e31b82003-02-18 22:55:36 +00009250 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00009251 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009252 break;
bellard9de5e442003-03-23 16:49:39 +00009253 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01009254 {
Andreas Färber0429a972013-08-26 18:14:44 +02009255 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01009256 /* Special hack to detect libc making the stack executable. */
9257 if ((arg3 & PROT_GROWSDOWN)
9258 && arg1 >= ts->info->stack_limit
9259 && arg1 <= ts->info->start_stack) {
9260 arg3 &= ~PROT_GROWSDOWN;
9261 arg2 = arg2 + arg1 - ts->info->stack_limit;
9262 arg1 = ts->info->stack_limit;
9263 }
9264 }
bellard54936002003-05-13 00:25:15 +00009265 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009266 break;
thse5febef2007-04-01 18:31:35 +00009267#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00009268 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00009269 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00009270 break;
thse5febef2007-04-01 18:31:35 +00009271#endif
pbrook53a59602006-03-25 19:31:22 +00009272 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00009273#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00009274 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00009275 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00009276 break;
thse5febef2007-04-01 18:31:35 +00009277#endif
9278#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00009279 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00009280 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009281 break;
thse5febef2007-04-01 18:31:35 +00009282#endif
9283#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00009284 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00009285 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00009286 break;
thse5febef2007-04-01 18:31:35 +00009287#endif
9288#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00009289 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05009290 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00009291 break;
thse5febef2007-04-01 18:31:35 +00009292#endif
9293#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00009294 case TARGET_NR_munlockall:
9295 ret = get_errno(munlockall());
9296 break;
thse5febef2007-04-01 18:31:35 +00009297#endif
bellard31e31b82003-02-18 22:55:36 +00009298 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00009299 if (!(p = lock_user_string(arg1)))
9300 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009301 ret = get_errno(truncate(p, arg2));
9302 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009303 break;
9304 case TARGET_NR_ftruncate:
9305 ret = get_errno(ftruncate(arg1, arg2));
9306 break;
9307 case TARGET_NR_fchmod:
9308 ret = get_errno(fchmod(arg1, arg2));
9309 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009310#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00009311 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00009312 if (!(p = lock_user_string(arg2)))
9313 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009314 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00009315 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00009316 break;
9317#endif
bellard31e31b82003-02-18 22:55:36 +00009318 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07009319 /* Note that negative values are valid for getpriority, so we must
9320 differentiate based on errno settings. */
9321 errno = 0;
9322 ret = getpriority(arg1, arg2);
9323 if (ret == -1 && errno != 0) {
9324 ret = -host_to_target_errno(errno);
9325 break;
9326 }
9327#ifdef TARGET_ALPHA
9328 /* Return value is the unbiased priority. Signal no error. */
9329 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
9330#else
9331 /* Return value is a biased priority to avoid negative numbers. */
9332 ret = 20 - ret;
9333#endif
bellard31e31b82003-02-18 22:55:36 +00009334 break;
9335 case TARGET_NR_setpriority:
9336 ret = get_errno(setpriority(arg1, arg2, arg3));
9337 break;
bellardebc05482003-09-30 21:08:41 +00009338#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00009339 case TARGET_NR_profil:
9340 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009341#endif
bellard31e31b82003-02-18 22:55:36 +00009342 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00009343 if (!(p = lock_user_string(arg1)))
9344 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009345 ret = get_errno(statfs(path(p), &stfs));
9346 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009347 convert_statfs:
9348 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009349 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009350
bellard579a97f2007-11-11 14:26:47 +00009351 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
9352 goto efault;
9353 __put_user(stfs.f_type, &target_stfs->f_type);
9354 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9355 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9356 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9357 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9358 __put_user(stfs.f_files, &target_stfs->f_files);
9359 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9360 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9361 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9362 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009363 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9364 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00009365 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009366 }
9367 break;
9368 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00009369 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00009370 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00009371#ifdef TARGET_NR_statfs64
9372 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00009373 if (!(p = lock_user_string(arg1)))
9374 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009375 ret = get_errno(statfs(path(p), &stfs));
9376 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00009377 convert_statfs64:
9378 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009379 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00009380
bellard579a97f2007-11-11 14:26:47 +00009381 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
9382 goto efault;
9383 __put_user(stfs.f_type, &target_stfs->f_type);
9384 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
9385 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
9386 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
9387 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
9388 __put_user(stfs.f_files, &target_stfs->f_files);
9389 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
9390 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
9391 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
9392 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02009393 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
9394 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00009395 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00009396 }
9397 break;
9398 case TARGET_NR_fstatfs64:
9399 ret = get_errno(fstatfs(arg1, &stfs));
9400 goto convert_statfs64;
9401#endif
bellardebc05482003-09-30 21:08:41 +00009402#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00009403 case TARGET_NR_ioperm:
9404 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009405#endif
thse5febef2007-04-01 18:31:35 +00009406#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00009407 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00009408 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00009409 break;
thse5febef2007-04-01 18:31:35 +00009410#endif
bellard3532fa72006-06-24 15:06:03 +00009411#ifdef TARGET_NR_accept
9412 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00009413 ret = do_accept4(arg1, arg2, arg3, 0);
9414 break;
9415#endif
9416#ifdef TARGET_NR_accept4
9417 case TARGET_NR_accept4:
Peter Maydella94b4982013-02-08 04:35:04 +00009418 ret = do_accept4(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009419 break;
9420#endif
9421#ifdef TARGET_NR_bind
9422 case TARGET_NR_bind:
9423 ret = do_bind(arg1, arg2, arg3);
9424 break;
9425#endif
9426#ifdef TARGET_NR_connect
9427 case TARGET_NR_connect:
9428 ret = do_connect(arg1, arg2, arg3);
9429 break;
9430#endif
9431#ifdef TARGET_NR_getpeername
9432 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00009433 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009434 break;
9435#endif
9436#ifdef TARGET_NR_getsockname
9437 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00009438 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00009439 break;
9440#endif
9441#ifdef TARGET_NR_getsockopt
9442 case TARGET_NR_getsockopt:
9443 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
9444 break;
9445#endif
9446#ifdef TARGET_NR_listen
9447 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00009448 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009449 break;
9450#endif
9451#ifdef TARGET_NR_recv
9452 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00009453 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009454 break;
9455#endif
9456#ifdef TARGET_NR_recvfrom
9457 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00009458 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009459 break;
9460#endif
9461#ifdef TARGET_NR_recvmsg
9462 case TARGET_NR_recvmsg:
9463 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
9464 break;
9465#endif
9466#ifdef TARGET_NR_send
9467 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00009468 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00009469 break;
9470#endif
9471#ifdef TARGET_NR_sendmsg
9472 case TARGET_NR_sendmsg:
9473 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
9474 break;
9475#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00009476#ifdef TARGET_NR_sendmmsg
9477 case TARGET_NR_sendmmsg:
9478 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
9479 break;
9480 case TARGET_NR_recvmmsg:
9481 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
9482 break;
9483#endif
bellard3532fa72006-06-24 15:06:03 +00009484#ifdef TARGET_NR_sendto
9485 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00009486 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00009487 break;
9488#endif
9489#ifdef TARGET_NR_shutdown
9490 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00009491 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00009492 break;
9493#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01009494#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
9495 case TARGET_NR_getrandom:
9496 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9497 if (!p) {
9498 goto efault;
9499 }
9500 ret = get_errno(getrandom(p, arg2, arg3));
9501 unlock_user(p, arg1, ret);
9502 break;
9503#endif
bellard3532fa72006-06-24 15:06:03 +00009504#ifdef TARGET_NR_socket
9505 case TARGET_NR_socket:
9506 ret = do_socket(arg1, arg2, arg3);
9507 break;
9508#endif
9509#ifdef TARGET_NR_socketpair
9510 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00009511 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00009512 break;
9513#endif
9514#ifdef TARGET_NR_setsockopt
9515 case TARGET_NR_setsockopt:
9516 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
9517 break;
9518#endif
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009519#if defined(TARGET_NR_syslog)
bellard31e31b82003-02-18 22:55:36 +00009520 case TARGET_NR_syslog:
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009521 {
9522 int len = arg2;
ths7494b0f2007-02-11 18:26:53 +00009523
Aleksandar Markovicda2c8ad2016-09-22 18:56:58 +02009524 switch (arg1) {
9525 case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */
9526 case TARGET_SYSLOG_ACTION_OPEN: /* Open log */
9527 case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
9528 case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */
9529 case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */
9530 case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
9531 case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
9532 case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
9533 {
9534 ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
9535 }
9536 break;
9537 case TARGET_SYSLOG_ACTION_READ: /* Read from log */
9538 case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
9539 case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
9540 {
9541 ret = -TARGET_EINVAL;
9542 if (len < 0) {
9543 goto fail;
9544 }
9545 ret = 0;
9546 if (len == 0) {
9547 break;
9548 }
9549 p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9550 if (!p) {
9551 ret = -TARGET_EFAULT;
9552 goto fail;
9553 }
9554 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
9555 unlock_user(p, arg2, arg3);
9556 }
9557 break;
9558 default:
9559 ret = -EINVAL;
9560 break;
9561 }
9562 }
9563 break;
9564#endif
bellard31e31b82003-02-18 22:55:36 +00009565 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00009566 {
bellard66fb9762003-03-23 01:06:05 +00009567 struct itimerval value, ovalue, *pvalue;
9568
pbrook53a59602006-03-25 19:31:22 +00009569 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00009570 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00009571 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
9572 || copy_from_user_timeval(&pvalue->it_value,
9573 arg2 + sizeof(struct target_timeval)))
9574 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009575 } else {
9576 pvalue = NULL;
9577 }
9578 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00009579 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00009580 if (copy_to_user_timeval(arg3,
9581 &ovalue.it_interval)
9582 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
9583 &ovalue.it_value))
9584 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009585 }
9586 }
9587 break;
bellard31e31b82003-02-18 22:55:36 +00009588 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00009589 {
bellard66fb9762003-03-23 01:06:05 +00009590 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00009591
bellard66fb9762003-03-23 01:06:05 +00009592 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00009593 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00009594 if (copy_to_user_timeval(arg2,
9595 &value.it_interval)
9596 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
9597 &value.it_value))
9598 goto efault;
bellard66fb9762003-03-23 01:06:05 +00009599 }
9600 }
9601 break;
Chen Gang704eff62015-08-21 05:37:33 +08009602#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00009603 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00009604 if (!(p = lock_user_string(arg1)))
9605 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009606 ret = get_errno(stat(path(p), &st));
9607 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009608 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009609#endif
9610#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00009611 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00009612 if (!(p = lock_user_string(arg1)))
9613 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009614 ret = get_errno(lstat(path(p), &st));
9615 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009616 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08009617#endif
bellard31e31b82003-02-18 22:55:36 +00009618 case TARGET_NR_fstat:
9619 {
9620 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08009621#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00009622 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08009623#endif
bellard31e31b82003-02-18 22:55:36 +00009624 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009625 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00009626
bellard579a97f2007-11-11 14:26:47 +00009627 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
9628 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02009629 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00009630 __put_user(st.st_dev, &target_st->st_dev);
9631 __put_user(st.st_ino, &target_st->st_ino);
9632 __put_user(st.st_mode, &target_st->st_mode);
9633 __put_user(st.st_uid, &target_st->st_uid);
9634 __put_user(st.st_gid, &target_st->st_gid);
9635 __put_user(st.st_nlink, &target_st->st_nlink);
9636 __put_user(st.st_rdev, &target_st->st_rdev);
9637 __put_user(st.st_size, &target_st->st_size);
9638 __put_user(st.st_blksize, &target_st->st_blksize);
9639 __put_user(st.st_blocks, &target_st->st_blocks);
9640 __put_user(st.st_atime, &target_st->target_st_atime);
9641 __put_user(st.st_mtime, &target_st->target_st_mtime);
9642 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00009643 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00009644 }
9645 }
9646 break;
bellardebc05482003-09-30 21:08:41 +00009647#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00009648 case TARGET_NR_olduname:
9649 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009650#endif
9651#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00009652 case TARGET_NR_iopl:
9653 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009654#endif
bellard31e31b82003-02-18 22:55:36 +00009655 case TARGET_NR_vhangup:
9656 ret = get_errno(vhangup());
9657 break;
bellardebc05482003-09-30 21:08:41 +00009658#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00009659 case TARGET_NR_idle:
9660 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009661#endif
bellard42ad6ae2005-01-03 22:48:11 +00009662#ifdef TARGET_NR_syscall
9663 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01009664 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
9665 arg6, arg7, arg8, 0);
9666 break;
bellard42ad6ae2005-01-03 22:48:11 +00009667#endif
bellard31e31b82003-02-18 22:55:36 +00009668 case TARGET_NR_wait4:
9669 {
9670 int status;
blueswir1992f48a2007-10-14 16:27:31 +00009671 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00009672 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00009673 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02009674 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00009675 if (target_rusage)
9676 rusage_ptr = &rusage;
9677 else
9678 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01009679 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00009680 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01009681 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00009682 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00009683 if (put_user_s32(status, status_ptr))
9684 goto efault;
bellard31e31b82003-02-18 22:55:36 +00009685 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02009686 if (target_rusage) {
9687 rusage_err = host_to_target_rusage(target_rusage, &rusage);
9688 if (rusage_err) {
9689 ret = rusage_err;
9690 }
9691 }
bellard31e31b82003-02-18 22:55:36 +00009692 }
9693 }
9694 break;
thse5febef2007-04-01 18:31:35 +00009695#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00009696 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00009697 if (!(p = lock_user_string(arg1)))
9698 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009699 ret = get_errno(swapoff(p));
9700 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009701 break;
thse5febef2007-04-01 18:31:35 +00009702#endif
bellard31e31b82003-02-18 22:55:36 +00009703 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00009704 {
pbrook53a59602006-03-25 19:31:22 +00009705 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00009706 struct sysinfo value;
9707 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00009708 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00009709 {
bellard579a97f2007-11-11 14:26:47 +00009710 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
9711 goto efault;
bellarda5448a72004-06-19 16:59:03 +00009712 __put_user(value.uptime, &target_value->uptime);
9713 __put_user(value.loads[0], &target_value->loads[0]);
9714 __put_user(value.loads[1], &target_value->loads[1]);
9715 __put_user(value.loads[2], &target_value->loads[2]);
9716 __put_user(value.totalram, &target_value->totalram);
9717 __put_user(value.freeram, &target_value->freeram);
9718 __put_user(value.sharedram, &target_value->sharedram);
9719 __put_user(value.bufferram, &target_value->bufferram);
9720 __put_user(value.totalswap, &target_value->totalswap);
9721 __put_user(value.freeswap, &target_value->freeswap);
9722 __put_user(value.procs, &target_value->procs);
9723 __put_user(value.totalhigh, &target_value->totalhigh);
9724 __put_user(value.freehigh, &target_value->freehigh);
9725 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00009726 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00009727 }
9728 }
9729 break;
thse5febef2007-04-01 18:31:35 +00009730#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00009731 case TARGET_NR_ipc:
Peter Maydellee8e7612016-07-11 16:48:11 +01009732 ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
9733 break;
thse5febef2007-04-01 18:31:35 +00009734#endif
aurel32e5289082009-04-18 16:16:12 +00009735#ifdef TARGET_NR_semget
9736 case TARGET_NR_semget:
9737 ret = get_errno(semget(arg1, arg2, arg3));
9738 break;
9739#endif
9740#ifdef TARGET_NR_semop
9741 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00009742 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00009743 break;
9744#endif
9745#ifdef TARGET_NR_semctl
9746 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01009747 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00009748 break;
9749#endif
aurel32eeb438c2008-10-13 21:08:55 +00009750#ifdef TARGET_NR_msgctl
9751 case TARGET_NR_msgctl:
9752 ret = do_msgctl(arg1, arg2, arg3);
9753 break;
9754#endif
9755#ifdef TARGET_NR_msgget
9756 case TARGET_NR_msgget:
9757 ret = get_errno(msgget(arg1, arg2));
9758 break;
9759#endif
9760#ifdef TARGET_NR_msgrcv
9761 case TARGET_NR_msgrcv:
9762 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
9763 break;
9764#endif
9765#ifdef TARGET_NR_msgsnd
9766 case TARGET_NR_msgsnd:
9767 ret = do_msgsnd(arg1, arg2, arg3, arg4);
9768 break;
9769#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03009770#ifdef TARGET_NR_shmget
9771 case TARGET_NR_shmget:
9772 ret = get_errno(shmget(arg1, arg2, arg3));
9773 break;
9774#endif
9775#ifdef TARGET_NR_shmctl
9776 case TARGET_NR_shmctl:
9777 ret = do_shmctl(arg1, arg2, arg3);
9778 break;
9779#endif
9780#ifdef TARGET_NR_shmat
9781 case TARGET_NR_shmat:
Peter Maydellee8e7612016-07-11 16:48:11 +01009782 ret = do_shmat(cpu_env, arg1, arg2, arg3);
Riku Voipio88a8c982009-04-03 10:42:00 +03009783 break;
9784#endif
9785#ifdef TARGET_NR_shmdt
9786 case TARGET_NR_shmdt:
9787 ret = do_shmdt(arg1);
9788 break;
9789#endif
bellard31e31b82003-02-18 22:55:36 +00009790 case TARGET_NR_fsync:
9791 ret = get_errno(fsync(arg1));
9792 break;
bellard31e31b82003-02-18 22:55:36 +00009793 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01009794 /* Linux manages to have three different orderings for its
9795 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
9796 * match the kernel's CONFIG_CLONE_* settings.
9797 * Microblaze is further special in that it uses a sixth
9798 * implicit argument to clone for the TLS pointer.
9799 */
9800#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02009801 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01009802#elif defined(TARGET_CLONE_BACKWARDS)
9803 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
9804#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02009805 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009806#else
Peter Maydell4ce62432013-07-16 18:44:57 +01009807 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00009808#endif
bellard1b6b0292003-03-22 17:31:38 +00009809 break;
bellardec86b0f2003-04-11 00:15:04 +00009810#ifdef __NR_exit_group
9811 /* new thread calls */
9812 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02009813#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00009814 _mcleanup();
9815#endif
bellarde9009672005-04-26 20:42:36 +00009816 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00009817 ret = get_errno(exit_group(arg1));
9818 break;
9819#endif
bellard31e31b82003-02-18 22:55:36 +00009820 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00009821 if (!(p = lock_user_string(arg1)))
9822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009823 ret = get_errno(setdomainname(p, arg2));
9824 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00009825 break;
9826 case TARGET_NR_uname:
9827 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00009828 {
9829 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00009830
bellard579a97f2007-11-11 14:26:47 +00009831 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
9832 goto efault;
bellard29e619b2004-09-13 21:41:04 +00009833 ret = get_errno(sys_uname(buf));
9834 if (!is_error(ret)) {
Peter Maydell332c9782016-07-12 13:02:16 +01009835 /* Overwrite the native machine name with whatever is being
bellard29e619b2004-09-13 21:41:04 +00009836 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01009837 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00009838 /* Allow the user to override the reported release. */
Peter Maydell332c9782016-07-12 13:02:16 +01009839 if (qemu_uname_release && *qemu_uname_release) {
9840 g_strlcpy(buf->release, qemu_uname_release,
9841 sizeof(buf->release));
9842 }
bellard29e619b2004-09-13 21:41:04 +00009843 }
pbrook53a59602006-03-25 19:31:22 +00009844 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00009845 }
bellard31e31b82003-02-18 22:55:36 +00009846 break;
bellard6dbad632003-03-16 18:05:05 +00009847#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00009848 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00009849 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00009850 break;
j_mayer84409dd2007-04-06 08:56:50 +00009851#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00009852 case TARGET_NR_vm86old:
9853 goto unimplemented;
9854 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00009855 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00009856 break;
9857#endif
j_mayer84409dd2007-04-06 08:56:50 +00009858#endif
bellard31e31b82003-02-18 22:55:36 +00009859 case TARGET_NR_adjtimex:
Aleksandar Markovic19f59bc2016-09-22 18:56:50 +02009860 {
9861 struct timex host_buf;
9862
9863 if (target_to_host_timex(&host_buf, arg1) != 0) {
9864 goto efault;
9865 }
9866 ret = get_errno(adjtimex(&host_buf));
9867 if (!is_error(ret)) {
9868 if (host_to_target_timex(arg1, &host_buf) != 0) {
9869 goto efault;
9870 }
9871 }
9872 }
9873 break;
Aleksandar Markovic38860a02016-10-10 13:23:29 +02009874#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
9875 case TARGET_NR_clock_adjtime:
9876 {
9877 struct timex htx, *phtx = &htx;
9878
9879 if (target_to_host_timex(phtx, arg2) != 0) {
9880 goto efault;
9881 }
9882 ret = get_errno(clock_adjtime(arg1, phtx));
9883 if (!is_error(ret) && phtx) {
9884 if (host_to_target_timex(arg2, phtx) != 0) {
9885 goto efault;
9886 }
9887 }
9888 }
9889 break;
9890#endif
thse5febef2007-04-01 18:31:35 +00009891#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00009892 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00009893#endif
bellard31e31b82003-02-18 22:55:36 +00009894 case TARGET_NR_init_module:
9895 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00009896#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00009897 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00009898#endif
bellard31e31b82003-02-18 22:55:36 +00009899 goto unimplemented;
9900 case TARGET_NR_quotactl:
9901 goto unimplemented;
9902 case TARGET_NR_getpgid:
9903 ret = get_errno(getpgid(arg1));
9904 break;
9905 case TARGET_NR_fchdir:
9906 ret = get_errno(fchdir(arg1));
9907 break;
j_mayer84409dd2007-04-06 08:56:50 +00009908#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00009909 case TARGET_NR_bdflush:
9910 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00009911#endif
thse5febef2007-04-01 18:31:35 +00009912#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00009913 case TARGET_NR_sysfs:
9914 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009915#endif
bellard31e31b82003-02-18 22:55:36 +00009916 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00009917 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00009918 break;
thse5febef2007-04-01 18:31:35 +00009919#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00009920 case TARGET_NR_afs_syscall:
9921 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009922#endif
j_mayer7a3148a2007-04-05 07:13:51 +00009923#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00009924 case TARGET_NR__llseek:
9925 {
9926 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00009927#if !defined(__NR_llseek)
Peter Maydell9fea2732016-08-11 18:59:39 +01009928 res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
Peter Maydell0c1592d2011-02-22 13:02:26 +00009929 if (res == -1) {
9930 ret = get_errno(res);
9931 } else {
9932 ret = 0;
9933 }
9934#else
bellard31e31b82003-02-18 22:55:36 +00009935 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00009936#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00009937 if ((ret == 0) && put_user_s64(res, arg4)) {
9938 goto efault;
9939 }
bellard31e31b82003-02-18 22:55:36 +00009940 }
9941 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009942#endif
Chen Gang704eff62015-08-21 05:37:33 +08009943#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00009944 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01009945#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02009946#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00009947 {
pbrook53a59602006-03-25 19:31:22 +00009948 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00009949 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009950 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00009951
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309952 dirp = g_try_malloc(count);
9953 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00009954 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00009955 goto fail;
9956 }
ths3b46e622007-09-17 08:09:54 +00009957
bellard4add45b2003-06-05 01:52:59 +00009958 ret = get_errno(sys_getdents(arg1, dirp, count));
9959 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00009960 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00009961 struct target_dirent *tde;
9962 int len = ret;
9963 int reclen, treclen;
9964 int count1, tnamelen;
9965
9966 count1 = 0;
9967 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00009968 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9969 goto efault;
bellard4add45b2003-06-05 01:52:59 +00009970 tde = target_dirp;
9971 while (len > 0) {
9972 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009973 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
9974 assert(tnamelen >= 0);
9975 treclen = tnamelen + offsetof(struct target_dirent, d_name);
9976 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00009977 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02009978 tde->d_ino = tswapal(de->d_ino);
9979 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04009980 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00009981 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00009982 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00009983 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00009984 count1 += treclen;
9985 }
9986 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00009987 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00009988 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05309989 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00009990 }
9991#else
bellard31e31b82003-02-18 22:55:36 +00009992 {
aurel326556a832008-10-13 21:08:17 +00009993 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00009994 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00009995
bellard579a97f2007-11-11 14:26:47 +00009996 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
9997 goto efault;
bellard72f03902003-02-18 23:33:18 +00009998 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00009999 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010000 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +000010001 int len = ret;
10002 int reclen;
10003 de = dirp;
10004 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010005 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +000010006 if (reclen > len)
10007 break;
bellard8083a3e2003-03-24 23:12:16 +000010008 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +000010009 tswapls(&de->d_ino);
10010 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010011 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +000010012 len -= reclen;
10013 }
10014 }
pbrook53a59602006-03-25 19:31:22 +000010015 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +000010016 }
bellard4add45b2003-06-05 01:52:59 +000010017#endif
Peter Maydell3307e232013-06-12 16:20:21 +010010018#else
10019 /* Implement getdents in terms of getdents64 */
10020 {
10021 struct linux_dirent64 *dirp;
10022 abi_long count = arg3;
10023
10024 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
10025 if (!dirp) {
10026 goto efault;
10027 }
10028 ret = get_errno(sys_getdents64(arg1, dirp, count));
10029 if (!is_error(ret)) {
10030 /* Convert the dirent64 structs to target dirent. We do this
10031 * in-place, since we can guarantee that a target_dirent is no
10032 * larger than a dirent64; however this means we have to be
10033 * careful to read everything before writing in the new format.
10034 */
10035 struct linux_dirent64 *de;
10036 struct target_dirent *tde;
10037 int len = ret;
10038 int tlen = 0;
10039
10040 de = dirp;
10041 tde = (struct target_dirent *)dirp;
10042 while (len > 0) {
10043 int namelen, treclen;
10044 int reclen = de->d_reclen;
10045 uint64_t ino = de->d_ino;
10046 int64_t off = de->d_off;
10047 uint8_t type = de->d_type;
10048
10049 namelen = strlen(de->d_name);
10050 treclen = offsetof(struct target_dirent, d_name)
10051 + namelen + 2;
10052 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
10053
10054 memmove(tde->d_name, de->d_name, namelen + 1);
10055 tde->d_ino = tswapal(ino);
10056 tde->d_off = tswapal(off);
10057 tde->d_reclen = tswap16(treclen);
10058 /* The target_dirent type is in what was formerly a padding
10059 * byte at the end of the structure:
10060 */
10061 *(((char *)tde) + treclen - 1) = type;
10062
10063 de = (struct linux_dirent64 *)((char *)de + reclen);
10064 tde = (struct target_dirent *)((char *)tde + treclen);
10065 len -= reclen;
10066 tlen += treclen;
10067 }
10068 ret = tlen;
10069 }
10070 unlock_user(dirp, arg2, ret);
10071 }
10072#endif
bellard31e31b82003-02-18 22:55:36 +000010073 break;
Chen Gang704eff62015-08-21 05:37:33 +080010074#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +000010075#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +000010076 case TARGET_NR_getdents64:
10077 {
aurel326556a832008-10-13 21:08:17 +000010078 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +000010079 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +000010080 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
10081 goto efault;
bellarddab2ed92003-03-22 15:23:14 +000010082 ret = get_errno(sys_getdents64(arg1, dirp, count));
10083 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +000010084 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +000010085 int len = ret;
10086 int reclen;
10087 de = dirp;
10088 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +000010089 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +000010090 if (reclen > len)
10091 break;
bellard8083a3e2003-03-24 23:12:16 +000010092 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +000010093 tswap64s((uint64_t *)&de->d_ino);
10094 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +000010095 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +000010096 len -= reclen;
10097 }
10098 }
pbrook53a59602006-03-25 19:31:22 +000010099 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +000010100 }
10101 break;
bellarda541f292004-04-12 20:39:29 +000010102#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +010010103#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +000010104 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +000010105 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +000010106 break;
thse5febef2007-04-01 18:31:35 +000010107#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -050010108#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
10109# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +000010110 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -050010111# endif
10112# ifdef TARGET_NR_ppoll
10113 case TARGET_NR_ppoll:
10114# endif
bellard9de5e442003-03-23 16:49:39 +000010115 {
pbrook53a59602006-03-25 19:31:22 +000010116 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +000010117 unsigned int nfds = arg2;
bellard9de5e442003-03-23 16:49:39 +000010118 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +000010119 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +000010120
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010121 pfd = NULL;
10122 target_pfd = NULL;
10123 if (nfds) {
Peter Maydellce9c1392016-07-18 16:30:36 +010010124 if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
10125 ret = -TARGET_EINVAL;
10126 break;
10127 }
10128
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010129 target_pfd = lock_user(VERIFY_WRITE, arg1,
10130 sizeof(struct target_pollfd) * nfds, 1);
10131 if (!target_pfd) {
10132 goto efault;
10133 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010134
Laurent Vivier3e24bb32015-10-06 01:20:48 +020010135 pfd = alloca(sizeof(struct pollfd) * nfds);
10136 for (i = 0; i < nfds; i++) {
10137 pfd[i].fd = tswap32(target_pfd[i].fd);
10138 pfd[i].events = tswap16(target_pfd[i].events);
10139 }
bellard9de5e442003-03-23 16:49:39 +000010140 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010141
Peter Maydella6130232016-06-06 19:58:10 +010010142 switch (num) {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010143# ifdef TARGET_NR_ppoll
Peter Maydella6130232016-06-06 19:58:10 +010010144 case TARGET_NR_ppoll:
10145 {
Mike Frysingerd8035d42011-02-07 01:05:51 -050010146 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
10147 target_sigset_t *target_set;
10148 sigset_t _set, *set = &_set;
10149
10150 if (arg3) {
10151 if (target_to_host_timespec(timeout_ts, arg3)) {
10152 unlock_user(target_pfd, arg1, 0);
10153 goto efault;
10154 }
10155 } else {
10156 timeout_ts = NULL;
10157 }
10158
10159 if (arg4) {
Peter Maydellc8157012016-06-30 14:23:24 +010010160 if (arg5 != sizeof(target_sigset_t)) {
10161 unlock_user(target_pfd, arg1, 0);
10162 ret = -TARGET_EINVAL;
10163 break;
10164 }
10165
Mike Frysingerd8035d42011-02-07 01:05:51 -050010166 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
10167 if (!target_set) {
10168 unlock_user(target_pfd, arg1, 0);
10169 goto efault;
10170 }
10171 target_to_host_sigset(set, target_set);
10172 } else {
10173 set = NULL;
10174 }
10175
Peter Maydella6130232016-06-06 19:58:10 +010010176 ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
10177 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -050010178
10179 if (!is_error(ret) && arg3) {
10180 host_to_target_timespec(arg3, timeout_ts);
10181 }
10182 if (arg4) {
10183 unlock_user(target_set, arg4, 0);
10184 }
Peter Maydella6130232016-06-06 19:58:10 +010010185 break;
10186 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010187# endif
Peter Maydella6130232016-06-06 19:58:10 +010010188# ifdef TARGET_NR_poll
10189 case TARGET_NR_poll:
10190 {
10191 struct timespec ts, *pts;
10192
10193 if (arg3 >= 0) {
10194 /* Convert ms to secs, ns */
10195 ts.tv_sec = arg3 / 1000;
10196 ts.tv_nsec = (arg3 % 1000) * 1000000LL;
10197 pts = &ts;
10198 } else {
10199 /* -ve poll() timeout means "infinite" */
10200 pts = NULL;
10201 }
10202 ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
10203 break;
10204 }
10205# endif
10206 default:
10207 g_assert_not_reached();
10208 }
Mike Frysingerd8035d42011-02-07 01:05:51 -050010209
bellard9de5e442003-03-23 16:49:39 +000010210 if (!is_error(ret)) {
10211 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +000010212 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +000010213 }
10214 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +000010215 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +000010216 }
10217 break;
thse5febef2007-04-01 18:31:35 +000010218#endif
bellard31e31b82003-02-18 22:55:36 +000010219 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +000010220 /* NOTE: the flock constant seems to be the same for every
10221 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +010010222 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +000010223 break;
10224 case TARGET_NR_readv:
10225 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010226 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10227 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010228 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010229 unlock_iovec(vec, arg2, arg3, 1);
10230 } else {
10231 ret = -host_to_target_errno(errno);
10232 }
bellard31e31b82003-02-18 22:55:36 +000010233 }
10234 break;
10235 case TARGET_NR_writev:
10236 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010237 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10238 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +010010239 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010240 unlock_iovec(vec, arg2, arg3, 0);
10241 } else {
10242 ret = -host_to_target_errno(errno);
10243 }
bellard31e31b82003-02-18 22:55:36 +000010244 }
10245 break;
Dejan Jovicevic0f263862016-10-11 11:52:46 +020010246#if defined(TARGET_NR_preadv)
10247 case TARGET_NR_preadv:
10248 {
10249 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
10250 if (vec != NULL) {
10251 ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
10252 unlock_iovec(vec, arg2, arg3, 1);
10253 } else {
10254 ret = -host_to_target_errno(errno);
10255 }
10256 }
10257 break;
10258#endif
Dejan Jovicevicf8d00fb2016-10-11 11:52:47 +020010259#if defined(TARGET_NR_pwritev)
10260 case TARGET_NR_pwritev:
10261 {
10262 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10263 if (vec != NULL) {
10264 ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
10265 unlock_iovec(vec, arg2, arg3, 0);
10266 } else {
10267 ret = -host_to_target_errno(errno);
10268 }
10269 }
10270 break;
10271#endif
bellard31e31b82003-02-18 22:55:36 +000010272 case TARGET_NR_getsid:
10273 ret = get_errno(getsid(arg1));
10274 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010275#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +000010276 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +000010277 ret = get_errno(fdatasync(arg1));
10278 break;
j_mayer7a3148a2007-04-05 07:13:51 +000010279#endif
Chen Gang704eff62015-08-21 05:37:33 +080010280#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +000010281 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +000010282 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +000010283 return value. */
ths0da46a62007-10-20 20:23:07 +000010284 ret = -TARGET_ENOTDIR;
10285 break;
Chen Gang704eff62015-08-21 05:37:33 +080010286#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -050010287 case TARGET_NR_sched_getaffinity:
10288 {
10289 unsigned int mask_size;
10290 unsigned long *mask;
10291
10292 /*
10293 * sched_getaffinity needs multiples of ulong, so need to take
10294 * care of mismatches between target ulong and host ulong sizes.
10295 */
10296 if (arg2 & (sizeof(abi_ulong) - 1)) {
10297 ret = -TARGET_EINVAL;
10298 break;
10299 }
10300 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10301
10302 mask = alloca(mask_size);
10303 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
10304
10305 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +010010306 if (ret > arg2) {
10307 /* More data returned than the caller's buffer will fit.
10308 * This only happens if sizeof(abi_long) < sizeof(long)
10309 * and the caller passed us a buffer holding an odd number
10310 * of abi_longs. If the host kernel is actually using the
10311 * extra 4 bytes then fail EINVAL; otherwise we can just
10312 * ignore them and only copy the interesting part.
10313 */
10314 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
10315 if (numcpus > arg2 * 8) {
10316 ret = -TARGET_EINVAL;
10317 break;
10318 }
10319 ret = arg2;
10320 }
10321
Mike McCormackcd18f052011-04-18 14:43:36 +090010322 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -050010323 goto efault;
10324 }
Mike Frysinger737de1d2011-02-07 01:05:55 -050010325 }
10326 }
10327 break;
10328 case TARGET_NR_sched_setaffinity:
10329 {
10330 unsigned int mask_size;
10331 unsigned long *mask;
10332
10333 /*
10334 * sched_setaffinity needs multiples of ulong, so need to take
10335 * care of mismatches between target ulong and host ulong sizes.
10336 */
10337 if (arg2 & (sizeof(abi_ulong) - 1)) {
10338 ret = -TARGET_EINVAL;
10339 break;
10340 }
10341 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
10342
10343 mask = alloca(mask_size);
10344 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
10345 goto efault;
10346 }
10347 memcpy(mask, p, arg2);
10348 unlock_user_struct(p, arg2, 0);
10349
10350 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
10351 }
10352 break;
bellard31e31b82003-02-18 22:55:36 +000010353 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +000010354 {
pbrook53a59602006-03-25 19:31:22 +000010355 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010356 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +000010357
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010358 if (arg2 == 0) {
10359 return -TARGET_EINVAL;
10360 }
bellard579a97f2007-11-11 14:26:47 +000010361 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
10362 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010363 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010364 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +000010365 ret = get_errno(sched_setparam(arg1, &schp));
10366 }
10367 break;
bellard31e31b82003-02-18 22:55:36 +000010368 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +000010369 {
pbrook53a59602006-03-25 19:31:22 +000010370 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010371 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010372
10373 if (arg2 == 0) {
10374 return -TARGET_EINVAL;
10375 }
bellard5cd43932003-03-29 16:54:36 +000010376 ret = get_errno(sched_getparam(arg1, &schp));
10377 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000010378 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
10379 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010380 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010381 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +000010382 }
10383 }
10384 break;
bellard31e31b82003-02-18 22:55:36 +000010385 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +000010386 {
pbrook53a59602006-03-25 19:31:22 +000010387 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +000010388 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -050010389 if (arg3 == 0) {
10390 return -TARGET_EINVAL;
10391 }
bellard579a97f2007-11-11 14:26:47 +000010392 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
10393 goto efault;
bellard5cd43932003-03-29 16:54:36 +000010394 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +000010395 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +000010396 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
10397 }
10398 break;
bellard31e31b82003-02-18 22:55:36 +000010399 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +000010400 ret = get_errno(sched_getscheduler(arg1));
10401 break;
bellard31e31b82003-02-18 22:55:36 +000010402 case TARGET_NR_sched_yield:
10403 ret = get_errno(sched_yield());
10404 break;
10405 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +000010406 ret = get_errno(sched_get_priority_max(arg1));
10407 break;
bellard31e31b82003-02-18 22:55:36 +000010408 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +000010409 ret = get_errno(sched_get_priority_min(arg1));
10410 break;
bellard31e31b82003-02-18 22:55:36 +000010411 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +000010412 {
bellard5cd43932003-03-29 16:54:36 +000010413 struct timespec ts;
10414 ret = get_errno(sched_rr_get_interval(arg1, &ts));
10415 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -050010416 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +000010417 }
10418 }
10419 break;
bellard31e31b82003-02-18 22:55:36 +000010420 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +000010421 {
bellard1b6b0292003-03-22 17:31:38 +000010422 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +000010423 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +010010424 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +000010425 if (is_error(ret) && arg2) {
10426 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +000010427 }
10428 }
10429 break;
thse5febef2007-04-01 18:31:35 +000010430#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +000010431 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +000010432 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010433#endif
10434#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +000010435 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +000010436 goto unimplemented;
thse5febef2007-04-01 18:31:35 +000010437#endif
bellard31e31b82003-02-18 22:55:36 +000010438 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +000010439 switch (arg1) {
10440 case PR_GET_PDEATHSIG:
10441 {
10442 int deathsig;
10443 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
10444 if (!is_error(ret) && arg2
10445 && put_user_ual(deathsig, arg2)) {
10446 goto efault;
thse5574482007-02-11 20:03:13 +000010447 }
Peter Maydell1e6722f2012-02-03 14:48:03 +000010448 break;
10449 }
Peter Maydelldb9526b2012-02-03 14:48:03 +000010450#ifdef PR_GET_NAME
10451 case PR_GET_NAME:
10452 {
10453 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
10454 if (!name) {
10455 goto efault;
10456 }
10457 ret = get_errno(prctl(arg1, (unsigned long)name,
10458 arg3, arg4, arg5));
10459 unlock_user(name, arg2, 16);
10460 break;
10461 }
10462 case PR_SET_NAME:
10463 {
10464 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
10465 if (!name) {
10466 goto efault;
10467 }
10468 ret = get_errno(prctl(arg1, (unsigned long)name,
10469 arg3, arg4, arg5));
10470 unlock_user(name, arg2, 0);
10471 break;
10472 }
10473#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +000010474 default:
10475 /* Most prctl options have no pointer arguments */
10476 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
10477 break;
10478 }
ths39b9aae2007-02-11 18:36:44 +000010479 break;
bellardd2fd1af2007-11-14 18:08:56 +000010480#ifdef TARGET_NR_arch_prctl
10481 case TARGET_NR_arch_prctl:
10482#if defined(TARGET_I386) && !defined(TARGET_ABI32)
10483 ret = do_arch_prctl(cpu_env, arg1, arg2);
10484 break;
10485#else
10486 goto unimplemented;
10487#endif
10488#endif
aurel32f2c7ba12008-03-28 22:32:06 +000010489#ifdef TARGET_NR_pread64
10490 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +000010491 if (regpairs_aligned(cpu_env)) {
10492 arg4 = arg5;
10493 arg5 = arg6;
10494 }
aurel32f2c7ba12008-03-28 22:32:06 +000010495 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
10496 goto efault;
10497 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
10498 unlock_user(p, arg2, ret);
10499 break;
10500 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +000010501 if (regpairs_aligned(cpu_env)) {
10502 arg4 = arg5;
10503 arg5 = arg6;
10504 }
aurel32f2c7ba12008-03-28 22:32:06 +000010505 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
10506 goto efault;
10507 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
10508 unlock_user(p, arg2, 0);
10509 break;
10510#endif
bellard31e31b82003-02-18 22:55:36 +000010511 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +000010512 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
10513 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010514 ret = get_errno(sys_getcwd1(p, arg2));
10515 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +000010516 break;
10517 case TARGET_NR_capget:
10518 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +000010519 {
10520 struct target_user_cap_header *target_header;
10521 struct target_user_cap_data *target_data = NULL;
10522 struct __user_cap_header_struct header;
10523 struct __user_cap_data_struct data[2];
10524 struct __user_cap_data_struct *dataptr = NULL;
10525 int i, target_datalen;
10526 int data_items = 1;
10527
10528 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
10529 goto efault;
10530 }
10531 header.version = tswap32(target_header->version);
10532 header.pid = tswap32(target_header->pid);
10533
Peter Maydellec864872014-03-19 16:07:30 +000010534 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +000010535 /* Version 2 and up takes pointer to two user_data structs */
10536 data_items = 2;
10537 }
10538
10539 target_datalen = sizeof(*target_data) * data_items;
10540
10541 if (arg2) {
10542 if (num == TARGET_NR_capget) {
10543 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
10544 } else {
10545 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
10546 }
10547 if (!target_data) {
10548 unlock_user_struct(target_header, arg1, 0);
10549 goto efault;
10550 }
10551
10552 if (num == TARGET_NR_capset) {
10553 for (i = 0; i < data_items; i++) {
10554 data[i].effective = tswap32(target_data[i].effective);
10555 data[i].permitted = tswap32(target_data[i].permitted);
10556 data[i].inheritable = tswap32(target_data[i].inheritable);
10557 }
10558 }
10559
10560 dataptr = data;
10561 }
10562
10563 if (num == TARGET_NR_capget) {
10564 ret = get_errno(capget(&header, dataptr));
10565 } else {
10566 ret = get_errno(capset(&header, dataptr));
10567 }
10568
10569 /* The kernel always updates version for both capget and capset */
10570 target_header->version = tswap32(header.version);
10571 unlock_user_struct(target_header, arg1, 1);
10572
10573 if (arg2) {
10574 if (num == TARGET_NR_capget) {
10575 for (i = 0; i < data_items; i++) {
10576 target_data[i].effective = tswap32(data[i].effective);
10577 target_data[i].permitted = tswap32(data[i].permitted);
10578 target_data[i].inheritable = tswap32(data[i].inheritable);
10579 }
10580 unlock_user(target_data, arg2, target_datalen);
10581 } else {
10582 unlock_user(target_data, arg2, 0);
10583 }
10584 }
10585 break;
10586 }
bellard31e31b82003-02-18 22:55:36 +000010587 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +010010588 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +000010589 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010590
10591#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +000010592 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010593 {
10594 off_t *offp = NULL;
10595 off_t off;
10596 if (arg3) {
10597 ret = get_user_sal(off, arg3);
10598 if (is_error(ret)) {
10599 break;
10600 }
10601 offp = &off;
10602 }
10603 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10604 if (!is_error(ret) && arg3) {
10605 abi_long ret2 = put_user_sal(off, arg3);
10606 if (is_error(ret2)) {
10607 ret = ret2;
10608 }
10609 }
10610 break;
10611 }
10612#ifdef TARGET_NR_sendfile64
10613 case TARGET_NR_sendfile64:
10614 {
10615 off_t *offp = NULL;
10616 off_t off;
10617 if (arg3) {
10618 ret = get_user_s64(off, arg3);
10619 if (is_error(ret)) {
10620 break;
10621 }
10622 offp = &off;
10623 }
10624 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
10625 if (!is_error(ret) && arg3) {
10626 abi_long ret2 = put_user_s64(off, arg3);
10627 if (is_error(ret2)) {
10628 ret = ret2;
10629 }
10630 }
10631 break;
10632 }
10633#endif
10634#else
10635 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +010010636#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010637 case TARGET_NR_sendfile64:
10638#endif
bellard5cd43932003-03-29 16:54:36 +000010639 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +000010640#endif
10641
bellardebc05482003-09-30 21:08:41 +000010642#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +000010643 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +000010644 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010645#endif
10646#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +000010647 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +000010648 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010649#endif
bellard048f6b42005-11-26 18:47:20 +000010650#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +000010651 case TARGET_NR_vfork:
Laurent Vivier7eddb5d2017-02-16 18:37:07 +010010652 ret = get_errno(do_fork(cpu_env,
10653 CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
pbrookd865bab2008-06-07 22:12:17 +000010654 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +000010655 break;
bellard048f6b42005-11-26 18:47:20 +000010656#endif
bellardebc05482003-09-30 21:08:41 +000010657#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +000010658 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +000010659 {
10660 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +030010661 int resource = target_to_host_resource(arg1);
10662 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +000010663 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +000010664 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +000010665 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
10666 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +090010667 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
10668 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +000010669 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +000010670 }
10671 break;
10672 }
bellardebc05482003-09-30 21:08:41 +000010673#endif
bellarda315a142005-01-30 22:59:18 +000010674#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +000010675 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +000010676 if (!(p = lock_user_string(arg1)))
10677 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010678 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
10679 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +000010680 break;
bellarda315a142005-01-30 22:59:18 +000010681#endif
10682#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +000010683 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +000010684 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +000010685 break;
bellarda315a142005-01-30 22:59:18 +000010686#endif
10687#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +000010688 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +000010689 if (!(p = lock_user_string(arg1)))
10690 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010691 ret = get_errno(stat(path(p), &st));
10692 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010693 if (!is_error(ret))
10694 ret = host_to_target_stat64(cpu_env, arg2, &st);
10695 break;
bellarda315a142005-01-30 22:59:18 +000010696#endif
10697#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +000010698 case TARGET_NR_lstat64:
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(lstat(path(p), &st));
10702 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +000010703 if (!is_error(ret))
10704 ret = host_to_target_stat64(cpu_env, arg2, &st);
10705 break;
bellarda315a142005-01-30 22:59:18 +000010706#endif
10707#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +000010708 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +000010709 ret = get_errno(fstat(arg1, &st));
10710 if (!is_error(ret))
10711 ret = host_to_target_stat64(cpu_env, arg2, &st);
10712 break;
bellardec86b0f2003-04-11 00:15:04 +000010713#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +010010714#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +000010715#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +000010716 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +000010717#endif
10718#ifdef TARGET_NR_newfstatat
10719 case TARGET_NR_newfstatat:
10720#endif
balrog6a24a772008-09-20 02:23:36 +000010721 if (!(p = lock_user_string(arg2)))
10722 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010723 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +000010724 if (!is_error(ret))
10725 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +000010726 break;
bellarda315a142005-01-30 22:59:18 +000010727#endif
Chen Gang704eff62015-08-21 05:37:33 +080010728#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +000010729 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +000010730 if (!(p = lock_user_string(arg1)))
10731 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010732 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
10733 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010734 break;
Chen Gang704eff62015-08-21 05:37:33 +080010735#endif
Riku Voipio0c866a72011-04-18 15:23:06 +030010736#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +000010737 case TARGET_NR_getuid:
10738 ret = get_errno(high2lowuid(getuid()));
10739 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010740#endif
10741#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +000010742 case TARGET_NR_getgid:
10743 ret = get_errno(high2lowgid(getgid()));
10744 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010745#endif
10746#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +000010747 case TARGET_NR_geteuid:
10748 ret = get_errno(high2lowuid(geteuid()));
10749 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010750#endif
10751#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +000010752 case TARGET_NR_getegid:
10753 ret = get_errno(high2lowgid(getegid()));
10754 break;
Riku Voipio0c866a72011-04-18 15:23:06 +030010755#endif
bellard67867302003-11-23 17:05:30 +000010756 case TARGET_NR_setreuid:
10757 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
10758 break;
10759 case TARGET_NR_setregid:
10760 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
10761 break;
10762 case TARGET_NR_getgroups:
10763 {
10764 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010765 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +000010766 gid_t *grouplist;
10767 int i;
10768
10769 grouplist = alloca(gidsetsize * sizeof(gid_t));
10770 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000010771 if (gidsetsize == 0)
10772 break;
bellard67867302003-11-23 17:05:30 +000010773 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +000010774 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +000010775 if (!target_grouplist)
10776 goto efault;
balroga2155fc2008-09-20 02:12:08 +000010777 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +030010778 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010779 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +000010780 }
10781 }
10782 break;
10783 case TARGET_NR_setgroups:
10784 {
10785 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +030010786 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010787 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +000010788 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010789 if (gidsetsize) {
10790 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +000010791 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -050010792 if (!target_grouplist) {
10793 ret = -TARGET_EFAULT;
10794 goto fail;
10795 }
10796 for (i = 0; i < gidsetsize; i++) {
10797 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
10798 }
10799 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +000010800 }
bellard67867302003-11-23 17:05:30 +000010801 ret = get_errno(setgroups(gidsetsize, grouplist));
10802 }
10803 break;
10804 case TARGET_NR_fchown:
10805 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
10806 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010807#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +000010808 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +000010809 if (!(p = lock_user_string(arg2)))
10810 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +010010811 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
10812 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +000010813 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +000010814 break;
10815#endif
bellard67867302003-11-23 17:05:30 +000010816#ifdef TARGET_NR_setresuid
10817 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010818 ret = get_errno(sys_setresuid(low2highuid(arg1),
10819 low2highuid(arg2),
10820 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +000010821 break;
10822#endif
10823#ifdef TARGET_NR_getresuid
10824 case TARGET_NR_getresuid:
10825 {
pbrook53a59602006-03-25 19:31:22 +000010826 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +000010827 ret = get_errno(getresuid(&ruid, &euid, &suid));
10828 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010829 if (put_user_id(high2lowuid(ruid), arg1)
10830 || put_user_id(high2lowuid(euid), arg2)
10831 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +000010832 goto efault;
bellard67867302003-11-23 17:05:30 +000010833 }
10834 }
10835 break;
10836#endif
10837#ifdef TARGET_NR_getresgid
10838 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010839 ret = get_errno(sys_setresgid(low2highgid(arg1),
10840 low2highgid(arg2),
10841 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +000010842 break;
10843#endif
10844#ifdef TARGET_NR_getresgid
10845 case TARGET_NR_getresgid:
10846 {
pbrook53a59602006-03-25 19:31:22 +000010847 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +000010848 ret = get_errno(getresgid(&rgid, &egid, &sgid));
10849 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +000010850 if (put_user_id(high2lowgid(rgid), arg1)
10851 || put_user_id(high2lowgid(egid), arg2)
10852 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +000010853 goto efault;
bellard67867302003-11-23 17:05:30 +000010854 }
10855 }
10856 break;
10857#endif
Chen Gang704eff62015-08-21 05:37:33 +080010858#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +000010859 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +000010860 if (!(p = lock_user_string(arg1)))
10861 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010862 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
10863 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +000010864 break;
Chen Gang704eff62015-08-21 05:37:33 +080010865#endif
bellard67867302003-11-23 17:05:30 +000010866 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010867 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +000010868 break;
10869 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +000010870 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +000010871 break;
10872 case TARGET_NR_setfsuid:
10873 ret = get_errno(setfsuid(arg1));
10874 break;
10875 case TARGET_NR_setfsgid:
10876 ret = get_errno(setfsgid(arg1));
10877 break;
bellard67867302003-11-23 17:05:30 +000010878
bellarda315a142005-01-30 22:59:18 +000010879#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +000010880 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +000010881 if (!(p = lock_user_string(arg1)))
10882 goto efault;
pbrook53a59602006-03-25 19:31:22 +000010883 ret = get_errno(lchown(p, arg2, arg3));
10884 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000010885 break;
bellarda315a142005-01-30 22:59:18 +000010886#endif
10887#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +000010888 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +000010889 ret = get_errno(getuid());
10890 break;
bellarda315a142005-01-30 22:59:18 +000010891#endif
aurel3264b4d282008-11-14 17:20:15 +000010892
10893#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
10894 /* Alpha specific */
10895 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010896 {
10897 uid_t euid;
10898 euid=geteuid();
10899 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
10900 }
aurel3264b4d282008-11-14 17:20:15 +000010901 ret = get_errno(getuid());
10902 break;
10903#endif
10904#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
10905 /* Alpha specific */
10906 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010907 {
10908 uid_t egid;
10909 egid=getegid();
10910 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
10911 }
aurel3264b4d282008-11-14 17:20:15 +000010912 ret = get_errno(getgid());
10913 break;
10914#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -080010915#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
10916 /* Alpha specific */
10917 case TARGET_NR_osf_getsysinfo:
10918 ret = -TARGET_EOPNOTSUPP;
10919 switch (arg1) {
10920 case TARGET_GSI_IEEE_FP_CONTROL:
10921 {
10922 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
10923
10924 /* Copied from linux ieee_fpcr_to_swcr. */
10925 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
10926 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
10927 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
10928 | SWCR_TRAP_ENABLE_DZE
10929 | SWCR_TRAP_ENABLE_OVF);
10930 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
10931 | SWCR_TRAP_ENABLE_INE);
10932 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
10933 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
10934
10935 if (put_user_u64 (swcr, arg2))
10936 goto efault;
10937 ret = 0;
10938 }
10939 break;
10940
10941 /* case GSI_IEEE_STATE_AT_SIGNAL:
10942 -- Not implemented in linux kernel.
10943 case GSI_UACPROC:
10944 -- Retrieves current unaligned access state; not much used.
10945 case GSI_PROC_TYPE:
10946 -- Retrieves implver information; surely not used.
10947 case GSI_GET_HWRPB:
10948 -- Grabs a copy of the HWRPB; surely not used.
10949 */
10950 }
10951 break;
10952#endif
10953#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
10954 /* Alpha specific */
10955 case TARGET_NR_osf_setsysinfo:
10956 ret = -TARGET_EOPNOTSUPP;
10957 switch (arg1) {
10958 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -080010959 {
10960 uint64_t swcr, fpcr, orig_fpcr;
10961
Richard Henderson6e06d512012-06-01 09:08:21 -070010962 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -080010963 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -070010964 }
10965 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010966 fpcr = orig_fpcr & FPCR_DYN_MASK;
10967
10968 /* Copied from linux ieee_swcr_to_fpcr. */
10969 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
10970 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
10971 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
10972 | SWCR_TRAP_ENABLE_DZE
10973 | SWCR_TRAP_ENABLE_OVF)) << 48;
10974 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
10975 | SWCR_TRAP_ENABLE_INE)) << 57;
10976 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
10977 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
10978
Richard Henderson6e06d512012-06-01 09:08:21 -070010979 cpu_alpha_store_fpcr(cpu_env, fpcr);
10980 ret = 0;
10981 }
10982 break;
10983
10984 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
10985 {
10986 uint64_t exc, fpcr, orig_fpcr;
10987 int si_code;
10988
10989 if (get_user_u64(exc, arg2)) {
10990 goto efault;
10991 }
10992
10993 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
10994
10995 /* We only add to the exception status here. */
10996 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
10997
10998 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -080010999 ret = 0;
11000
Richard Henderson6e06d512012-06-01 09:08:21 -070011001 /* Old exceptions are not signaled. */
11002 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011003
Richard Henderson6e06d512012-06-01 09:08:21 -070011004 /* If any exceptions set by this call,
11005 and are unmasked, send a signal. */
11006 si_code = 0;
11007 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
11008 si_code = TARGET_FPE_FLTRES;
11009 }
11010 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
11011 si_code = TARGET_FPE_FLTUND;
11012 }
11013 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
11014 si_code = TARGET_FPE_FLTOVF;
11015 }
11016 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
11017 si_code = TARGET_FPE_FLTDIV;
11018 }
11019 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
11020 si_code = TARGET_FPE_FLTINV;
11021 }
11022 if (si_code != 0) {
11023 target_siginfo_t info;
11024 info.si_signo = SIGFPE;
11025 info.si_errno = 0;
11026 info.si_code = si_code;
11027 info._sifields._sigfault._addr
11028 = ((CPUArchState *)cpu_env)->pc;
Peter Maydell9d2803f2016-07-28 16:44:46 +010011029 queue_signal((CPUArchState *)cpu_env, info.si_signo,
11030 QEMU_SI_FAULT, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -080011031 }
11032 }
11033 break;
11034
11035 /* case SSI_NVPAIRS:
11036 -- Used with SSIN_UACPROC to enable unaligned accesses.
11037 case SSI_IEEE_STATE_AT_SIGNAL:
11038 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
11039 -- Not implemented in linux kernel
11040 */
11041 }
11042 break;
11043#endif
11044#ifdef TARGET_NR_osf_sigprocmask
11045 /* Alpha specific. */
11046 case TARGET_NR_osf_sigprocmask:
11047 {
11048 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +010011049 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -080011050 sigset_t set, oldset;
11051
11052 switch(arg1) {
11053 case TARGET_SIG_BLOCK:
11054 how = SIG_BLOCK;
11055 break;
11056 case TARGET_SIG_UNBLOCK:
11057 how = SIG_UNBLOCK;
11058 break;
11059 case TARGET_SIG_SETMASK:
11060 how = SIG_SETMASK;
11061 break;
11062 default:
11063 ret = -TARGET_EINVAL;
11064 goto fail;
11065 }
11066 mask = arg2;
11067 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +010011068 ret = do_sigprocmask(how, &set, &oldset);
11069 if (!ret) {
11070 host_to_target_old_sigset(&mask, &oldset);
11071 ret = mask;
11072 }
Richard Hendersonba0e2762009-12-09 15:56:29 -080011073 }
11074 break;
11075#endif
aurel3264b4d282008-11-14 17:20:15 +000011076
bellarda315a142005-01-30 22:59:18 +000011077#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +000011078 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +000011079 ret = get_errno(getgid());
11080 break;
bellarda315a142005-01-30 22:59:18 +000011081#endif
11082#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +000011083 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +000011084 ret = get_errno(geteuid());
11085 break;
bellarda315a142005-01-30 22:59:18 +000011086#endif
11087#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +000011088 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +000011089 ret = get_errno(getegid());
11090 break;
bellarda315a142005-01-30 22:59:18 +000011091#endif
11092#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +000011093 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +000011094 ret = get_errno(setreuid(arg1, arg2));
11095 break;
bellarda315a142005-01-30 22:59:18 +000011096#endif
11097#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +000011098 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +000011099 ret = get_errno(setregid(arg1, arg2));
11100 break;
bellarda315a142005-01-30 22:59:18 +000011101#endif
11102#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +000011103 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +000011104 {
11105 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011106 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011107 gid_t *grouplist;
11108 int i;
11109
11110 grouplist = alloca(gidsetsize * sizeof(gid_t));
11111 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +000011112 if (gidsetsize == 0)
11113 break;
bellard99c475a2005-01-31 20:45:13 +000011114 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +000011115 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
11116 if (!target_grouplist) {
11117 ret = -TARGET_EFAULT;
11118 goto fail;
11119 }
balroga2155fc2008-09-20 02:12:08 +000011120 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +000011121 target_grouplist[i] = tswap32(grouplist[i]);
11122 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +000011123 }
11124 }
11125 break;
bellarda315a142005-01-30 22:59:18 +000011126#endif
11127#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +000011128 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +000011129 {
11130 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +000011131 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +000011132 gid_t *grouplist;
11133 int i;
ths3b46e622007-09-17 08:09:54 +000011134
bellard99c475a2005-01-31 20:45:13 +000011135 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +000011136 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
11137 if (!target_grouplist) {
11138 ret = -TARGET_EFAULT;
11139 goto fail;
11140 }
bellard99c475a2005-01-31 20:45:13 +000011141 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +000011142 grouplist[i] = tswap32(target_grouplist[i]);
11143 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +000011144 ret = get_errno(setgroups(gidsetsize, grouplist));
11145 }
11146 break;
bellarda315a142005-01-30 22:59:18 +000011147#endif
11148#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +000011149 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +000011150 ret = get_errno(fchown(arg1, arg2, arg3));
11151 break;
bellarda315a142005-01-30 22:59:18 +000011152#endif
11153#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +000011154 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011155 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011156 break;
bellarda315a142005-01-30 22:59:18 +000011157#endif
11158#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +000011159 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +000011160 {
pbrook53a59602006-03-25 19:31:22 +000011161 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +000011162 ret = get_errno(getresuid(&ruid, &euid, &suid));
11163 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011164 if (put_user_u32(ruid, arg1)
11165 || put_user_u32(euid, arg2)
11166 || put_user_u32(suid, arg3))
11167 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011168 }
11169 }
11170 break;
bellarda315a142005-01-30 22:59:18 +000011171#endif
11172#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +000011173 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011174 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +000011175 break;
bellarda315a142005-01-30 22:59:18 +000011176#endif
11177#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +000011178 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +000011179 {
pbrook53a59602006-03-25 19:31:22 +000011180 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +000011181 ret = get_errno(getresgid(&rgid, &egid, &sgid));
11182 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +000011183 if (put_user_u32(rgid, arg1)
11184 || put_user_u32(egid, arg2)
11185 || put_user_u32(sgid, arg3))
11186 goto efault;
bellardb03c60f2003-03-23 17:19:56 +000011187 }
11188 }
11189 break;
bellarda315a142005-01-30 22:59:18 +000011190#endif
11191#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +000011192 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +000011193 if (!(p = lock_user_string(arg1)))
11194 goto efault;
pbrook53a59602006-03-25 19:31:22 +000011195 ret = get_errno(chown(p, arg2, arg3));
11196 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +000011197 break;
bellarda315a142005-01-30 22:59:18 +000011198#endif
11199#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +000011200 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011201 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011202 break;
bellarda315a142005-01-30 22:59:18 +000011203#endif
11204#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +000011205 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +000011206 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +000011207 break;
bellarda315a142005-01-30 22:59:18 +000011208#endif
11209#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +000011210 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +000011211 ret = get_errno(setfsuid(arg1));
11212 break;
bellarda315a142005-01-30 22:59:18 +000011213#endif
11214#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000011215 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000011216 ret = get_errno(setfsgid(arg1));
11217 break;
bellarda315a142005-01-30 22:59:18 +000011218#endif
bellard67867302003-11-23 17:05:30 +000011219
bellard31e31b82003-02-18 22:55:36 +000011220 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000011221 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000011222#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000011223 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000011224 {
11225 void *a;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011226 ret = -TARGET_ENOMEM;
11227 a = lock_user(VERIFY_READ, arg1, arg2, 0);
11228 if (!a) {
11229 goto fail;
11230 }
aurel3204bb9ac2008-10-01 21:46:41 +000011231 ret = -TARGET_EFAULT;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011232 p = lock_user_string(arg3);
11233 if (!p) {
aurel3204bb9ac2008-10-01 21:46:41 +000011234 goto mincore_fail;
Franklin \"Snaipe\" Mathieu98a33312017-02-17 08:58:00 +000011235 }
aurel3204bb9ac2008-10-01 21:46:41 +000011236 ret = get_errno(mincore(a, arg2, p));
11237 unlock_user(p, arg3, ret);
11238 mincore_fail:
11239 unlock_user(a, arg1, 0);
11240 }
11241 break;
bellardffa65c32004-01-04 23:57:22 +000011242#endif
aurel32408321b2008-10-01 21:46:32 +000011243#ifdef TARGET_NR_arm_fadvise64_64
11244 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010011245 /* arm_fadvise64_64 looks like fadvise64_64 but
11246 * with different argument order: fd, advice, offset, len
11247 * rather than the usual fd, offset, len, advice.
11248 * Note that offset and len are both 64-bit so appear as
11249 * pairs of 32-bit registers.
11250 */
11251 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
11252 target_offset64(arg5, arg6), arg2);
11253 ret = -host_to_target_errno(ret);
11254 break;
aurel32408321b2008-10-01 21:46:32 +000011255#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011256
11257#if TARGET_ABI_BITS == 32
11258
11259#ifdef TARGET_NR_fadvise64_64
11260 case TARGET_NR_fadvise64_64:
Laurent Vivier43046b52017-03-02 01:11:45 +010011261#if defined(TARGET_PPC)
11262 /* 6 args: fd, advice, offset (high, low), len (high, low) */
11263 ret = arg2;
11264 arg2 = arg3;
11265 arg3 = arg4;
11266 arg4 = arg5;
11267 arg5 = arg6;
11268 arg6 = ret;
11269#else
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011270 /* 6 args: fd, offset (high, low), len (high, low), advice */
11271 if (regpairs_aligned(cpu_env)) {
11272 /* offset is in (3,4), len in (5,6) and advice in 7 */
11273 arg2 = arg3;
11274 arg3 = arg4;
11275 arg4 = arg5;
11276 arg5 = arg6;
11277 arg6 = arg7;
11278 }
Laurent Vivier43046b52017-03-02 01:11:45 +010011279#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011280 ret = -host_to_target_errno(posix_fadvise(arg1,
11281 target_offset64(arg2, arg3),
11282 target_offset64(arg4, arg5),
11283 arg6));
11284 break;
11285#endif
11286
11287#ifdef TARGET_NR_fadvise64
11288 case TARGET_NR_fadvise64:
11289 /* 5 args: fd, offset (high, low), len, advice */
11290 if (regpairs_aligned(cpu_env)) {
11291 /* offset is in (3,4), len in 5 and advice in 6 */
11292 arg2 = arg3;
11293 arg3 = arg4;
11294 arg4 = arg5;
11295 arg5 = arg6;
11296 }
11297 ret = -host_to_target_errno(posix_fadvise(arg1,
11298 target_offset64(arg2, arg3),
11299 arg4, arg5));
11300 break;
11301#endif
11302
11303#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010011304#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000011305#ifdef TARGET_NR_fadvise64_64
11306 case TARGET_NR_fadvise64_64:
11307#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020011308#ifdef TARGET_NR_fadvise64
11309 case TARGET_NR_fadvise64:
11310#endif
11311#ifdef TARGET_S390X
11312 switch (arg4) {
11313 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
11314 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
11315 case 6: arg4 = POSIX_FADV_DONTNEED; break;
11316 case 7: arg4 = POSIX_FADV_NOREUSE; break;
11317 default: break;
11318 }
11319#endif
Peter Maydell977d8242016-05-31 15:45:11 +010011320 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
11321 break;
aurel32408321b2008-10-01 21:46:32 +000011322#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010011323#endif /* end of 64-bit ABI fadvise handling */
11324
bellardffa65c32004-01-04 23:57:22 +000011325#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000011326 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000011327 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080011328 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000011329 This will break MADV_DONTNEED.
11330 This is a hint, so ignoring and returning success is ok. */
11331 ret = get_errno(0);
11332 break;
bellardffa65c32004-01-04 23:57:22 +000011333#endif
blueswir1992f48a2007-10-14 16:27:31 +000011334#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000011335 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000011336 {
thsb1e341e2007-03-20 21:50:52 +000011337 int cmd;
bellard77e46722003-04-29 20:39:06 +000011338 struct flock64 fl;
Peter Maydell213d3e92016-06-13 11:22:05 +010011339 from_flock64_fn *copyfrom = copy_from_user_flock64;
11340 to_flock64_fn *copyto = copy_to_user_flock64;
11341
pbrookce4defa2006-02-09 16:49:55 +000011342#ifdef TARGET_ARM
Peter Maydell213d3e92016-06-13 11:22:05 +010011343 if (((CPUARMState *)cpu_env)->eabi) {
11344 copyfrom = copy_from_user_eabi_flock64;
11345 copyto = copy_to_user_eabi_flock64;
11346 }
pbrookce4defa2006-02-09 16:49:55 +000011347#endif
bellard77e46722003-04-29 20:39:06 +000011348
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011349 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000011350 if (cmd == -TARGET_EINVAL) {
11351 ret = cmd;
11352 break;
11353 }
thsb1e341e2007-03-20 21:50:52 +000011354
bellard60cd49d2003-03-16 22:53:56 +000011355 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000011356 case TARGET_F_GETLK64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011357 ret = copyfrom(&fl, arg3);
11358 if (ret) {
11359 break;
ths58134272007-03-31 18:59:32 +000011360 }
thsb1e341e2007-03-20 21:50:52 +000011361 ret = get_errno(fcntl(arg1, cmd, &fl));
Peter Maydell213d3e92016-06-13 11:22:05 +010011362 if (ret == 0) {
11363 ret = copyto(arg3, &fl);
11364 }
bellard77e46722003-04-29 20:39:06 +000011365 break;
11366
thsb1e341e2007-03-20 21:50:52 +000011367 case TARGET_F_SETLK64:
11368 case TARGET_F_SETLKW64:
Peter Maydell213d3e92016-06-13 11:22:05 +010011369 ret = copyfrom(&fl, arg3);
11370 if (ret) {
11371 break;
pbrookce4defa2006-02-09 16:49:55 +000011372 }
Peter Maydell435da5e2016-06-13 11:22:05 +010011373 ret = get_errno(safe_fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000011374 break;
bellard60cd49d2003-03-16 22:53:56 +000011375 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020011376 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000011377 break;
11378 }
bellard77e46722003-04-29 20:39:06 +000011379 break;
11380 }
bellard60cd49d2003-03-16 22:53:56 +000011381#endif
ths7d600c82006-12-08 01:32:58 +000011382#ifdef TARGET_NR_cacheflush
11383 case TARGET_NR_cacheflush:
11384 /* self-modifying code is handled automatically, so nothing needed */
11385 ret = 0;
11386 break;
11387#endif
bellardebc05482003-09-30 21:08:41 +000011388#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000011389 case TARGET_NR_security:
11390 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000011391#endif
bellardc573ff62004-01-04 15:51:36 +000011392#ifdef TARGET_NR_getpagesize
11393 case TARGET_NR_getpagesize:
11394 ret = TARGET_PAGE_SIZE;
11395 break;
11396#endif
bellard31e31b82003-02-18 22:55:36 +000011397 case TARGET_NR_gettid:
11398 ret = get_errno(gettid());
11399 break;
thse5febef2007-04-01 18:31:35 +000011400#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000011401 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000011402#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030011403 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000011404 arg2 = arg3;
11405 arg3 = arg4;
11406 arg4 = arg5;
11407 }
Lena Djokic77c68502016-11-24 17:08:56 +010011408 ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
aurel322054ac92008-10-13 21:08:07 +000011409#else
11410 ret = get_errno(readahead(arg1, arg2, arg3));
11411#endif
11412 break;
thse5febef2007-04-01 18:31:35 +000011413#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011414#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000011415#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000011416 case TARGET_NR_listxattr:
11417 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000011418 {
11419 void *p, *b = 0;
11420 if (arg2) {
11421 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11422 if (!b) {
11423 ret = -TARGET_EFAULT;
11424 break;
11425 }
11426 }
11427 p = lock_user_string(arg1);
11428 if (p) {
11429 if (num == TARGET_NR_listxattr) {
11430 ret = get_errno(listxattr(p, b, arg3));
11431 } else {
11432 ret = get_errno(llistxattr(p, b, arg3));
11433 }
11434 } else {
11435 ret = -TARGET_EFAULT;
11436 }
11437 unlock_user(p, arg1, 0);
11438 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030011439 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000011440 }
11441 case TARGET_NR_flistxattr:
11442 {
11443 void *b = 0;
11444 if (arg2) {
11445 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
11446 if (!b) {
11447 ret = -TARGET_EFAULT;
11448 break;
11449 }
11450 }
11451 ret = get_errno(flistxattr(arg1, b, arg3));
11452 unlock_user(b, arg2, arg3);
11453 break;
11454 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011455 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011456 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011457 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011458 void *p, *n, *v = 0;
11459 if (arg3) {
11460 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11461 if (!v) {
11462 ret = -TARGET_EFAULT;
11463 break;
11464 }
11465 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011466 p = lock_user_string(arg1);
11467 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011468 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011469 if (num == TARGET_NR_setxattr) {
11470 ret = get_errno(setxattr(p, n, v, arg4, arg5));
11471 } else {
11472 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
11473 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011474 } else {
11475 ret = -TARGET_EFAULT;
11476 }
11477 unlock_user(p, arg1, 0);
11478 unlock_user(n, arg2, 0);
11479 unlock_user(v, arg3, 0);
11480 }
11481 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011482 case TARGET_NR_fsetxattr:
11483 {
11484 void *n, *v = 0;
11485 if (arg3) {
11486 v = lock_user(VERIFY_READ, arg3, arg4, 1);
11487 if (!v) {
11488 ret = -TARGET_EFAULT;
11489 break;
11490 }
11491 }
11492 n = lock_user_string(arg2);
11493 if (n) {
11494 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
11495 } else {
11496 ret = -TARGET_EFAULT;
11497 }
11498 unlock_user(n, arg2, 0);
11499 unlock_user(v, arg3, 0);
11500 }
11501 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011502 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011503 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011504 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011505 void *p, *n, *v = 0;
11506 if (arg3) {
11507 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11508 if (!v) {
11509 ret = -TARGET_EFAULT;
11510 break;
11511 }
11512 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011513 p = lock_user_string(arg1);
11514 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000011515 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011516 if (num == TARGET_NR_getxattr) {
11517 ret = get_errno(getxattr(p, n, v, arg4));
11518 } else {
11519 ret = get_errno(lgetxattr(p, n, v, arg4));
11520 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011521 } else {
11522 ret = -TARGET_EFAULT;
11523 }
11524 unlock_user(p, arg1, 0);
11525 unlock_user(n, arg2, 0);
11526 unlock_user(v, arg3, arg4);
11527 }
11528 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011529 case TARGET_NR_fgetxattr:
11530 {
11531 void *n, *v = 0;
11532 if (arg3) {
11533 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
11534 if (!v) {
11535 ret = -TARGET_EFAULT;
11536 break;
11537 }
11538 }
11539 n = lock_user_string(arg2);
11540 if (n) {
11541 ret = get_errno(fgetxattr(arg1, n, v, arg4));
11542 } else {
11543 ret = -TARGET_EFAULT;
11544 }
11545 unlock_user(n, arg2, 0);
11546 unlock_user(v, arg3, arg4);
11547 }
11548 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011549 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000011550 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011551 {
11552 void *p, *n;
11553 p = lock_user_string(arg1);
11554 n = lock_user_string(arg2);
11555 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000011556 if (num == TARGET_NR_removexattr) {
11557 ret = get_errno(removexattr(p, n));
11558 } else {
11559 ret = get_errno(lremovexattr(p, n));
11560 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011561 } else {
11562 ret = -TARGET_EFAULT;
11563 }
11564 unlock_user(p, arg1, 0);
11565 unlock_user(n, arg2, 0);
11566 }
11567 break;
Peter Maydell30297b52011-12-14 15:37:18 +000011568 case TARGET_NR_fremovexattr:
11569 {
11570 void *n;
11571 n = lock_user_string(arg2);
11572 if (n) {
11573 ret = get_errno(fremovexattr(arg1, n));
11574 } else {
11575 ret = -TARGET_EFAULT;
11576 }
11577 unlock_user(n, arg2, 0);
11578 }
11579 break;
bellardebc05482003-09-30 21:08:41 +000011580#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070011581#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000011582#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000011583 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011584#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020011585 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000011586 ret = 0;
11587 break;
edgar_iglef967792009-01-07 14:19:38 +000011588#elif defined(TARGET_CRIS)
11589 if (arg1 & 0xff)
11590 ret = -TARGET_EINVAL;
11591 else {
11592 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
11593 ret = 0;
11594 }
11595 break;
bellard8d18e892007-11-14 15:18:40 +000011596#elif defined(TARGET_I386) && defined(TARGET_ABI32)
11597 ret = do_set_thread_area(cpu_env, arg1);
11598 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011599#elif defined(TARGET_M68K)
11600 {
Andreas Färber0429a972013-08-26 18:14:44 +020011601 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011602 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010011603 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011604 break;
11605 }
ths6f5b89a2007-03-02 20:48:00 +000011606#else
11607 goto unimplemented_nowarn;
11608#endif
11609#endif
11610#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000011611 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000011612#if defined(TARGET_I386) && defined(TARGET_ABI32)
11613 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010011614 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011615#elif defined(TARGET_M68K)
11616 {
Andreas Färber0429a972013-08-26 18:14:44 +020011617 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010011618 ret = ts->tp_value;
11619 break;
11620 }
bellard8d18e892007-11-14 15:18:40 +000011621#else
bellard5cd43932003-03-29 16:54:36 +000011622 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000011623#endif
bellard8d18e892007-11-14 15:18:40 +000011624#endif
bellard48dc41e2006-06-21 18:15:50 +000011625#ifdef TARGET_NR_getdomainname
11626 case TARGET_NR_getdomainname:
11627 goto unimplemented_nowarn;
11628#endif
ths6f5b89a2007-03-02 20:48:00 +000011629
thsb5906f92007-03-19 13:32:45 +000011630#ifdef TARGET_NR_clock_gettime
11631 case TARGET_NR_clock_gettime:
11632 {
11633 struct timespec ts;
11634 ret = get_errno(clock_gettime(arg1, &ts));
11635 if (!is_error(ret)) {
11636 host_to_target_timespec(arg2, &ts);
11637 }
11638 break;
11639 }
11640#endif
11641#ifdef TARGET_NR_clock_getres
11642 case TARGET_NR_clock_getres:
11643 {
11644 struct timespec ts;
11645 ret = get_errno(clock_getres(arg1, &ts));
11646 if (!is_error(ret)) {
11647 host_to_target_timespec(arg2, &ts);
11648 }
11649 break;
11650 }
11651#endif
pbrook63d76512008-05-29 13:43:29 +000011652#ifdef TARGET_NR_clock_nanosleep
11653 case TARGET_NR_clock_nanosleep:
11654 {
11655 struct timespec ts;
11656 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010011657 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
11658 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000011659 if (arg4)
11660 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011661
11662#if defined(TARGET_PPC)
11663 /* clock_nanosleep is odd in that it returns positive errno values.
11664 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010011665 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050011666 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
11667 }
11668#endif
pbrook63d76512008-05-29 13:43:29 +000011669 break;
11670 }
11671#endif
thsb5906f92007-03-19 13:32:45 +000011672
ths6f5b89a2007-03-02 20:48:00 +000011673#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
11674 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000011675 ret = get_errno(set_tid_address((int *)g2h(arg1)));
11676 break;
ths6f5b89a2007-03-02 20:48:00 +000011677#endif
11678
ths4cae1d12007-07-12 11:06:53 +000011679 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011680 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000011681 break;
ths4cae1d12007-07-12 11:06:53 +000011682
ths71455572007-06-21 21:45:30 +000011683 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010011684 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000011685 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010011686 break;
ths71455572007-06-21 21:45:30 +000011687
ths4f2b1fe2007-06-21 21:57:12 +000011688#ifdef TARGET_NR_set_robust_list
11689 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000011690 case TARGET_NR_get_robust_list:
11691 /* The ABI for supporting robust futexes has userspace pass
11692 * the kernel a pointer to a linked list which is updated by
11693 * userspace after the syscall; the list is walked by the kernel
11694 * when the thread exits. Since the linked list in QEMU guest
11695 * memory isn't a valid linked list for the host and we have
11696 * no way to reliably intercept the thread-death event, we can't
11697 * support these. Silently return ENOSYS so that guest userspace
11698 * falls back to a non-robust futex implementation (which should
11699 * be OK except in the corner case of the guest crashing while
11700 * holding a mutex that is shared with another process via
11701 * shared memory).
11702 */
11703 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000011704#endif
11705
Peter Maydell1acae9f2013-07-02 14:04:12 +010011706#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000011707 case TARGET_NR_utimensat:
11708 {
Riku Voipioebc996f2009-04-21 15:01:51 +030011709 struct timespec *tsp, ts[2];
11710 if (!arg3) {
11711 tsp = NULL;
11712 } else {
11713 target_to_host_timespec(ts, arg3);
11714 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
11715 tsp = ts;
11716 }
ths9007f0e2007-09-25 17:50:37 +000011717 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030011718 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000011719 else {
bellard579a97f2007-11-11 14:26:47 +000011720 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000011721 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000011722 goto fail;
11723 }
Riku Voipioebc996f2009-04-21 15:01:51 +030011724 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000011725 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000011726 }
11727 }
11728 break;
11729#endif
pbrookbd0c5662008-05-29 14:34:11 +000011730 case TARGET_NR_futex:
11731 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
11732 break;
aurel32dbfe4c32009-04-08 21:29:30 +000011733#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000011734 case TARGET_NR_inotify_init:
11735 ret = get_errno(sys_inotify_init());
Laurent Vivierc4e316c2017-03-02 01:54:48 +010011736 fd_trans_register(ret, &target_inotify_trans);
aurel3239b59762008-10-01 21:46:50 +000011737 break;
11738#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011739#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000011740#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
11741 case TARGET_NR_inotify_init1:
Lena Djokicfea243e2016-11-24 17:08:53 +010011742 ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
11743 fcntl_flags_tbl)));
Laurent Vivierc4e316c2017-03-02 01:54:48 +010011744 fd_trans_register(ret, &target_inotify_trans);
Riku Voipioc05c7a72010-03-26 15:25:11 +000011745 break;
11746#endif
Stefan Weila1606b02010-03-28 11:44:41 +020011747#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011748#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000011749 case TARGET_NR_inotify_add_watch:
11750 p = lock_user_string(arg2);
11751 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
11752 unlock_user(p, arg2, 0);
11753 break;
11754#endif
aurel32dbfe4c32009-04-08 21:29:30 +000011755#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000011756 case TARGET_NR_inotify_rm_watch:
11757 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
11758 break;
11759#endif
ths9007f0e2007-09-25 17:50:37 +000011760
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070011761#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000011762 case TARGET_NR_mq_open:
11763 {
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011764 struct mq_attr posix_mq_attr;
Lena Djokic26400772016-11-24 17:08:58 +010011765 struct mq_attr *pposix_mq_attr;
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011766 int host_flags;
aurel3224e10032009-04-15 16:11:43 +000011767
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011768 host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
Lena Djokic26400772016-11-24 17:08:58 +010011769 pposix_mq_attr = NULL;
11770 if (arg4) {
11771 if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
11772 goto efault;
11773 }
11774 pposix_mq_attr = &posix_mq_attr;
Tom Mustab6ce1f62014-08-12 13:53:36 -050011775 }
Aleksandar Markovicc7536ab2016-09-22 18:56:55 +020011776 p = lock_user_string(arg1 - 1);
11777 if (!p) {
11778 goto efault;
11779 }
Lena Djokic26400772016-11-24 17:08:58 +010011780 ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
aurel3224e10032009-04-15 16:11:43 +000011781 unlock_user (p, arg1, 0);
11782 }
11783 break;
11784
11785 case TARGET_NR_mq_unlink:
11786 p = lock_user_string(arg1 - 1);
Peter Maydell32112152016-07-12 13:02:13 +010011787 if (!p) {
11788 ret = -TARGET_EFAULT;
11789 break;
11790 }
aurel3224e10032009-04-15 16:11:43 +000011791 ret = get_errno(mq_unlink(p));
11792 unlock_user (p, arg1, 0);
11793 break;
11794
11795 case TARGET_NR_mq_timedsend:
11796 {
11797 struct timespec ts;
11798
11799 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11800 if (arg5 != 0) {
11801 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011802 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000011803 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011804 } else {
11805 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000011806 }
aurel3224e10032009-04-15 16:11:43 +000011807 unlock_user (p, arg2, arg3);
11808 }
11809 break;
11810
11811 case TARGET_NR_mq_timedreceive:
11812 {
11813 struct timespec ts;
11814 unsigned int prio;
11815
11816 p = lock_user (VERIFY_READ, arg2, arg3, 1);
11817 if (arg5 != 0) {
11818 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011819 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11820 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000011821 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010011822 } else {
11823 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
11824 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000011825 }
aurel3224e10032009-04-15 16:11:43 +000011826 unlock_user (p, arg2, arg3);
11827 if (arg4 != 0)
11828 put_user_u32(prio, arg4);
11829 }
11830 break;
11831
11832 /* Not implemented for now... */
11833/* case TARGET_NR_mq_notify: */
11834/* break; */
11835
11836 case TARGET_NR_mq_getsetattr:
11837 {
11838 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
11839 ret = 0;
11840 if (arg3 != 0) {
11841 ret = mq_getattr(arg1, &posix_mq_attr_out);
11842 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
11843 }
11844 if (arg2 != 0) {
11845 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
11846 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
11847 }
11848
11849 }
11850 break;
11851#endif
11852
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011853#ifdef CONFIG_SPLICE
11854#ifdef TARGET_NR_tee
11855 case TARGET_NR_tee:
11856 {
11857 ret = get_errno(tee(arg1,arg2,arg3,arg4));
11858 }
11859 break;
11860#endif
11861#ifdef TARGET_NR_splice
11862 case TARGET_NR_splice:
11863 {
11864 loff_t loff_in, loff_out;
11865 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010011866 if (arg2) {
11867 if (get_user_u64(loff_in, arg2)) {
11868 goto efault;
11869 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011870 ploff_in = &loff_in;
11871 }
Andreas Schwab17644b32015-03-10 17:11:35 +010011872 if (arg4) {
11873 if (get_user_u64(loff_out, arg4)) {
11874 goto efault;
11875 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011876 ploff_out = &loff_out;
11877 }
11878 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010011879 if (arg2) {
11880 if (put_user_u64(loff_in, arg2)) {
11881 goto efault;
11882 }
11883 }
11884 if (arg4) {
11885 if (put_user_u64(loff_out, arg4)) {
11886 goto efault;
11887 }
11888 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011889 }
11890 break;
11891#endif
11892#ifdef TARGET_NR_vmsplice
11893 case TARGET_NR_vmsplice:
11894 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070011895 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
11896 if (vec != NULL) {
11897 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
11898 unlock_iovec(vec, arg2, arg3, 0);
11899 } else {
11900 ret = -host_to_target_errno(errno);
11901 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053011902 }
11903 break;
11904#endif
11905#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030011906#ifdef CONFIG_EVENTFD
11907#if defined(TARGET_NR_eventfd)
11908 case TARGET_NR_eventfd:
11909 ret = get_errno(eventfd(arg1, 0));
Laurent Vivier562a20b2017-03-01 10:37:48 +010011910 fd_trans_register(ret, &target_eventfd_trans);
Riku Voipioc2882b92009-08-12 15:08:24 +030011911 break;
11912#endif
11913#if defined(TARGET_NR_eventfd2)
11914 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020011915 {
11916 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
11917 if (arg2 & TARGET_O_NONBLOCK) {
11918 host_flags |= O_NONBLOCK;
11919 }
11920 if (arg2 & TARGET_O_CLOEXEC) {
11921 host_flags |= O_CLOEXEC;
11922 }
11923 ret = get_errno(eventfd(arg1, host_flags));
Laurent Vivier562a20b2017-03-01 10:37:48 +010011924 fd_trans_register(ret, &target_eventfd_trans);
Riku Voipioc2882b92009-08-12 15:08:24 +030011925 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020011926 }
Riku Voipioc2882b92009-08-12 15:08:24 +030011927#endif
11928#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030011929#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
11930 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010011931#if TARGET_ABI_BITS == 32
11932 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
11933 target_offset64(arg5, arg6)));
11934#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030011935 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010011936#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030011937 break;
11938#endif
Peter Maydellc727f472011-01-06 11:05:10 +000011939#if defined(CONFIG_SYNC_FILE_RANGE)
11940#if defined(TARGET_NR_sync_file_range)
11941 case TARGET_NR_sync_file_range:
11942#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030011943#if defined(TARGET_MIPS)
11944 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11945 target_offset64(arg5, arg6), arg7));
11946#else
Peter Maydellc727f472011-01-06 11:05:10 +000011947 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
11948 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030011949#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000011950#else
11951 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
11952#endif
11953 break;
11954#endif
11955#if defined(TARGET_NR_sync_file_range2)
11956 case TARGET_NR_sync_file_range2:
11957 /* This is like sync_file_range but the arguments are reordered */
11958#if TARGET_ABI_BITS == 32
11959 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
11960 target_offset64(arg5, arg6), arg2));
11961#else
11962 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
11963#endif
11964 break;
11965#endif
11966#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020011967#if defined(TARGET_NR_signalfd4)
11968 case TARGET_NR_signalfd4:
11969 ret = do_signalfd4(arg1, arg2, arg4);
11970 break;
11971#endif
11972#if defined(TARGET_NR_signalfd)
11973 case TARGET_NR_signalfd:
11974 ret = do_signalfd4(arg1, arg2, 0);
11975 break;
11976#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000011977#if defined(CONFIG_EPOLL)
11978#if defined(TARGET_NR_epoll_create)
11979 case TARGET_NR_epoll_create:
11980 ret = get_errno(epoll_create(arg1));
11981 break;
11982#endif
11983#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
11984 case TARGET_NR_epoll_create1:
11985 ret = get_errno(epoll_create1(arg1));
11986 break;
11987#endif
11988#if defined(TARGET_NR_epoll_ctl)
11989 case TARGET_NR_epoll_ctl:
11990 {
11991 struct epoll_event ep;
11992 struct epoll_event *epp = 0;
11993 if (arg4) {
11994 struct target_epoll_event *target_ep;
11995 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
11996 goto efault;
11997 }
11998 ep.events = tswap32(target_ep->events);
11999 /* The epoll_data_t union is just opaque data to the kernel,
12000 * so we transfer all 64 bits across and need not worry what
12001 * actual data type it is.
12002 */
12003 ep.data.u64 = tswap64(target_ep->data.u64);
12004 unlock_user_struct(target_ep, arg4, 0);
12005 epp = &ep;
12006 }
12007 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
12008 break;
12009 }
12010#endif
12011
Peter Maydell227f0212016-06-06 19:58:11 +010012012#if defined(TARGET_NR_epoll_wait) || defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012013#if defined(TARGET_NR_epoll_wait)
12014 case TARGET_NR_epoll_wait:
12015#endif
Peter Maydell227f0212016-06-06 19:58:11 +010012016#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012017 case TARGET_NR_epoll_pwait:
12018#endif
12019 {
12020 struct target_epoll_event *target_ep;
12021 struct epoll_event *ep;
12022 int epfd = arg1;
12023 int maxevents = arg3;
12024 int timeout = arg4;
12025
Peter Maydell2ba7fae32016-07-18 15:35:59 +010012026 if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
12027 ret = -TARGET_EINVAL;
12028 break;
12029 }
12030
Peter Maydell3b6edd12011-02-15 18:35:05 +000012031 target_ep = lock_user(VERIFY_WRITE, arg2,
12032 maxevents * sizeof(struct target_epoll_event), 1);
12033 if (!target_ep) {
12034 goto efault;
12035 }
12036
Peter Maydell04c95f42016-07-18 15:36:00 +010012037 ep = g_try_new(struct epoll_event, maxevents);
12038 if (!ep) {
12039 unlock_user(target_ep, arg2, 0);
12040 ret = -TARGET_ENOMEM;
12041 break;
12042 }
Peter Maydell3b6edd12011-02-15 18:35:05 +000012043
12044 switch (num) {
Peter Maydell227f0212016-06-06 19:58:11 +010012045#if defined(TARGET_NR_epoll_pwait)
Peter Maydell3b6edd12011-02-15 18:35:05 +000012046 case TARGET_NR_epoll_pwait:
12047 {
12048 target_sigset_t *target_set;
12049 sigset_t _set, *set = &_set;
12050
12051 if (arg5) {
Peter Maydellc8157012016-06-30 14:23:24 +010012052 if (arg6 != sizeof(target_sigset_t)) {
12053 ret = -TARGET_EINVAL;
12054 break;
12055 }
12056
Peter Maydell3b6edd12011-02-15 18:35:05 +000012057 target_set = lock_user(VERIFY_READ, arg5,
12058 sizeof(target_sigset_t), 1);
12059 if (!target_set) {
Peter Maydell04c95f42016-07-18 15:36:00 +010012060 ret = -TARGET_EFAULT;
12061 break;
Peter Maydell3b6edd12011-02-15 18:35:05 +000012062 }
12063 target_to_host_sigset(set, target_set);
12064 unlock_user(target_set, arg5, 0);
12065 } else {
12066 set = NULL;
12067 }
12068
Peter Maydell227f0212016-06-06 19:58:11 +010012069 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12070 set, SIGSET_T_SIZE));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012071 break;
12072 }
12073#endif
12074#if defined(TARGET_NR_epoll_wait)
12075 case TARGET_NR_epoll_wait:
Peter Maydell227f0212016-06-06 19:58:11 +010012076 ret = get_errno(safe_epoll_pwait(epfd, ep, maxevents, timeout,
12077 NULL, 0));
Peter Maydell3b6edd12011-02-15 18:35:05 +000012078 break;
12079#endif
12080 default:
12081 ret = -TARGET_ENOSYS;
12082 }
12083 if (!is_error(ret)) {
12084 int i;
12085 for (i = 0; i < ret; i++) {
12086 target_ep[i].events = tswap32(ep[i].events);
12087 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
12088 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012089 unlock_user(target_ep, arg2,
12090 ret * sizeof(struct target_epoll_event));
12091 } else {
12092 unlock_user(target_ep, arg2, 0);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012093 }
Peter Maydell04c95f42016-07-18 15:36:00 +010012094 g_free(ep);
Peter Maydell3b6edd12011-02-15 18:35:05 +000012095 break;
12096 }
12097#endif
12098#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010012099#ifdef TARGET_NR_prlimit64
12100 case TARGET_NR_prlimit64:
12101 {
12102 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
12103 struct target_rlimit64 *target_rnew, *target_rold;
12104 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010012105 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010012106 if (arg3) {
12107 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
12108 goto efault;
12109 }
12110 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
12111 rnew.rlim_max = tswap64(target_rnew->rlim_max);
12112 unlock_user_struct(target_rnew, arg3, 0);
12113 rnewp = &rnew;
12114 }
12115
Felix Janda95018012014-12-02 22:11:17 +010012116 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010012117 if (!is_error(ret) && arg4) {
12118 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
12119 goto efault;
12120 }
12121 target_rold->rlim_cur = tswap64(rold.rlim_cur);
12122 target_rold->rlim_max = tswap64(rold.rlim_max);
12123 unlock_user_struct(target_rold, arg4, 1);
12124 }
12125 break;
12126 }
12127#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070012128#ifdef TARGET_NR_gethostname
12129 case TARGET_NR_gethostname:
12130 {
12131 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
12132 if (name) {
12133 ret = get_errno(gethostname(name, arg2));
12134 unlock_user(name, arg1, arg2);
12135 } else {
12136 ret = -TARGET_EFAULT;
12137 }
12138 break;
12139 }
12140#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012141#ifdef TARGET_NR_atomic_cmpxchg_32
12142 case TARGET_NR_atomic_cmpxchg_32:
12143 {
12144 /* should use start_exclusive from main.c */
12145 abi_ulong mem_value;
12146 if (get_user_u32(mem_value, arg6)) {
12147 target_siginfo_t info;
12148 info.si_signo = SIGSEGV;
12149 info.si_errno = 0;
12150 info.si_code = TARGET_SEGV_MAPERR;
12151 info._sifields._sigfault._addr = arg6;
Peter Maydell9d2803f2016-07-28 16:44:46 +010012152 queue_signal((CPUArchState *)cpu_env, info.si_signo,
12153 QEMU_SI_FAULT, &info);
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012154 ret = 0xdeadbeef;
12155
12156 }
12157 if (mem_value == arg2)
12158 put_user_u32(arg1, arg6);
12159 ret = mem_value;
12160 break;
12161 }
12162#endif
12163#ifdef TARGET_NR_atomic_barrier
12164 case TARGET_NR_atomic_barrier:
12165 {
12166 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000012167 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030012168 break;
12169 }
12170#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012171
12172#ifdef TARGET_NR_timer_create
12173 case TARGET_NR_timer_create:
12174 {
12175 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
12176
12177 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012178
12179 int clkid = arg1;
12180 int timer_index = next_free_host_timer();
12181
12182 if (timer_index < 0) {
12183 ret = -TARGET_EAGAIN;
12184 } else {
12185 timer_t *phtimer = g_posix_timers + timer_index;
12186
12187 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012188 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010012189 ret = target_to_host_sigevent(phost_sevp, arg2);
12190 if (ret != 0) {
12191 break;
12192 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012193 }
12194
12195 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
12196 if (ret) {
12197 phtimer = NULL;
12198 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010012199 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012200 goto efault;
12201 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012202 }
12203 }
12204 break;
12205 }
12206#endif
12207
12208#ifdef TARGET_NR_timer_settime
12209 case TARGET_NR_timer_settime:
12210 {
12211 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
12212 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012213 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012214
Alexander Grafaecc8862014-11-10 21:33:03 +010012215 if (timerid < 0) {
12216 ret = timerid;
12217 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012218 ret = -TARGET_EINVAL;
12219 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012220 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012221 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
12222
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012223 if (target_to_host_itimerspec(&hspec_new, arg3)) {
12224 goto efault;
12225 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012226 ret = get_errno(
12227 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
Marc-André Lureau40c80b52017-01-19 10:15:32 -050012228 if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
12229 goto efault;
12230 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012231 }
12232 break;
12233 }
12234#endif
12235
12236#ifdef TARGET_NR_timer_gettime
12237 case TARGET_NR_timer_gettime:
12238 {
12239 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010012240 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012241
Alexander Grafaecc8862014-11-10 21:33:03 +010012242 if (timerid < 0) {
12243 ret = timerid;
12244 } else if (!arg2) {
12245 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012246 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012247 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012248 struct itimerspec hspec;
12249 ret = get_errno(timer_gettime(htimer, &hspec));
12250
12251 if (host_to_target_itimerspec(arg2, &hspec)) {
12252 ret = -TARGET_EFAULT;
12253 }
12254 }
12255 break;
12256 }
12257#endif
12258
12259#ifdef TARGET_NR_timer_getoverrun
12260 case TARGET_NR_timer_getoverrun:
12261 {
12262 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012263 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012264
Alexander Grafaecc8862014-11-10 21:33:03 +010012265 if (timerid < 0) {
12266 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012267 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012268 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012269 ret = get_errno(timer_getoverrun(htimer));
12270 }
Laurent Viviere36800c2015-10-02 14:48:09 +020012271 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012272 break;
12273 }
12274#endif
12275
12276#ifdef TARGET_NR_timer_delete
12277 case TARGET_NR_timer_delete:
12278 {
12279 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010012280 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020012281
Alexander Grafaecc8862014-11-10 21:33:03 +010012282 if (timerid < 0) {
12283 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012284 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020012285 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012286 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020012287 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110012288 }
12289 break;
12290 }
12291#endif
12292
Riku Voipio51834342014-06-22 11:25:42 +010012293#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
12294 case TARGET_NR_timerfd_create:
12295 ret = get_errno(timerfd_create(arg1,
12296 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
12297 break;
12298#endif
12299
12300#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
12301 case TARGET_NR_timerfd_gettime:
12302 {
12303 struct itimerspec its_curr;
12304
12305 ret = get_errno(timerfd_gettime(arg1, &its_curr));
12306
12307 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
12308 goto efault;
12309 }
12310 }
12311 break;
12312#endif
12313
12314#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
12315 case TARGET_NR_timerfd_settime:
12316 {
12317 struct itimerspec its_new, its_old, *p_new;
12318
12319 if (arg3) {
12320 if (target_to_host_itimerspec(&its_new, arg3)) {
12321 goto efault;
12322 }
12323 p_new = &its_new;
12324 } else {
12325 p_new = NULL;
12326 }
12327
12328 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
12329
12330 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
12331 goto efault;
12332 }
12333 }
12334 break;
12335#endif
12336
Paul Burtonab31cda2014-06-22 11:25:43 +010012337#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
12338 case TARGET_NR_ioprio_get:
12339 ret = get_errno(ioprio_get(arg1, arg2));
12340 break;
12341#endif
12342
12343#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
12344 case TARGET_NR_ioprio_set:
12345 ret = get_errno(ioprio_set(arg1, arg2, arg3));
12346 break;
12347#endif
12348
Riku Voipio9af5c902014-08-12 15:58:57 +030012349#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
12350 case TARGET_NR_setns:
12351 ret = get_errno(setns(arg1, arg2));
12352 break;
12353#endif
12354#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
12355 case TARGET_NR_unshare:
12356 ret = get_errno(unshare(arg1));
12357 break;
12358#endif
Laurent Vivier2f147882016-09-25 22:20:20 +020012359#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
12360 case TARGET_NR_kcmp:
12361 ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
12362 break;
12363#endif
Riku Voipio9af5c902014-08-12 15:58:57 +030012364
bellard31e31b82003-02-18 22:55:36 +000012365 default:
12366 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000012367 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000012368#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 +000012369 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000012370#endif
ths0da46a62007-10-20 20:23:07 +000012371 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000012372 break;
12373 }
bellard579a97f2007-11-11 14:26:47 +000012374fail:
bellardc573ff62004-01-04 15:51:36 +000012375#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000012376 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000012377#endif
thsb92c47c2007-11-01 00:07:38 +000012378 if(do_strace)
12379 print_syscall_ret(num, ret);
LluĂ­s Vilanova9c15e702016-06-21 15:52:04 +020012380 trace_guest_user_syscall_ret(cpu, num, ret);
bellard31e31b82003-02-18 22:55:36 +000012381 return ret;
bellard579a97f2007-11-11 14:26:47 +000012382efault:
12383 ret = -TARGET_EFAULT;
12384 goto fail;
bellard31e31b82003-02-18 22:55:36 +000012385}