blob: ff20ea7d74db08b86d8e6532e5c544cae81f0032 [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
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
John Spencerc56dc772012-12-10 07:59:46 +010031#include <grp.h>
bellard31e31b82003-02-18 22:55:36 +000032#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000033#include <sys/ipc.h>
34#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/stat.h>
38#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010039#include <sys/file.h>
40#include <sys/fsuid.h>
41#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000042#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/resource.h>
44#include <sys/mman.h>
45#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000046#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000047#include <signal.h>
48#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020049#ifdef __ia64__
50int __clone2(int (*fn)(void *), void *child_stack_base,
51 size_t stack_size, int flags, void *arg, ...);
52#endif
bellard31e31b82003-02-18 22:55:36 +000053#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000054#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000055#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000056#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000057#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000058#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000059#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000060#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000061#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000062#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020063#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000064//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000065#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000066#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020067#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000068#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020069#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030070#ifdef CONFIG_TIMERFD
71#include <sys/timerfd.h>
72#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020073#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000074#include <sys/gmon.h>
75#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030076#ifdef CONFIG_EVENTFD
77#include <sys/eventfd.h>
78#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000079#ifdef CONFIG_EPOLL
80#include <sys/epoll.h>
81#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070082#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010083#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070084#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000085#ifdef CONFIG_SENDFILE
86#include <sys/sendfile.h>
87#endif
bellard31e31b82003-02-18 22:55:36 +000088
89#define termios host_termios
90#define winsize host_winsize
91#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000092#define sgttyb host_sgttyb /* same as target */
93#define tchars host_tchars /* same as target */
94#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000095
96#include <linux/termios.h>
97#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000098#include <linux/cdrom.h>
99#include <linux/hdreg.h>
100#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +0000101#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +0000102#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300103#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000104#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000105#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000106#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200107#include <linux/fb.h>
108#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100109#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000110#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100111#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200112#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100113#include <linux/blkpg.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
pbrookd865bab2008-06-07 22:12:17 +0000119#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
120 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000121
bellard72f03902003-02-18 23:33:18 +0000122//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000123
bellard1a9353d2003-03-16 20:28:50 +0000124//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000125#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
126#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000127
bellard70a194b2003-08-11 22:20:16 +0000128
bellard70a194b2003-08-11 22:20:16 +0000129#undef _syscall0
130#undef _syscall1
131#undef _syscall2
132#undef _syscall3
133#undef _syscall4
134#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000135#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000136
bellard83fcb512006-06-14 13:37:16 +0000137#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000138static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000139{ \
140 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000141}
142
bellard83fcb512006-06-14 13:37:16 +0000143#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000144static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000145{ \
146 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000147}
148
bellard83fcb512006-06-14 13:37:16 +0000149#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000150static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000151{ \
152 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000153}
154
bellard83fcb512006-06-14 13:37:16 +0000155#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000156static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000157{ \
158 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000159}
160
bellard83fcb512006-06-14 13:37:16 +0000161#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000162static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000163{ \
164 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000165}
166
bellard83fcb512006-06-14 13:37:16 +0000167#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
168 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000169static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000170{ \
171 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000172}
bellard83fcb512006-06-14 13:37:16 +0000173
174
175#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
176 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000177static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
178 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000179{ \
180 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
181}
182
bellard70a194b2003-08-11 22:20:16 +0000183
bellard31e31b82003-02-18 22:55:36 +0000184#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000185#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000186#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000187#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000188#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000189#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000190#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000191#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000192#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000193#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000194#define __NR_sys_inotify_init __NR_inotify_init
195#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
196#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000197
Alexander Graf42a39fb2011-04-15 17:32:45 +0200198#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
199 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000200#define __NR__llseek __NR_lseek
201#endif
202
James Hogana29e5ba2014-03-25 21:51:08 +0000203/* Newer kernel ports have llseek() instead of _llseek() */
204#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
205#define TARGET_NR__llseek TARGET_NR_llseek
206#endif
207
bellard72f03902003-02-18 23:33:18 +0000208#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000209_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000210#else
ths0da46a62007-10-20 20:23:07 +0000211/* This is a replacement for the host gettid() and must return a host
212 errno. */
bellard72f03902003-02-18 23:33:18 +0000213static int gettid(void) {
214 return -ENOSYS;
215}
216#endif
Chen Gang704eff62015-08-21 05:37:33 +0800217#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100219#endif
220#if !defined(__NR_getdents) || \
221 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000222_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
223#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700224#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000225_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
226 loff_t *, res, uint, wh);
227#endif
228_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
229_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
230#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
231_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
232#endif
233#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
234_syscall2(int,sys_tkill,int,tid,int,sig)
235#endif
236#ifdef __NR_exit_group
237_syscall1(int,exit_group,int,error_code)
238#endif
239#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
240_syscall1(int,set_tid_address,int *,tidptr)
241#endif
aurel323b3f24a2009-04-15 16:12:13 +0000242#if defined(TARGET_NR_futex) && defined(__NR_futex)
243_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
244 const struct timespec *,timeout,int *,uaddr2,int,val3)
245#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500246#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
247_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
248 unsigned long *, user_mask_ptr);
249#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
250_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
251 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200252_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
253 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000254_syscall2(int, capget, struct __user_cap_header_struct *, header,
255 struct __user_cap_data_struct *, data);
256_syscall2(int, capset, struct __user_cap_header_struct *, header,
257 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100258#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
259_syscall2(int, ioprio_get, int, which, int, who)
260#endif
261#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
262_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
263#endif
aurel323b3f24a2009-04-15 16:12:13 +0000264
265static bitmask_transtbl fcntl_flags_tbl[] = {
266 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
267 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
268 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
269 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
270 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
271 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
272 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
273 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700274 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000275 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
276 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
277 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
278 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000279#if defined(O_DIRECT)
280 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
281#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700282#if defined(O_NOATIME)
283 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
284#endif
285#if defined(O_CLOEXEC)
286 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
287#endif
288#if defined(O_PATH)
289 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
290#endif
291 /* Don't terminate the list prematurely on 64-bit host+guest. */
292#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
293 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
294#endif
aurel323b3f24a2009-04-15 16:12:13 +0000295 { 0, 0, 0, 0 }
296};
297
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100298typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100299typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200300typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100301 TargetFdDataFunc host_to_target_data;
302 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100303 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200304} TargetFdTrans;
305
306static TargetFdTrans **target_fd_trans;
307
308static unsigned int target_fd_max;
309
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100310static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200311{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100312 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100313 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200314 }
315 return NULL;
316}
317
Laurent Vivier7b36f782015-10-28 21:40:44 +0100318static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
319{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100320 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100321 return target_fd_trans[fd]->target_to_host_addr;
322 }
323 return NULL;
324}
325
Laurent Viviere36800c2015-10-02 14:48:09 +0200326static void fd_trans_register(int fd, TargetFdTrans *trans)
327{
328 unsigned int oldmax;
329
330 if (fd >= target_fd_max) {
331 oldmax = target_fd_max;
332 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
333 target_fd_trans = g_realloc(target_fd_trans,
334 target_fd_max * sizeof(TargetFdTrans));
335 memset((void *)(target_fd_trans + oldmax), 0,
336 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
337 }
338 target_fd_trans[fd] = trans;
339}
340
341static void fd_trans_unregister(int fd)
342{
343 if (fd >= 0 && fd < target_fd_max) {
344 target_fd_trans[fd] = NULL;
345 }
346}
347
348static void fd_trans_dup(int oldfd, int newfd)
349{
350 fd_trans_unregister(newfd);
351 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
352 fd_trans_register(newfd, target_fd_trans[oldfd]);
353 }
354}
355
aurel323b3f24a2009-04-15 16:12:13 +0000356static int sys_getcwd1(char *buf, size_t size)
357{
358 if (getcwd(buf, size) == NULL) {
359 /* getcwd() sets errno */
360 return (-1);
361 }
aurel32aaf4ad32009-04-16 14:17:14 +0000362 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000363}
364
Alexander Graff4c69012011-09-25 06:25:35 +0200365static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000366{
367 /*
368 * open(2) has extra parameter 'mode' when called with
369 * flag O_CREAT.
370 */
371 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000372 return (openat(dirfd, pathname, flags, mode));
373 }
374 return (openat(dirfd, pathname, flags));
375}
Riku Voipioebc996f2009-04-21 15:01:51 +0300376
Peter Maydell1acae9f2013-07-02 14:04:12 +0100377#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300378#ifdef CONFIG_UTIMENSAT
379static int sys_utimensat(int dirfd, const char *pathname,
380 const struct timespec times[2], int flags)
381{
382 if (pathname == NULL)
383 return futimens(dirfd, times);
384 else
385 return utimensat(dirfd, pathname, times, flags);
386}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100387#elif defined(__NR_utimensat)
388#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000389_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
390 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100391#else
392static int sys_utimensat(int dirfd, const char *pathname,
393 const struct timespec times[2], int flags)
394{
395 errno = ENOSYS;
396 return -1;
397}
ths9007f0e2007-09-25 17:50:37 +0000398#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100399#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000400
401#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000402#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000403
aurel3239b59762008-10-01 21:46:50 +0000404#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000405static int sys_inotify_init(void)
406{
407 return (inotify_init());
408}
aurel3239b59762008-10-01 21:46:50 +0000409#endif
410#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000411static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
412{
413 return (inotify_add_watch(fd, pathname, mask));
414}
aurel3239b59762008-10-01 21:46:50 +0000415#endif
416#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000417static int sys_inotify_rm_watch(int fd, int32_t wd)
418{
aurel328690e422009-04-17 13:50:32 +0000419 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000420}
aurel3239b59762008-10-01 21:46:50 +0000421#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000422#ifdef CONFIG_INOTIFY1
423#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
424static int sys_inotify_init1(int flags)
425{
426 return (inotify_init1(flags));
427}
428#endif
429#endif
aurel323b3f24a2009-04-15 16:12:13 +0000430#else
431/* Userspace can usually survive runtime without inotify */
432#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000433#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000434#undef TARGET_NR_inotify_add_watch
435#undef TARGET_NR_inotify_rm_watch
436#endif /* CONFIG_INOTIFY */
437
Mike Frysingerd8035d42011-02-07 01:05:51 -0500438#if defined(TARGET_NR_ppoll)
439#ifndef __NR_ppoll
440# define __NR_ppoll -1
441#endif
442#define __NR_sys_ppoll __NR_ppoll
443_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200444 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500445 size_t, sigsetsize)
446#endif
bellard66fb9762003-03-23 01:06:05 +0000447
Mike Frysinger055e0902011-06-03 17:01:49 -0400448#if defined(TARGET_NR_pselect6)
449#ifndef __NR_pselect6
450# define __NR_pselect6 -1
451#endif
452#define __NR_sys_pselect6 __NR_pselect6
453_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
454 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
455#endif
456
Peter Maydell163a05a2011-06-27 17:44:52 +0100457#if defined(TARGET_NR_prlimit64)
458#ifndef __NR_prlimit64
459# define __NR_prlimit64 -1
460#endif
461#define __NR_sys_prlimit64 __NR_prlimit64
462/* The glibc rlimit structure may not be that used by the underlying syscall */
463struct host_rlimit64 {
464 uint64_t rlim_cur;
465 uint64_t rlim_max;
466};
467_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
468 const struct host_rlimit64 *, new_limit,
469 struct host_rlimit64 *, old_limit)
470#endif
471
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100472
473#if defined(TARGET_NR_timer_create)
474/* Maxiumum of 32 active POSIX timers allowed at any one time. */
475static timer_t g_posix_timers[32] = { 0, } ;
476
477static inline int next_free_host_timer(void)
478{
479 int k ;
480 /* FIXME: Does finding the next free slot require a lock? */
481 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
482 if (g_posix_timers[k] == 0) {
483 g_posix_timers[k] = (timer_t) 1;
484 return k;
485 }
486 }
487 return -1;
488}
489#endif
490
Riku Voipio48e515d2011-07-12 15:40:51 +0300491/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000492#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300493static inline int regpairs_aligned(void *cpu_env) {
494 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
495}
496#elif defined(TARGET_MIPS)
497static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000498#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
499/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
500 * of registers which translates to the same as ARM/MIPS, because we start with
501 * r3 as arg1 */
502static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300503#else
504static inline int regpairs_aligned(void *cpu_env) { return 0; }
505#endif
506
thsb92c47c2007-11-01 00:07:38 +0000507#define ERRNO_TABLE_SIZE 1200
508
509/* target_to_host_errno_table[] is initialized from
510 * host_to_target_errno_table[] in syscall_init(). */
511static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
512};
513
ths637947f2007-06-01 12:09:19 +0000514/*
thsfe8f0962007-07-12 10:59:21 +0000515 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000516 * minus the errnos that are not actually generic to all archs.
517 */
thsb92c47c2007-11-01 00:07:38 +0000518static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800519 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000520 [EIDRM] = TARGET_EIDRM,
521 [ECHRNG] = TARGET_ECHRNG,
522 [EL2NSYNC] = TARGET_EL2NSYNC,
523 [EL3HLT] = TARGET_EL3HLT,
524 [EL3RST] = TARGET_EL3RST,
525 [ELNRNG] = TARGET_ELNRNG,
526 [EUNATCH] = TARGET_EUNATCH,
527 [ENOCSI] = TARGET_ENOCSI,
528 [EL2HLT] = TARGET_EL2HLT,
529 [EDEADLK] = TARGET_EDEADLK,
530 [ENOLCK] = TARGET_ENOLCK,
531 [EBADE] = TARGET_EBADE,
532 [EBADR] = TARGET_EBADR,
533 [EXFULL] = TARGET_EXFULL,
534 [ENOANO] = TARGET_ENOANO,
535 [EBADRQC] = TARGET_EBADRQC,
536 [EBADSLT] = TARGET_EBADSLT,
537 [EBFONT] = TARGET_EBFONT,
538 [ENOSTR] = TARGET_ENOSTR,
539 [ENODATA] = TARGET_ENODATA,
540 [ETIME] = TARGET_ETIME,
541 [ENOSR] = TARGET_ENOSR,
542 [ENONET] = TARGET_ENONET,
543 [ENOPKG] = TARGET_ENOPKG,
544 [EREMOTE] = TARGET_EREMOTE,
545 [ENOLINK] = TARGET_ENOLINK,
546 [EADV] = TARGET_EADV,
547 [ESRMNT] = TARGET_ESRMNT,
548 [ECOMM] = TARGET_ECOMM,
549 [EPROTO] = TARGET_EPROTO,
550 [EDOTDOT] = TARGET_EDOTDOT,
551 [EMULTIHOP] = TARGET_EMULTIHOP,
552 [EBADMSG] = TARGET_EBADMSG,
553 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
554 [EOVERFLOW] = TARGET_EOVERFLOW,
555 [ENOTUNIQ] = TARGET_ENOTUNIQ,
556 [EBADFD] = TARGET_EBADFD,
557 [EREMCHG] = TARGET_EREMCHG,
558 [ELIBACC] = TARGET_ELIBACC,
559 [ELIBBAD] = TARGET_ELIBBAD,
560 [ELIBSCN] = TARGET_ELIBSCN,
561 [ELIBMAX] = TARGET_ELIBMAX,
562 [ELIBEXEC] = TARGET_ELIBEXEC,
563 [EILSEQ] = TARGET_EILSEQ,
564 [ENOSYS] = TARGET_ENOSYS,
565 [ELOOP] = TARGET_ELOOP,
566 [ERESTART] = TARGET_ERESTART,
567 [ESTRPIPE] = TARGET_ESTRPIPE,
568 [ENOTEMPTY] = TARGET_ENOTEMPTY,
569 [EUSERS] = TARGET_EUSERS,
570 [ENOTSOCK] = TARGET_ENOTSOCK,
571 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
572 [EMSGSIZE] = TARGET_EMSGSIZE,
573 [EPROTOTYPE] = TARGET_EPROTOTYPE,
574 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
575 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
576 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
577 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
578 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
579 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
580 [EADDRINUSE] = TARGET_EADDRINUSE,
581 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
582 [ENETDOWN] = TARGET_ENETDOWN,
583 [ENETUNREACH] = TARGET_ENETUNREACH,
584 [ENETRESET] = TARGET_ENETRESET,
585 [ECONNABORTED] = TARGET_ECONNABORTED,
586 [ECONNRESET] = TARGET_ECONNRESET,
587 [ENOBUFS] = TARGET_ENOBUFS,
588 [EISCONN] = TARGET_EISCONN,
589 [ENOTCONN] = TARGET_ENOTCONN,
590 [EUCLEAN] = TARGET_EUCLEAN,
591 [ENOTNAM] = TARGET_ENOTNAM,
592 [ENAVAIL] = TARGET_ENAVAIL,
593 [EISNAM] = TARGET_EISNAM,
594 [EREMOTEIO] = TARGET_EREMOTEIO,
595 [ESHUTDOWN] = TARGET_ESHUTDOWN,
596 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
597 [ETIMEDOUT] = TARGET_ETIMEDOUT,
598 [ECONNREFUSED] = TARGET_ECONNREFUSED,
599 [EHOSTDOWN] = TARGET_EHOSTDOWN,
600 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
601 [EALREADY] = TARGET_EALREADY,
602 [EINPROGRESS] = TARGET_EINPROGRESS,
603 [ESTALE] = TARGET_ESTALE,
604 [ECANCELED] = TARGET_ECANCELED,
605 [ENOMEDIUM] = TARGET_ENOMEDIUM,
606 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000607#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000608 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000609#endif
610#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000611 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000612#endif
613#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000614 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000615#endif
616#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000617 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000618#endif
619#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000620 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000621#endif
622#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000623 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000624#endif
thsb92c47c2007-11-01 00:07:38 +0000625};
ths637947f2007-06-01 12:09:19 +0000626
627static inline int host_to_target_errno(int err)
628{
629 if(host_to_target_errno_table[err])
630 return host_to_target_errno_table[err];
631 return err;
632}
633
thsb92c47c2007-11-01 00:07:38 +0000634static inline int target_to_host_errno(int err)
635{
636 if (target_to_host_errno_table[err])
637 return target_to_host_errno_table[err];
638 return err;
639}
640
blueswir1992f48a2007-10-14 16:27:31 +0000641static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000642{
643 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000644 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000645 else
646 return ret;
647}
648
blueswir1992f48a2007-10-14 16:27:31 +0000649static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000650{
blueswir1992f48a2007-10-14 16:27:31 +0000651 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000652}
653
thsb92c47c2007-11-01 00:07:38 +0000654char *target_strerror(int err)
655{
Alexander Graf962b2892011-11-21 12:04:07 +0100656 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
657 return NULL;
658 }
thsb92c47c2007-11-01 00:07:38 +0000659 return strerror(target_to_host_errno(err));
660}
661
Paul Burton8289d112014-06-22 11:25:33 +0100662static inline int host_to_target_sock_type(int host_type)
663{
664 int target_type;
665
666 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
667 case SOCK_DGRAM:
668 target_type = TARGET_SOCK_DGRAM;
669 break;
670 case SOCK_STREAM:
671 target_type = TARGET_SOCK_STREAM;
672 break;
673 default:
674 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
675 break;
676 }
677
678#if defined(SOCK_CLOEXEC)
679 if (host_type & SOCK_CLOEXEC) {
680 target_type |= TARGET_SOCK_CLOEXEC;
681 }
682#endif
683
684#if defined(SOCK_NONBLOCK)
685 if (host_type & SOCK_NONBLOCK) {
686 target_type |= TARGET_SOCK_NONBLOCK;
687 }
688#endif
689
690 return target_type;
691}
692
blueswir1992f48a2007-10-14 16:27:31 +0000693static abi_ulong target_brk;
694static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000695static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000696
blueswir1992f48a2007-10-14 16:27:31 +0000697void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000698{
blueswir14c1de732007-07-07 20:45:44 +0000699 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000700 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000701}
702
vincent4d1de872011-06-14 21:56:33 +0000703//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
704#define DEBUGF_BRK(message, args...)
705
ths0da46a62007-10-20 20:23:07 +0000706/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000707abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000708{
blueswir1992f48a2007-10-14 16:27:31 +0000709 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000710 int new_alloc_size;
711
Paul Brook3a0c6c42012-02-09 19:04:27 +0000712 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000713
vincent4d1de872011-06-14 21:56:33 +0000714 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000715 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000716 return target_brk;
717 }
718 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000719 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
720 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000721 return target_brk;
722 }
bellard31e31b82003-02-18 22:55:36 +0000723
vincent4d1de872011-06-14 21:56:33 +0000724 /* If the new brk is less than the highest page reserved to the
725 * target heap allocation, set it and we're almost done... */
726 if (new_brk <= brk_page) {
727 /* Heap contents are initialized to zero, as for anonymous
728 * mapped pages. */
729 if (new_brk > target_brk) {
730 memset(g2h(target_brk), 0, new_brk - target_brk);
731 }
bellard31e31b82003-02-18 22:55:36 +0000732 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000733 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000734 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000735 }
736
Peter Maydell00faf082011-04-18 16:34:24 +0100737 /* We need to allocate more memory after the brk... Note that
738 * we don't use MAP_FIXED because that will map over the top of
739 * any existing mapping (like the one with the host libc or qemu
740 * itself); instead we treat "mapped but at wrong address" as
741 * a failure and unmap again.
742 */
vincent4d1de872011-06-14 21:56:33 +0000743 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000744 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000745 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100746 MAP_ANON|MAP_PRIVATE, 0, 0));
747
748 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200749 /* Heap contents are initialized to zero, as for anonymous
750 * mapped pages. Technically the new pages are already
751 * initialized to zero since they *are* anonymous mapped
752 * pages, however we have to take care with the contents that
753 * come from the remaining part of the previous page: it may
754 * contains garbage data due to a previous heap usage (grown
755 * then shrunken). */
756 memset(g2h(target_brk), 0, brk_page - target_brk);
757
Peter Maydell00faf082011-04-18 16:34:24 +0100758 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000759 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000760 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
761 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100762 return target_brk;
763 } else if (mapped_addr != -1) {
764 /* Mapped but at wrong address, meaning there wasn't actually
765 * enough space for this brk.
766 */
767 target_munmap(mapped_addr, new_alloc_size);
768 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000769 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000770 }
771 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000772 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100773 }
balrog7ab240a2008-04-26 12:17:34 +0000774
Richard Henderson7dd46c02010-05-03 10:07:49 -0700775#if defined(TARGET_ALPHA)
776 /* We (partially) emulate OSF/1 on Alpha, which requires we
777 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100778 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700779#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100780 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000781 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000782}
783
ths26edcf42007-12-09 02:25:24 +0000784static inline abi_long copy_from_user_fdset(fd_set *fds,
785 abi_ulong target_fds_addr,
786 int n)
bellard31e31b82003-02-18 22:55:36 +0000787{
ths26edcf42007-12-09 02:25:24 +0000788 int i, nw, j, k;
789 abi_ulong b, *target_fds;
790
791 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
792 if (!(target_fds = lock_user(VERIFY_READ,
793 target_fds_addr,
794 sizeof(abi_ulong) * nw,
795 1)))
796 return -TARGET_EFAULT;
797
798 FD_ZERO(fds);
799 k = 0;
800 for (i = 0; i < nw; i++) {
801 /* grab the abi_ulong */
802 __get_user(b, &target_fds[i]);
803 for (j = 0; j < TARGET_ABI_BITS; j++) {
804 /* check the bit inside the abi_ulong */
805 if ((b >> j) & 1)
806 FD_SET(k, fds);
807 k++;
bellard31e31b82003-02-18 22:55:36 +0000808 }
bellard31e31b82003-02-18 22:55:36 +0000809 }
ths26edcf42007-12-09 02:25:24 +0000810
811 unlock_user(target_fds, target_fds_addr, 0);
812
813 return 0;
bellard31e31b82003-02-18 22:55:36 +0000814}
815
Mike Frysinger055e0902011-06-03 17:01:49 -0400816static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
817 abi_ulong target_fds_addr,
818 int n)
819{
820 if (target_fds_addr) {
821 if (copy_from_user_fdset(fds, target_fds_addr, n))
822 return -TARGET_EFAULT;
823 *fds_ptr = fds;
824 } else {
825 *fds_ptr = NULL;
826 }
827 return 0;
828}
829
ths26edcf42007-12-09 02:25:24 +0000830static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
831 const fd_set *fds,
832 int n)
bellard31e31b82003-02-18 22:55:36 +0000833{
bellard31e31b82003-02-18 22:55:36 +0000834 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000835 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000836 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000837
ths26edcf42007-12-09 02:25:24 +0000838 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
839 if (!(target_fds = lock_user(VERIFY_WRITE,
840 target_fds_addr,
841 sizeof(abi_ulong) * nw,
842 0)))
843 return -TARGET_EFAULT;
844
845 k = 0;
846 for (i = 0; i < nw; i++) {
847 v = 0;
848 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000849 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000850 k++;
bellard31e31b82003-02-18 22:55:36 +0000851 }
ths26edcf42007-12-09 02:25:24 +0000852 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000853 }
ths26edcf42007-12-09 02:25:24 +0000854
855 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
856
857 return 0;
bellard31e31b82003-02-18 22:55:36 +0000858}
859
bellardc596ed12003-07-13 17:32:31 +0000860#if defined(__alpha__)
861#define HOST_HZ 1024
862#else
863#define HOST_HZ 100
864#endif
865
blueswir1992f48a2007-10-14 16:27:31 +0000866static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000867{
868#if HOST_HZ == TARGET_HZ
869 return ticks;
870#else
871 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
872#endif
873}
874
bellard579a97f2007-11-11 14:26:47 +0000875static inline abi_long host_to_target_rusage(abi_ulong target_addr,
876 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000877{
pbrook53a59602006-03-25 19:31:22 +0000878 struct target_rusage *target_rusage;
879
bellard579a97f2007-11-11 14:26:47 +0000880 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
881 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200882 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
883 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
884 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
885 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
886 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
887 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
888 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
889 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
890 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
891 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
892 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
893 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
894 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
895 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
896 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
897 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
898 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
899 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000900 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000901
902 return 0;
bellardb4091862003-05-16 15:39:34 +0000903}
904
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200905static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900906{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200907 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300908 rlim_t result;
909
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200910 target_rlim_swap = tswapal(target_rlim);
911 if (target_rlim_swap == TARGET_RLIM_INFINITY)
912 return RLIM_INFINITY;
913
914 result = target_rlim_swap;
915 if (target_rlim_swap != (rlim_t)result)
916 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300917
918 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900919}
920
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200921static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900922{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200923 abi_ulong target_rlim_swap;
924 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300925
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200926 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300927 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900928 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300929 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200930 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300931
932 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900933}
934
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300935static inline int target_to_host_resource(int code)
936{
937 switch (code) {
938 case TARGET_RLIMIT_AS:
939 return RLIMIT_AS;
940 case TARGET_RLIMIT_CORE:
941 return RLIMIT_CORE;
942 case TARGET_RLIMIT_CPU:
943 return RLIMIT_CPU;
944 case TARGET_RLIMIT_DATA:
945 return RLIMIT_DATA;
946 case TARGET_RLIMIT_FSIZE:
947 return RLIMIT_FSIZE;
948 case TARGET_RLIMIT_LOCKS:
949 return RLIMIT_LOCKS;
950 case TARGET_RLIMIT_MEMLOCK:
951 return RLIMIT_MEMLOCK;
952 case TARGET_RLIMIT_MSGQUEUE:
953 return RLIMIT_MSGQUEUE;
954 case TARGET_RLIMIT_NICE:
955 return RLIMIT_NICE;
956 case TARGET_RLIMIT_NOFILE:
957 return RLIMIT_NOFILE;
958 case TARGET_RLIMIT_NPROC:
959 return RLIMIT_NPROC;
960 case TARGET_RLIMIT_RSS:
961 return RLIMIT_RSS;
962 case TARGET_RLIMIT_RTPRIO:
963 return RLIMIT_RTPRIO;
964 case TARGET_RLIMIT_SIGPENDING:
965 return RLIMIT_SIGPENDING;
966 case TARGET_RLIMIT_STACK:
967 return RLIMIT_STACK;
968 default:
969 return code;
970 }
971}
972
ths788f5ec2007-12-09 02:37:05 +0000973static inline abi_long copy_from_user_timeval(struct timeval *tv,
974 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000975{
pbrook53a59602006-03-25 19:31:22 +0000976 struct target_timeval *target_tv;
977
ths788f5ec2007-12-09 02:37:05 +0000978 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000979 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000980
981 __get_user(tv->tv_sec, &target_tv->tv_sec);
982 __get_user(tv->tv_usec, &target_tv->tv_usec);
983
984 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000985
986 return 0;
bellard31e31b82003-02-18 22:55:36 +0000987}
988
ths788f5ec2007-12-09 02:37:05 +0000989static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
990 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000991{
pbrook53a59602006-03-25 19:31:22 +0000992 struct target_timeval *target_tv;
993
ths788f5ec2007-12-09 02:37:05 +0000994 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000995 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000996
997 __put_user(tv->tv_sec, &target_tv->tv_sec);
998 __put_user(tv->tv_usec, &target_tv->tv_usec);
999
1000 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001001
1002 return 0;
bellard31e31b82003-02-18 22:55:36 +00001003}
1004
Paul Burtonef4467e2014-06-22 11:25:40 +01001005static inline abi_long copy_from_user_timezone(struct timezone *tz,
1006 abi_ulong target_tz_addr)
1007{
1008 struct target_timezone *target_tz;
1009
1010 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1011 return -TARGET_EFAULT;
1012 }
1013
1014 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1015 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1016
1017 unlock_user_struct(target_tz, target_tz_addr, 0);
1018
1019 return 0;
1020}
1021
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001022#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1023#include <mqueue.h>
1024
aurel3224e10032009-04-15 16:11:43 +00001025static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1026 abi_ulong target_mq_attr_addr)
1027{
1028 struct target_mq_attr *target_mq_attr;
1029
1030 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1031 target_mq_attr_addr, 1))
1032 return -TARGET_EFAULT;
1033
1034 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1035 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1036 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1037 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1038
1039 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1040
1041 return 0;
1042}
1043
1044static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1045 const struct mq_attr *attr)
1046{
1047 struct target_mq_attr *target_mq_attr;
1048
1049 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1050 target_mq_attr_addr, 0))
1051 return -TARGET_EFAULT;
1052
1053 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1054 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1055 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1056 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1057
1058 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1059
1060 return 0;
1061}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001062#endif
bellard31e31b82003-02-18 22:55:36 +00001063
Mike Frysinger055e0902011-06-03 17:01:49 -04001064#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001065/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001066static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001067 abi_ulong rfd_addr, abi_ulong wfd_addr,
1068 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001069{
1070 fd_set rfds, wfds, efds;
1071 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1072 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001073 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001074
Mike Frysinger055e0902011-06-03 17:01:49 -04001075 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1076 if (ret) {
1077 return ret;
pbrook53a59602006-03-25 19:31:22 +00001078 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001079 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1080 if (ret) {
1081 return ret;
pbrook53a59602006-03-25 19:31:22 +00001082 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001083 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1084 if (ret) {
1085 return ret;
pbrook53a59602006-03-25 19:31:22 +00001086 }
ths3b46e622007-09-17 08:09:54 +00001087
ths26edcf42007-12-09 02:25:24 +00001088 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001089 if (copy_from_user_timeval(&tv, target_tv_addr))
1090 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001091 tv_ptr = &tv;
1092 } else {
1093 tv_ptr = NULL;
1094 }
ths26edcf42007-12-09 02:25:24 +00001095
bellard31e31b82003-02-18 22:55:36 +00001096 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001097
ths26edcf42007-12-09 02:25:24 +00001098 if (!is_error(ret)) {
1099 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1100 return -TARGET_EFAULT;
1101 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1102 return -TARGET_EFAULT;
1103 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1104 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001105
ths788f5ec2007-12-09 02:37:05 +00001106 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1107 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001108 }
bellard579a97f2007-11-11 14:26:47 +00001109
bellard31e31b82003-02-18 22:55:36 +00001110 return ret;
1111}
Mike Frysinger055e0902011-06-03 17:01:49 -04001112#endif
bellard31e31b82003-02-18 22:55:36 +00001113
Riku Voipio099d6b02009-05-05 12:10:04 +03001114static abi_long do_pipe2(int host_pipe[], int flags)
1115{
1116#ifdef CONFIG_PIPE2
1117 return pipe2(host_pipe, flags);
1118#else
1119 return -ENOSYS;
1120#endif
1121}
1122
Richard Hendersonfb41a662010-05-03 10:07:52 -07001123static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1124 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001125{
1126 int host_pipe[2];
1127 abi_long ret;
1128 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1129
1130 if (is_error(ret))
1131 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001132
1133 /* Several targets have special calling conventions for the original
1134 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1135 if (!is_pipe2) {
1136#if defined(TARGET_ALPHA)
1137 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1138 return host_pipe[0];
1139#elif defined(TARGET_MIPS)
1140 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1141 return host_pipe[0];
1142#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001143 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001144 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001145#elif defined(TARGET_SPARC)
1146 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1147 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001148#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001149 }
1150
Riku Voipio099d6b02009-05-05 12:10:04 +03001151 if (put_user_s32(host_pipe[0], pipedes)
1152 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1153 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001154 return get_errno(ret);
1155}
1156
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001157static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1158 abi_ulong target_addr,
1159 socklen_t len)
1160{
1161 struct target_ip_mreqn *target_smreqn;
1162
1163 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1164 if (!target_smreqn)
1165 return -TARGET_EFAULT;
1166 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1167 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1168 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001169 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001170 unlock_user(target_smreqn, target_addr, 0);
1171
1172 return 0;
1173}
1174
Laurent Vivier7b36f782015-10-28 21:40:44 +01001175static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001176 abi_ulong target_addr,
1177 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001178{
aurel32607175e2009-04-15 16:11:59 +00001179 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1180 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001181 struct target_sockaddr *target_saddr;
1182
Laurent Vivier7b36f782015-10-28 21:40:44 +01001183 if (fd_trans_target_to_host_addr(fd)) {
1184 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1185 }
1186
bellard579a97f2007-11-11 14:26:47 +00001187 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1188 if (!target_saddr)
1189 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001190
1191 sa_family = tswap16(target_saddr->sa_family);
1192
1193 /* Oops. The caller might send a incomplete sun_path; sun_path
1194 * must be terminated by \0 (see the manual page), but
1195 * unfortunately it is quite common to specify sockaddr_un
1196 * length as "strlen(x->sun_path)" while it should be
1197 * "strlen(...) + 1". We'll fix that here if needed.
1198 * Linux kernel has a similar feature.
1199 */
1200
1201 if (sa_family == AF_UNIX) {
1202 if (len < unix_maxlen && len > 0) {
1203 char *cp = (char*)target_saddr;
1204
1205 if ( cp[len-1] && !cp[len] )
1206 len++;
1207 }
1208 if (len > unix_maxlen)
1209 len = unix_maxlen;
1210 }
1211
pbrook53a59602006-03-25 19:31:22 +00001212 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001213 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001214 if (sa_family == AF_PACKET) {
1215 struct target_sockaddr_ll *lladdr;
1216
1217 lladdr = (struct target_sockaddr_ll *)addr;
1218 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1219 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1220 }
pbrook53a59602006-03-25 19:31:22 +00001221 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001222
1223 return 0;
bellard7854b052003-03-29 17:22:23 +00001224}
1225
bellard579a97f2007-11-11 14:26:47 +00001226static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1227 struct sockaddr *addr,
1228 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001229{
pbrook53a59602006-03-25 19:31:22 +00001230 struct target_sockaddr *target_saddr;
1231
bellard579a97f2007-11-11 14:26:47 +00001232 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1233 if (!target_saddr)
1234 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001235 memcpy(target_saddr, addr, len);
1236 target_saddr->sa_family = tswap16(addr->sa_family);
1237 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001238
1239 return 0;
bellard7854b052003-03-29 17:22:23 +00001240}
1241
bellard5a4a8982007-11-11 17:39:18 +00001242static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1243 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001244{
1245 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001246 abi_long msg_controllen;
1247 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001248 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001249 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001250
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001251 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001252 if (msg_controllen < sizeof (struct target_cmsghdr))
1253 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001254 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001255 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001256 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001257 if (!target_cmsg)
1258 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001259
1260 while (cmsg && target_cmsg) {
1261 void *data = CMSG_DATA(cmsg);
1262 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1263
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001264 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001265 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1266
1267 space += CMSG_SPACE(len);
1268 if (space > msgh->msg_controllen) {
1269 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001270 /* This is a QEMU bug, since we allocated the payload
1271 * area ourselves (unlike overflow in host-to-target
1272 * conversion, which is just the guest giving us a buffer
1273 * that's too small). It can't happen for the payload types
1274 * we currently support; if it becomes an issue in future
1275 * we would need to improve our allocation strategy to
1276 * something more intelligent than "twice the size of the
1277 * target buffer we're reading from".
1278 */
bellard31febb72005-12-18 20:03:27 +00001279 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001280 break;
1281 }
1282
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001283 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1284 cmsg->cmsg_level = SOL_SOCKET;
1285 } else {
1286 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1287 }
bellard7854b052003-03-29 17:22:23 +00001288 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1289 cmsg->cmsg_len = CMSG_LEN(len);
1290
Alex Suykov30b8b682014-12-23 07:52:58 +02001291 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001292 int *fd = (int *)data;
1293 int *target_fd = (int *)target_data;
1294 int i, numfds = len / sizeof(int);
1295
Peter Maydell876e23c2015-05-26 19:46:32 +01001296 for (i = 0; i < numfds; i++) {
1297 __get_user(fd[i], target_fd + i);
1298 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001299 } else if (cmsg->cmsg_level == SOL_SOCKET
1300 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1301 struct ucred *cred = (struct ucred *)data;
1302 struct target_ucred *target_cred =
1303 (struct target_ucred *)target_data;
1304
Peter Maydell876e23c2015-05-26 19:46:32 +01001305 __get_user(cred->pid, &target_cred->pid);
1306 __get_user(cred->uid, &target_cred->uid);
1307 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001308 } else {
1309 gemu_log("Unsupported ancillary data: %d/%d\n",
1310 cmsg->cmsg_level, cmsg->cmsg_type);
1311 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001312 }
1313
1314 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001315 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1316 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001317 }
bellard5a4a8982007-11-11 17:39:18 +00001318 unlock_user(target_cmsg, target_cmsg_addr, 0);
1319 the_end:
bellard7854b052003-03-29 17:22:23 +00001320 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001321 return 0;
bellard7854b052003-03-29 17:22:23 +00001322}
1323
bellard5a4a8982007-11-11 17:39:18 +00001324static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1325 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001326{
1327 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001328 abi_long msg_controllen;
1329 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001330 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001331 socklen_t space = 0;
1332
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001333 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001334 if (msg_controllen < sizeof (struct target_cmsghdr))
1335 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001336 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001337 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001338 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001339 if (!target_cmsg)
1340 return -TARGET_EFAULT;
1341
bellard7854b052003-03-29 17:22:23 +00001342 while (cmsg && target_cmsg) {
1343 void *data = CMSG_DATA(cmsg);
1344 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1345
1346 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001347 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001348
Peter Maydellc2aeb252015-05-26 19:46:31 +01001349 /* We never copy a half-header but may copy half-data;
1350 * this is Linux's behaviour in put_cmsg(). Note that
1351 * truncation here is a guest problem (which we report
1352 * to the guest via the CTRUNC bit), unlike truncation
1353 * in target_to_host_cmsg, which is a QEMU bug.
1354 */
1355 if (msg_controllen < sizeof(struct cmsghdr)) {
1356 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001357 break;
1358 }
1359
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001360 if (cmsg->cmsg_level == SOL_SOCKET) {
1361 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1362 } else {
1363 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1364 }
bellard7854b052003-03-29 17:22:23 +00001365 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001366
Peter Maydellc2aeb252015-05-26 19:46:31 +01001367 tgt_len = TARGET_CMSG_LEN(len);
1368
1369 /* Payload types which need a different size of payload on
1370 * the target must adjust tgt_len here.
1371 */
1372 switch (cmsg->cmsg_level) {
1373 case SOL_SOCKET:
1374 switch (cmsg->cmsg_type) {
1375 case SO_TIMESTAMP:
1376 tgt_len = sizeof(struct target_timeval);
1377 break;
1378 default:
1379 break;
1380 }
1381 default:
1382 break;
1383 }
1384
1385 if (msg_controllen < tgt_len) {
1386 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1387 tgt_len = msg_controllen;
1388 }
1389
1390 /* We must now copy-and-convert len bytes of payload
1391 * into tgt_len bytes of destination space. Bear in mind
1392 * that in both source and destination we may be dealing
1393 * with a truncated value!
1394 */
Huw Davies52b65492014-04-17 14:02:47 +01001395 switch (cmsg->cmsg_level) {
1396 case SOL_SOCKET:
1397 switch (cmsg->cmsg_type) {
1398 case SCM_RIGHTS:
1399 {
1400 int *fd = (int *)data;
1401 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001402 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001403
Peter Maydell876e23c2015-05-26 19:46:32 +01001404 for (i = 0; i < numfds; i++) {
1405 __put_user(fd[i], target_fd + i);
1406 }
Huw Davies52b65492014-04-17 14:02:47 +01001407 break;
1408 }
1409 case SO_TIMESTAMP:
1410 {
1411 struct timeval *tv = (struct timeval *)data;
1412 struct target_timeval *target_tv =
1413 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001414
Peter Maydellc2aeb252015-05-26 19:46:31 +01001415 if (len != sizeof(struct timeval) ||
1416 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001417 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001418 }
Huw Davies52b65492014-04-17 14:02:47 +01001419
1420 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001421 __put_user(tv->tv_sec, &target_tv->tv_sec);
1422 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001423 break;
1424 }
Huw Davies4bc29752014-04-17 14:02:48 +01001425 case SCM_CREDENTIALS:
1426 {
1427 struct ucred *cred = (struct ucred *)data;
1428 struct target_ucred *target_cred =
1429 (struct target_ucred *)target_data;
1430
1431 __put_user(cred->pid, &target_cred->pid);
1432 __put_user(cred->uid, &target_cred->uid);
1433 __put_user(cred->gid, &target_cred->gid);
1434 break;
1435 }
Huw Davies52b65492014-04-17 14:02:47 +01001436 default:
1437 goto unimplemented;
1438 }
1439 break;
1440
1441 default:
1442 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001443 gemu_log("Unsupported ancillary data: %d/%d\n",
1444 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001445 memcpy(target_data, data, MIN(len, tgt_len));
1446 if (tgt_len > len) {
1447 memset(target_data + len, 0, tgt_len - len);
1448 }
bellard7854b052003-03-29 17:22:23 +00001449 }
1450
Peter Maydellc2aeb252015-05-26 19:46:31 +01001451 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001452 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001453 if (msg_controllen < tgt_space) {
1454 tgt_space = msg_controllen;
1455 }
1456 msg_controllen -= tgt_space;
1457 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001458 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001459 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1460 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001461 }
bellard5a4a8982007-11-11 17:39:18 +00001462 unlock_user(target_cmsg, target_cmsg_addr, space);
1463 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001464 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001465 return 0;
bellard7854b052003-03-29 17:22:23 +00001466}
1467
ths0da46a62007-10-20 20:23:07 +00001468/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001469static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001470 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001471{
blueswir1992f48a2007-10-14 16:27:31 +00001472 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001473 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001474 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001475 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001476
bellard8853f862004-02-22 14:57:26 +00001477 switch(level) {
1478 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001479 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001480 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001481 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001482
bellard2f619692007-11-16 10:46:05 +00001483 if (get_user_u32(val, optval_addr))
1484 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001485 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1486 break;
1487 case SOL_IP:
1488 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001489 case IP_TOS:
1490 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001491 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001492 case IP_ROUTER_ALERT:
1493 case IP_RECVOPTS:
1494 case IP_RETOPTS:
1495 case IP_PKTINFO:
1496 case IP_MTU_DISCOVER:
1497 case IP_RECVERR:
1498 case IP_RECVTOS:
1499#ifdef IP_FREEBIND
1500 case IP_FREEBIND:
1501#endif
1502 case IP_MULTICAST_TTL:
1503 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001504 val = 0;
1505 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001506 if (get_user_u32(val, optval_addr))
1507 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001508 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001509 if (get_user_u8(val, optval_addr))
1510 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001511 }
1512 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1513 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001514 case IP_ADD_MEMBERSHIP:
1515 case IP_DROP_MEMBERSHIP:
1516 if (optlen < sizeof (struct target_ip_mreq) ||
1517 optlen > sizeof (struct target_ip_mreqn))
1518 return -TARGET_EINVAL;
1519
1520 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1521 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1522 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1523 break;
1524
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001525 case IP_BLOCK_SOURCE:
1526 case IP_UNBLOCK_SOURCE:
1527 case IP_ADD_SOURCE_MEMBERSHIP:
1528 case IP_DROP_SOURCE_MEMBERSHIP:
1529 if (optlen != sizeof (struct target_ip_mreq_source))
1530 return -TARGET_EINVAL;
1531
1532 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1533 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1534 unlock_user (ip_mreq_source, optval_addr, 0);
1535 break;
1536
bellard8853f862004-02-22 14:57:26 +00001537 default:
1538 goto unimplemented;
1539 }
1540 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001541 case SOL_IPV6:
1542 switch (optname) {
1543 case IPV6_MTU_DISCOVER:
1544 case IPV6_MTU:
1545 case IPV6_V6ONLY:
1546 case IPV6_RECVPKTINFO:
1547 val = 0;
1548 if (optlen < sizeof(uint32_t)) {
1549 return -TARGET_EINVAL;
1550 }
1551 if (get_user_u32(val, optval_addr)) {
1552 return -TARGET_EFAULT;
1553 }
1554 ret = get_errno(setsockopt(sockfd, level, optname,
1555 &val, sizeof(val)));
1556 break;
1557 default:
1558 goto unimplemented;
1559 }
1560 break;
Jing Huang920394d2012-07-24 13:59:23 +00001561 case SOL_RAW:
1562 switch (optname) {
1563 case ICMP_FILTER:
1564 /* struct icmp_filter takes an u32 value */
1565 if (optlen < sizeof(uint32_t)) {
1566 return -TARGET_EINVAL;
1567 }
1568
1569 if (get_user_u32(val, optval_addr)) {
1570 return -TARGET_EFAULT;
1571 }
1572 ret = get_errno(setsockopt(sockfd, level, optname,
1573 &val, sizeof(val)));
1574 break;
1575
1576 default:
1577 goto unimplemented;
1578 }
1579 break;
bellard3532fa72006-06-24 15:06:03 +00001580 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001581 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001582 case TARGET_SO_RCVTIMEO:
1583 {
1584 struct timeval tv;
1585
1586 optname = SO_RCVTIMEO;
1587
1588set_timeout:
1589 if (optlen != sizeof(struct target_timeval)) {
1590 return -TARGET_EINVAL;
1591 }
1592
1593 if (copy_from_user_timeval(&tv, optval_addr)) {
1594 return -TARGET_EFAULT;
1595 }
1596
1597 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1598 &tv, sizeof(tv)));
1599 return ret;
1600 }
1601 case TARGET_SO_SNDTIMEO:
1602 optname = SO_SNDTIMEO;
1603 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001604 case TARGET_SO_ATTACH_FILTER:
1605 {
1606 struct target_sock_fprog *tfprog;
1607 struct target_sock_filter *tfilter;
1608 struct sock_fprog fprog;
1609 struct sock_filter *filter;
1610 int i;
1611
1612 if (optlen != sizeof(*tfprog)) {
1613 return -TARGET_EINVAL;
1614 }
1615 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1616 return -TARGET_EFAULT;
1617 }
1618 if (!lock_user_struct(VERIFY_READ, tfilter,
1619 tswapal(tfprog->filter), 0)) {
1620 unlock_user_struct(tfprog, optval_addr, 1);
1621 return -TARGET_EFAULT;
1622 }
1623
1624 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301625 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001626 if (filter == NULL) {
1627 unlock_user_struct(tfilter, tfprog->filter, 1);
1628 unlock_user_struct(tfprog, optval_addr, 1);
1629 return -TARGET_ENOMEM;
1630 }
1631 for (i = 0; i < fprog.len; i++) {
1632 filter[i].code = tswap16(tfilter[i].code);
1633 filter[i].jt = tfilter[i].jt;
1634 filter[i].jf = tfilter[i].jf;
1635 filter[i].k = tswap32(tfilter[i].k);
1636 }
1637 fprog.filter = filter;
1638
1639 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1640 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301641 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02001642
1643 unlock_user_struct(tfilter, tfprog->filter, 1);
1644 unlock_user_struct(tfprog, optval_addr, 1);
1645 return ret;
1646 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001647 case TARGET_SO_BINDTODEVICE:
1648 {
1649 char *dev_ifname, *addr_ifname;
1650
1651 if (optlen > IFNAMSIZ - 1) {
1652 optlen = IFNAMSIZ - 1;
1653 }
1654 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1655 if (!dev_ifname) {
1656 return -TARGET_EFAULT;
1657 }
1658 optname = SO_BINDTODEVICE;
1659 addr_ifname = alloca(IFNAMSIZ);
1660 memcpy(addr_ifname, dev_ifname, optlen);
1661 addr_ifname[optlen] = 0;
1662 ret = get_errno(setsockopt(sockfd, level, optname, addr_ifname, optlen));
1663 unlock_user (dev_ifname, optval_addr, 0);
1664 return ret;
1665 }
bellard8853f862004-02-22 14:57:26 +00001666 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001667 case TARGET_SO_DEBUG:
1668 optname = SO_DEBUG;
1669 break;
1670 case TARGET_SO_REUSEADDR:
1671 optname = SO_REUSEADDR;
1672 break;
1673 case TARGET_SO_TYPE:
1674 optname = SO_TYPE;
1675 break;
1676 case TARGET_SO_ERROR:
1677 optname = SO_ERROR;
1678 break;
1679 case TARGET_SO_DONTROUTE:
1680 optname = SO_DONTROUTE;
1681 break;
1682 case TARGET_SO_BROADCAST:
1683 optname = SO_BROADCAST;
1684 break;
1685 case TARGET_SO_SNDBUF:
1686 optname = SO_SNDBUF;
1687 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001688 case TARGET_SO_SNDBUFFORCE:
1689 optname = SO_SNDBUFFORCE;
1690 break;
bellard3532fa72006-06-24 15:06:03 +00001691 case TARGET_SO_RCVBUF:
1692 optname = SO_RCVBUF;
1693 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001694 case TARGET_SO_RCVBUFFORCE:
1695 optname = SO_RCVBUFFORCE;
1696 break;
bellard3532fa72006-06-24 15:06:03 +00001697 case TARGET_SO_KEEPALIVE:
1698 optname = SO_KEEPALIVE;
1699 break;
1700 case TARGET_SO_OOBINLINE:
1701 optname = SO_OOBINLINE;
1702 break;
1703 case TARGET_SO_NO_CHECK:
1704 optname = SO_NO_CHECK;
1705 break;
1706 case TARGET_SO_PRIORITY:
1707 optname = SO_PRIORITY;
1708 break;
bellard5e83e8e2005-03-01 22:32:06 +00001709#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001710 case TARGET_SO_BSDCOMPAT:
1711 optname = SO_BSDCOMPAT;
1712 break;
bellard5e83e8e2005-03-01 22:32:06 +00001713#endif
bellard3532fa72006-06-24 15:06:03 +00001714 case TARGET_SO_PASSCRED:
1715 optname = SO_PASSCRED;
1716 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001717 case TARGET_SO_PASSSEC:
1718 optname = SO_PASSSEC;
1719 break;
bellard3532fa72006-06-24 15:06:03 +00001720 case TARGET_SO_TIMESTAMP:
1721 optname = SO_TIMESTAMP;
1722 break;
1723 case TARGET_SO_RCVLOWAT:
1724 optname = SO_RCVLOWAT;
1725 break;
bellard8853f862004-02-22 14:57:26 +00001726 break;
1727 default:
1728 goto unimplemented;
1729 }
bellard3532fa72006-06-24 15:06:03 +00001730 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001731 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001732
bellard2f619692007-11-16 10:46:05 +00001733 if (get_user_u32(val, optval_addr))
1734 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001735 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001736 break;
bellard7854b052003-03-29 17:22:23 +00001737 default:
bellard8853f862004-02-22 14:57:26 +00001738 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001739 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001740 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001741 }
bellard8853f862004-02-22 14:57:26 +00001742 return ret;
bellard7854b052003-03-29 17:22:23 +00001743}
1744
ths0da46a62007-10-20 20:23:07 +00001745/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001746static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001747 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001748{
blueswir1992f48a2007-10-14 16:27:31 +00001749 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001750 int len, val;
1751 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001752
1753 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001754 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001755 level = SOL_SOCKET;
1756 switch (optname) {
1757 /* These don't just return a single integer */
1758 case TARGET_SO_LINGER:
1759 case TARGET_SO_RCVTIMEO:
1760 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001761 case TARGET_SO_PEERNAME:
1762 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001763 case TARGET_SO_PEERCRED: {
1764 struct ucred cr;
1765 socklen_t crlen;
1766 struct target_ucred *tcr;
1767
1768 if (get_user_u32(len, optlen)) {
1769 return -TARGET_EFAULT;
1770 }
1771 if (len < 0) {
1772 return -TARGET_EINVAL;
1773 }
1774
1775 crlen = sizeof(cr);
1776 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1777 &cr, &crlen));
1778 if (ret < 0) {
1779 return ret;
1780 }
1781 if (len > crlen) {
1782 len = crlen;
1783 }
1784 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1785 return -TARGET_EFAULT;
1786 }
1787 __put_user(cr.pid, &tcr->pid);
1788 __put_user(cr.uid, &tcr->uid);
1789 __put_user(cr.gid, &tcr->gid);
1790 unlock_user_struct(tcr, optval_addr, 1);
1791 if (put_user_u32(len, optlen)) {
1792 return -TARGET_EFAULT;
1793 }
1794 break;
1795 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001796 /* Options with 'int' argument. */
1797 case TARGET_SO_DEBUG:
1798 optname = SO_DEBUG;
1799 goto int_case;
1800 case TARGET_SO_REUSEADDR:
1801 optname = SO_REUSEADDR;
1802 goto int_case;
1803 case TARGET_SO_TYPE:
1804 optname = SO_TYPE;
1805 goto int_case;
1806 case TARGET_SO_ERROR:
1807 optname = SO_ERROR;
1808 goto int_case;
1809 case TARGET_SO_DONTROUTE:
1810 optname = SO_DONTROUTE;
1811 goto int_case;
1812 case TARGET_SO_BROADCAST:
1813 optname = SO_BROADCAST;
1814 goto int_case;
1815 case TARGET_SO_SNDBUF:
1816 optname = SO_SNDBUF;
1817 goto int_case;
1818 case TARGET_SO_RCVBUF:
1819 optname = SO_RCVBUF;
1820 goto int_case;
1821 case TARGET_SO_KEEPALIVE:
1822 optname = SO_KEEPALIVE;
1823 goto int_case;
1824 case TARGET_SO_OOBINLINE:
1825 optname = SO_OOBINLINE;
1826 goto int_case;
1827 case TARGET_SO_NO_CHECK:
1828 optname = SO_NO_CHECK;
1829 goto int_case;
1830 case TARGET_SO_PRIORITY:
1831 optname = SO_PRIORITY;
1832 goto int_case;
1833#ifdef SO_BSDCOMPAT
1834 case TARGET_SO_BSDCOMPAT:
1835 optname = SO_BSDCOMPAT;
1836 goto int_case;
1837#endif
1838 case TARGET_SO_PASSCRED:
1839 optname = SO_PASSCRED;
1840 goto int_case;
1841 case TARGET_SO_TIMESTAMP:
1842 optname = SO_TIMESTAMP;
1843 goto int_case;
1844 case TARGET_SO_RCVLOWAT:
1845 optname = SO_RCVLOWAT;
1846 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001847 case TARGET_SO_ACCEPTCONN:
1848 optname = SO_ACCEPTCONN;
1849 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001850 default:
bellard2efbe912005-07-23 15:10:20 +00001851 goto int_case;
1852 }
1853 break;
1854 case SOL_TCP:
1855 /* TCP options all take an 'int' value. */
1856 int_case:
bellard2f619692007-11-16 10:46:05 +00001857 if (get_user_u32(len, optlen))
1858 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001859 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001860 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001861 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001862 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1863 if (ret < 0)
1864 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001865 if (optname == SO_TYPE) {
1866 val = host_to_target_sock_type(val);
1867 }
bellard2efbe912005-07-23 15:10:20 +00001868 if (len > lv)
1869 len = lv;
bellard2f619692007-11-16 10:46:05 +00001870 if (len == 4) {
1871 if (put_user_u32(val, optval_addr))
1872 return -TARGET_EFAULT;
1873 } else {
1874 if (put_user_u8(val, optval_addr))
1875 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001876 }
bellard2f619692007-11-16 10:46:05 +00001877 if (put_user_u32(len, optlen))
1878 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001879 break;
1880 case SOL_IP:
1881 switch(optname) {
1882 case IP_TOS:
1883 case IP_TTL:
1884 case IP_HDRINCL:
1885 case IP_ROUTER_ALERT:
1886 case IP_RECVOPTS:
1887 case IP_RETOPTS:
1888 case IP_PKTINFO:
1889 case IP_MTU_DISCOVER:
1890 case IP_RECVERR:
1891 case IP_RECVTOS:
1892#ifdef IP_FREEBIND
1893 case IP_FREEBIND:
1894#endif
1895 case IP_MULTICAST_TTL:
1896 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001897 if (get_user_u32(len, optlen))
1898 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001899 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001900 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001901 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001902 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1903 if (ret < 0)
1904 return ret;
bellard2efbe912005-07-23 15:10:20 +00001905 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001906 len = 1;
bellard2f619692007-11-16 10:46:05 +00001907 if (put_user_u32(len, optlen)
1908 || put_user_u8(val, optval_addr))
1909 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001910 } else {
bellard2efbe912005-07-23 15:10:20 +00001911 if (len > sizeof(int))
1912 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001913 if (put_user_u32(len, optlen)
1914 || put_user_u32(val, optval_addr))
1915 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001916 }
bellard8853f862004-02-22 14:57:26 +00001917 break;
bellard2efbe912005-07-23 15:10:20 +00001918 default:
thsc02f4992007-12-18 02:39:59 +00001919 ret = -TARGET_ENOPROTOOPT;
1920 break;
bellard8853f862004-02-22 14:57:26 +00001921 }
1922 break;
1923 default:
1924 unimplemented:
1925 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1926 level, optname);
thsc02f4992007-12-18 02:39:59 +00001927 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001928 break;
1929 }
1930 return ret;
bellard7854b052003-03-29 17:22:23 +00001931}
1932
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001933static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1934 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001935{
1936 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001937 struct iovec *vec;
1938 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001939 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001940 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001941 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001942
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001943 if (count == 0) {
1944 errno = 0;
1945 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001946 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001947 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001948 errno = EINVAL;
1949 return NULL;
1950 }
1951
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05301952 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001953 if (vec == NULL) {
1954 errno = ENOMEM;
1955 return NULL;
1956 }
1957
1958 target_vec = lock_user(VERIFY_READ, target_addr,
1959 count * sizeof(struct target_iovec), 1);
1960 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001961 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001962 goto fail2;
1963 }
1964
1965 /* ??? If host page size > target page size, this will result in a
1966 value larger than what we can actually support. */
1967 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1968 total_len = 0;
1969
1970 for (i = 0; i < count; i++) {
1971 abi_ulong base = tswapal(target_vec[i].iov_base);
1972 abi_long len = tswapal(target_vec[i].iov_len);
1973
1974 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001975 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001976 goto fail;
1977 } else if (len == 0) {
1978 /* Zero length pointer is ignored. */
1979 vec[i].iov_base = 0;
1980 } else {
1981 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05001982 /* If the first buffer pointer is bad, this is a fault. But
1983 * subsequent bad buffers will result in a partial write; this
1984 * is realized by filling the vector with null pointers and
1985 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001986 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05001987 if (i == 0) {
1988 err = EFAULT;
1989 goto fail;
1990 } else {
1991 bad_address = true;
1992 }
1993 }
1994 if (bad_address) {
1995 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001996 }
1997 if (len > max_len - total_len) {
1998 len = max_len - total_len;
1999 }
2000 }
2001 vec[i].iov_len = len;
2002 total_len += len;
2003 }
2004
2005 unlock_user(target_vec, target_addr, 0);
2006 return vec;
2007
2008 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002009 while (--i >= 0) {
2010 if (tswapal(target_vec[i].iov_len) > 0) {
2011 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2012 }
2013 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002014 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002015 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302016 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002017 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002018 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002019}
2020
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002021static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2022 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002023{
2024 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002025 int i;
2026
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002027 target_vec = lock_user(VERIFY_READ, target_addr,
2028 count * sizeof(struct target_iovec), 1);
2029 if (target_vec) {
2030 for (i = 0; i < count; i++) {
2031 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002032 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002033 if (len < 0) {
2034 break;
2035 }
balrogd732dcb2008-10-28 10:21:03 +00002036 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2037 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002038 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002039 }
bellard579a97f2007-11-11 14:26:47 +00002040
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302041 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002042}
2043
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002044static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002045{
2046 int host_type = 0;
2047 int target_type = *type;
2048
2049 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2050 case TARGET_SOCK_DGRAM:
2051 host_type = SOCK_DGRAM;
2052 break;
2053 case TARGET_SOCK_STREAM:
2054 host_type = SOCK_STREAM;
2055 break;
2056 default:
2057 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2058 break;
2059 }
2060 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002061#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002062 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002063#else
2064 return -TARGET_EINVAL;
2065#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002066 }
2067 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002068#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002069 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002070#elif !defined(O_NONBLOCK)
2071 return -TARGET_EINVAL;
2072#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002073 }
2074 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002075 return 0;
2076}
2077
2078/* Try to emulate socket type flags after socket creation. */
2079static int sock_flags_fixup(int fd, int target_type)
2080{
2081#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2082 if (target_type & TARGET_SOCK_NONBLOCK) {
2083 int flags = fcntl(fd, F_GETFL);
2084 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2085 close(fd);
2086 return -TARGET_EINVAL;
2087 }
2088 }
2089#endif
2090 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002091}
2092
Laurent Vivier0cf22722015-10-28 21:40:45 +01002093static abi_long packet_target_to_host_sockaddr(void *host_addr,
2094 abi_ulong target_addr,
2095 socklen_t len)
2096{
2097 struct sockaddr *addr = host_addr;
2098 struct target_sockaddr *target_saddr;
2099
2100 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2101 if (!target_saddr) {
2102 return -TARGET_EFAULT;
2103 }
2104
2105 memcpy(addr, target_saddr, len);
2106 addr->sa_family = tswap16(target_saddr->sa_family);
2107 /* spkt_protocol is big-endian */
2108
2109 unlock_user(target_saddr, target_addr, 0);
2110 return 0;
2111}
2112
2113static TargetFdTrans target_packet_trans = {
2114 .target_to_host_addr = packet_target_to_host_sockaddr,
2115};
2116
ths0da46a62007-10-20 20:23:07 +00002117/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002118static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002119{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002120 int target_type = type;
2121 int ret;
2122
2123 ret = target_to_host_sock_type(&type);
2124 if (ret) {
2125 return ret;
2126 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002127
balrog12bc92a2007-10-30 21:06:14 +00002128 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07002129 return -TARGET_EAFNOSUPPORT;
Laurent Vivierff626f22015-10-28 21:40:42 +01002130
2131 if (domain == AF_PACKET ||
2132 (domain == AF_INET && type == SOCK_PACKET)) {
2133 protocol = tswap16(protocol);
2134 }
2135
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002136 ret = get_errno(socket(domain, type, protocol));
2137 if (ret >= 0) {
2138 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002139 if (type == SOCK_PACKET) {
2140 /* Manage an obsolete case :
2141 * if socket type is SOCK_PACKET, bind by name
2142 */
2143 fd_trans_register(ret, &target_packet_trans);
2144 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002145 }
2146 return ret;
bellard3532fa72006-06-24 15:06:03 +00002147}
2148
ths0da46a62007-10-20 20:23:07 +00002149/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002150static abi_long do_bind(int sockfd, abi_ulong target_addr,
2151 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002152{
aurel328f7aeaf2009-01-30 19:47:57 +00002153 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002154 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002155
Blue Swirl38724252010-09-18 05:53:14 +00002156 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002157 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002158 }
aurel328f7aeaf2009-01-30 19:47:57 +00002159
aurel32607175e2009-04-15 16:11:59 +00002160 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002161
Laurent Vivier7b36f782015-10-28 21:40:44 +01002162 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002163 if (ret)
2164 return ret;
2165
bellard3532fa72006-06-24 15:06:03 +00002166 return get_errno(bind(sockfd, addr, addrlen));
2167}
2168
ths0da46a62007-10-20 20:23:07 +00002169/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002170static abi_long do_connect(int sockfd, abi_ulong target_addr,
2171 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002172{
aurel328f7aeaf2009-01-30 19:47:57 +00002173 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002174 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002175
Blue Swirl38724252010-09-18 05:53:14 +00002176 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002177 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002178 }
aurel328f7aeaf2009-01-30 19:47:57 +00002179
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002180 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002181
Laurent Vivier7b36f782015-10-28 21:40:44 +01002182 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002183 if (ret)
2184 return ret;
2185
bellard3532fa72006-06-24 15:06:03 +00002186 return get_errno(connect(sockfd, addr, addrlen));
2187}
2188
Alexander Graff19e00d2014-03-02 19:36:42 +00002189/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2190static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2191 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002192{
balrog6de645c2008-10-28 10:26:29 +00002193 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002194 struct msghdr msg;
2195 int count;
2196 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002197 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002198
bellard3532fa72006-06-24 15:06:03 +00002199 if (msgp->msg_name) {
2200 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002201 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002202 ret = target_to_host_sockaddr(fd, msg.msg_name,
2203 tswapal(msgp->msg_name),
2204 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002205 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002206 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002207 }
bellard3532fa72006-06-24 15:06:03 +00002208 } else {
2209 msg.msg_name = NULL;
2210 msg.msg_namelen = 0;
2211 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002212 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002213 msg.msg_control = alloca(msg.msg_controllen);
2214 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002215
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002216 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002217 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002218 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2219 target_vec, count, send);
2220 if (vec == NULL) {
2221 ret = -host_to_target_errno(errno);
2222 goto out2;
2223 }
bellard3532fa72006-06-24 15:06:03 +00002224 msg.msg_iovlen = count;
2225 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002226
bellard3532fa72006-06-24 15:06:03 +00002227 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002228 ret = target_to_host_cmsg(&msg, msgp);
2229 if (ret == 0)
2230 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002231 } else {
2232 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002233 if (!is_error(ret)) {
2234 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002235 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002236 if (!is_error(ret)) {
2237 msgp->msg_namelen = tswap32(msg.msg_namelen);
2238 if (msg.msg_name != NULL) {
2239 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2240 msg.msg_name, msg.msg_namelen);
2241 if (ret) {
2242 goto out;
2243 }
2244 }
2245
balrog6de645c2008-10-28 10:26:29 +00002246 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002247 }
balrog6de645c2008-10-28 10:26:29 +00002248 }
bellard3532fa72006-06-24 15:06:03 +00002249 }
Jing Huangca619062012-07-24 13:58:02 +00002250
2251out:
bellard3532fa72006-06-24 15:06:03 +00002252 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002253out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002254 return ret;
2255}
2256
2257static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2258 int flags, int send)
2259{
2260 abi_long ret;
2261 struct target_msghdr *msgp;
2262
2263 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2264 msgp,
2265 target_msg,
2266 send ? 1 : 0)) {
2267 return -TARGET_EFAULT;
2268 }
2269 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002270 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002271 return ret;
2272}
2273
Alexander Graff19e00d2014-03-02 19:36:42 +00002274#ifdef TARGET_NR_sendmmsg
2275/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2276 * so it might not have this *mmsg-specific flag either.
2277 */
2278#ifndef MSG_WAITFORONE
2279#define MSG_WAITFORONE 0x10000
2280#endif
2281
2282static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2283 unsigned int vlen, unsigned int flags,
2284 int send)
2285{
2286 struct target_mmsghdr *mmsgp;
2287 abi_long ret = 0;
2288 int i;
2289
2290 if (vlen > UIO_MAXIOV) {
2291 vlen = UIO_MAXIOV;
2292 }
2293
2294 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2295 if (!mmsgp) {
2296 return -TARGET_EFAULT;
2297 }
2298
2299 for (i = 0; i < vlen; i++) {
2300 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2301 if (is_error(ret)) {
2302 break;
2303 }
2304 mmsgp[i].msg_len = tswap32(ret);
2305 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2306 if (flags & MSG_WAITFORONE) {
2307 flags |= MSG_DONTWAIT;
2308 }
2309 }
2310
2311 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2312
2313 /* Return number of datagrams sent if we sent any at all;
2314 * otherwise return the error.
2315 */
2316 if (i) {
2317 return i;
2318 }
2319 return ret;
2320}
2321#endif
2322
Peter Maydella94b4982013-02-08 04:35:04 +00002323/* If we don't have a system accept4() then just call accept.
2324 * The callsites to do_accept4() will ensure that they don't
2325 * pass a non-zero flags argument in this config.
2326 */
2327#ifndef CONFIG_ACCEPT4
2328static inline int accept4(int sockfd, struct sockaddr *addr,
2329 socklen_t *addrlen, int flags)
2330{
2331 assert(flags == 0);
2332 return accept(sockfd, addr, addrlen);
2333}
2334#endif
2335
2336/* do_accept4() Must return target values and target errnos. */
2337static abi_long do_accept4(int fd, abi_ulong target_addr,
2338 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002339{
bellard2f619692007-11-16 10:46:05 +00002340 socklen_t addrlen;
2341 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002342 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002343 int host_flags;
2344
2345 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002346
Peter Maydella94b4982013-02-08 04:35:04 +00002347 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002348 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002349 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002350
2351 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002352 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002353 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002354
Blue Swirl38724252010-09-18 05:53:14 +00002355 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002356 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002357 }
aurel328f7aeaf2009-01-30 19:47:57 +00002358
Arnaud Patard917507b2009-06-19 10:44:45 +03002359 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2360 return -TARGET_EINVAL;
2361
bellard2f619692007-11-16 10:46:05 +00002362 addr = alloca(addrlen);
2363
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002364 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002365 if (!is_error(ret)) {
2366 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002367 if (put_user_u32(addrlen, target_addrlen_addr))
2368 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002369 }
2370 return ret;
2371}
2372
ths0da46a62007-10-20 20:23:07 +00002373/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002374static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002375 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002376{
bellard2f619692007-11-16 10:46:05 +00002377 socklen_t addrlen;
2378 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002379 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002380
bellard2f619692007-11-16 10:46:05 +00002381 if (get_user_u32(addrlen, target_addrlen_addr))
2382 return -TARGET_EFAULT;
2383
Blue Swirl38724252010-09-18 05:53:14 +00002384 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002385 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002386 }
aurel328f7aeaf2009-01-30 19:47:57 +00002387
Arnaud Patard917507b2009-06-19 10:44:45 +03002388 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2389 return -TARGET_EFAULT;
2390
bellard2f619692007-11-16 10:46:05 +00002391 addr = alloca(addrlen);
2392
pbrook1be9e1d2006-11-19 15:26:04 +00002393 ret = get_errno(getpeername(fd, addr, &addrlen));
2394 if (!is_error(ret)) {
2395 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002396 if (put_user_u32(addrlen, target_addrlen_addr))
2397 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002398 }
2399 return ret;
2400}
2401
ths0da46a62007-10-20 20:23:07 +00002402/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002403static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002404 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002405{
bellard2f619692007-11-16 10:46:05 +00002406 socklen_t addrlen;
2407 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002408 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002409
bellard2f619692007-11-16 10:46:05 +00002410 if (get_user_u32(addrlen, target_addrlen_addr))
2411 return -TARGET_EFAULT;
2412
Blue Swirl38724252010-09-18 05:53:14 +00002413 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002414 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002415 }
aurel328f7aeaf2009-01-30 19:47:57 +00002416
Arnaud Patard917507b2009-06-19 10:44:45 +03002417 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2418 return -TARGET_EFAULT;
2419
bellard2f619692007-11-16 10:46:05 +00002420 addr = alloca(addrlen);
2421
pbrook1be9e1d2006-11-19 15:26:04 +00002422 ret = get_errno(getsockname(fd, addr, &addrlen));
2423 if (!is_error(ret)) {
2424 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002425 if (put_user_u32(addrlen, target_addrlen_addr))
2426 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002427 }
2428 return ret;
2429}
2430
ths0da46a62007-10-20 20:23:07 +00002431/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002432static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002433 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002434{
2435 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002436 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002437
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002438 target_to_host_sock_type(&type);
2439
pbrook1be9e1d2006-11-19 15:26:04 +00002440 ret = get_errno(socketpair(domain, type, protocol, tab));
2441 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002442 if (put_user_s32(tab[0], target_tab_addr)
2443 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2444 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002445 }
2446 return ret;
2447}
2448
ths0da46a62007-10-20 20:23:07 +00002449/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002450static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2451 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002452{
2453 void *addr;
2454 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002455 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002456
Blue Swirl38724252010-09-18 05:53:14 +00002457 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002458 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002459 }
aurel328f7aeaf2009-01-30 19:47:57 +00002460
bellard579a97f2007-11-11 14:26:47 +00002461 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2462 if (!host_msg)
2463 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002464 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002465 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002466 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002467 if (ret) {
2468 unlock_user(host_msg, msg, 0);
2469 return ret;
2470 }
pbrook1be9e1d2006-11-19 15:26:04 +00002471 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2472 } else {
2473 ret = get_errno(send(fd, host_msg, len, flags));
2474 }
2475 unlock_user(host_msg, msg, 0);
2476 return ret;
2477}
2478
ths0da46a62007-10-20 20:23:07 +00002479/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002480static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2481 abi_ulong target_addr,
2482 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002483{
2484 socklen_t addrlen;
2485 void *addr;
2486 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002487 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002488
bellard579a97f2007-11-11 14:26:47 +00002489 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2490 if (!host_msg)
2491 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002492 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002493 if (get_user_u32(addrlen, target_addrlen)) {
2494 ret = -TARGET_EFAULT;
2495 goto fail;
2496 }
Blue Swirl38724252010-09-18 05:53:14 +00002497 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002498 ret = -TARGET_EINVAL;
2499 goto fail;
2500 }
pbrook1be9e1d2006-11-19 15:26:04 +00002501 addr = alloca(addrlen);
2502 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2503 } else {
2504 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002505 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002506 }
2507 if (!is_error(ret)) {
2508 if (target_addr) {
2509 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002510 if (put_user_u32(addrlen, target_addrlen)) {
2511 ret = -TARGET_EFAULT;
2512 goto fail;
2513 }
pbrook1be9e1d2006-11-19 15:26:04 +00002514 }
2515 unlock_user(host_msg, msg, len);
2516 } else {
bellard2f619692007-11-16 10:46:05 +00002517fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002518 unlock_user(host_msg, msg, 0);
2519 }
2520 return ret;
2521}
2522
j_mayer32407102007-09-26 23:01:49 +00002523#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002524/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002525static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002526{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002527 static const unsigned ac[] = { /* number of arguments per call */
2528 [SOCKOP_socket] = 3, /* domain, type, protocol */
2529 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2530 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2531 [SOCKOP_listen] = 2, /* sockfd, backlog */
2532 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2533 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2534 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2535 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2536 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2537 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2538 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2539 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2540 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2541 [SOCKOP_shutdown] = 2, /* sockfd, how */
2542 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2543 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2544 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2545 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2546 };
2547 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002548
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002549 /* first, collect the arguments in a[] according to ac[] */
2550 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2551 unsigned i;
2552 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2553 for (i = 0; i < ac[num]; ++i) {
2554 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002555 return -TARGET_EFAULT;
2556 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002557 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002558 }
bellard2f619692007-11-16 10:46:05 +00002559
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002560 /* now when we have the args, actually handle the call */
2561 switch (num) {
2562 case SOCKOP_socket: /* domain, type, protocol */
2563 return do_socket(a[0], a[1], a[2]);
2564 case SOCKOP_bind: /* sockfd, addr, addrlen */
2565 return do_bind(a[0], a[1], a[2]);
2566 case SOCKOP_connect: /* sockfd, addr, addrlen */
2567 return do_connect(a[0], a[1], a[2]);
2568 case SOCKOP_listen: /* sockfd, backlog */
2569 return get_errno(listen(a[0], a[1]));
2570 case SOCKOP_accept: /* sockfd, addr, addrlen */
2571 return do_accept4(a[0], a[1], a[2], 0);
2572 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2573 return do_accept4(a[0], a[1], a[2], a[3]);
2574 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2575 return do_getsockname(a[0], a[1], a[2]);
2576 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2577 return do_getpeername(a[0], a[1], a[2]);
2578 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2579 return do_socketpair(a[0], a[1], a[2], a[3]);
2580 case SOCKOP_send: /* sockfd, msg, len, flags */
2581 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2582 case SOCKOP_recv: /* sockfd, msg, len, flags */
2583 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2584 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2585 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2586 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2587 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2588 case SOCKOP_shutdown: /* sockfd, how */
2589 return get_errno(shutdown(a[0], a[1]));
2590 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2591 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2592 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2593 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2594 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2595 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2596 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2597 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002598 default:
2599 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002600 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002601 }
bellard31e31b82003-02-18 22:55:36 +00002602}
j_mayer32407102007-09-26 23:01:49 +00002603#endif
bellard31e31b82003-02-18 22:55:36 +00002604
bellard8853f862004-02-22 14:57:26 +00002605#define N_SHM_REGIONS 32
2606
2607static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002608 abi_ulong start;
2609 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002610} shm_regions[N_SHM_REGIONS];
2611
ths3eb6b042007-06-03 14:26:27 +00002612struct target_semid_ds
2613{
2614 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002615 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002616#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002617 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002618#endif
blueswir1992f48a2007-10-14 16:27:31 +00002619 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002620#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002621 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002622#endif
blueswir1992f48a2007-10-14 16:27:31 +00002623 abi_ulong sem_nsems;
2624 abi_ulong __unused3;
2625 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002626};
2627
bellard579a97f2007-11-11 14:26:47 +00002628static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2629 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002630{
2631 struct target_ipc_perm *target_ip;
2632 struct target_semid_ds *target_sd;
2633
bellard579a97f2007-11-11 14:26:47 +00002634 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2635 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002636 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002637 host_ip->__key = tswap32(target_ip->__key);
2638 host_ip->uid = tswap32(target_ip->uid);
2639 host_ip->gid = tswap32(target_ip->gid);
2640 host_ip->cuid = tswap32(target_ip->cuid);
2641 host_ip->cgid = tswap32(target_ip->cgid);
2642#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2643 host_ip->mode = tswap32(target_ip->mode);
2644#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002645 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002646#endif
2647#if defined(TARGET_PPC)
2648 host_ip->__seq = tswap32(target_ip->__seq);
2649#else
2650 host_ip->__seq = tswap16(target_ip->__seq);
2651#endif
ths3eb6b042007-06-03 14:26:27 +00002652 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002653 return 0;
ths3eb6b042007-06-03 14:26:27 +00002654}
2655
bellard579a97f2007-11-11 14:26:47 +00002656static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2657 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002658{
2659 struct target_ipc_perm *target_ip;
2660 struct target_semid_ds *target_sd;
2661
bellard579a97f2007-11-11 14:26:47 +00002662 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2663 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002664 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002665 target_ip->__key = tswap32(host_ip->__key);
2666 target_ip->uid = tswap32(host_ip->uid);
2667 target_ip->gid = tswap32(host_ip->gid);
2668 target_ip->cuid = tswap32(host_ip->cuid);
2669 target_ip->cgid = tswap32(host_ip->cgid);
2670#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2671 target_ip->mode = tswap32(host_ip->mode);
2672#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002673 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002674#endif
2675#if defined(TARGET_PPC)
2676 target_ip->__seq = tswap32(host_ip->__seq);
2677#else
2678 target_ip->__seq = tswap16(host_ip->__seq);
2679#endif
ths3eb6b042007-06-03 14:26:27 +00002680 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002681 return 0;
ths3eb6b042007-06-03 14:26:27 +00002682}
2683
bellard579a97f2007-11-11 14:26:47 +00002684static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2685 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002686{
2687 struct target_semid_ds *target_sd;
2688
bellard579a97f2007-11-11 14:26:47 +00002689 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2690 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002691 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2692 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002693 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2694 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2695 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002696 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002697 return 0;
ths3eb6b042007-06-03 14:26:27 +00002698}
2699
bellard579a97f2007-11-11 14:26:47 +00002700static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2701 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002702{
2703 struct target_semid_ds *target_sd;
2704
bellard579a97f2007-11-11 14:26:47 +00002705 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2706 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002707 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002708 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002709 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2710 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2711 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002712 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002713 return 0;
ths3eb6b042007-06-03 14:26:27 +00002714}
2715
aurel32e5289082009-04-18 16:16:12 +00002716struct target_seminfo {
2717 int semmap;
2718 int semmni;
2719 int semmns;
2720 int semmnu;
2721 int semmsl;
2722 int semopm;
2723 int semume;
2724 int semusz;
2725 int semvmx;
2726 int semaem;
2727};
2728
2729static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2730 struct seminfo *host_seminfo)
2731{
2732 struct target_seminfo *target_seminfo;
2733 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2734 return -TARGET_EFAULT;
2735 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2736 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2737 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2738 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2739 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2740 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2741 __put_user(host_seminfo->semume, &target_seminfo->semume);
2742 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2743 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2744 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2745 unlock_user_struct(target_seminfo, target_addr, 1);
2746 return 0;
2747}
2748
thsfa294812007-02-02 22:05:00 +00002749union semun {
2750 int val;
ths3eb6b042007-06-03 14:26:27 +00002751 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002752 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002753 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002754};
2755
ths3eb6b042007-06-03 14:26:27 +00002756union target_semun {
2757 int val;
aurel32e5289082009-04-18 16:16:12 +00002758 abi_ulong buf;
2759 abi_ulong array;
2760 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002761};
2762
aurel32e5289082009-04-18 16:16:12 +00002763static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2764 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002765{
aurel32e5289082009-04-18 16:16:12 +00002766 int nsems;
2767 unsigned short *array;
2768 union semun semun;
2769 struct semid_ds semid_ds;
2770 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002771
aurel32e5289082009-04-18 16:16:12 +00002772 semun.buf = &semid_ds;
2773
2774 ret = semctl(semid, 0, IPC_STAT, semun);
2775 if (ret == -1)
2776 return get_errno(ret);
2777
2778 nsems = semid_ds.sem_nsems;
2779
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302780 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00002781 if (!*host_array) {
2782 return -TARGET_ENOMEM;
2783 }
aurel32e5289082009-04-18 16:16:12 +00002784 array = lock_user(VERIFY_READ, target_addr,
2785 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002786 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302787 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002788 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002789 }
aurel32e5289082009-04-18 16:16:12 +00002790
2791 for(i=0; i<nsems; i++) {
2792 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002793 }
aurel32e5289082009-04-18 16:16:12 +00002794 unlock_user(array, target_addr, 0);
2795
bellard579a97f2007-11-11 14:26:47 +00002796 return 0;
ths3eb6b042007-06-03 14:26:27 +00002797}
2798
aurel32e5289082009-04-18 16:16:12 +00002799static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2800 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002801{
aurel32e5289082009-04-18 16:16:12 +00002802 int nsems;
2803 unsigned short *array;
2804 union semun semun;
2805 struct semid_ds semid_ds;
2806 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002807
aurel32e5289082009-04-18 16:16:12 +00002808 semun.buf = &semid_ds;
2809
2810 ret = semctl(semid, 0, IPC_STAT, semun);
2811 if (ret == -1)
2812 return get_errno(ret);
2813
2814 nsems = semid_ds.sem_nsems;
2815
2816 array = lock_user(VERIFY_WRITE, target_addr,
2817 nsems*sizeof(unsigned short), 0);
2818 if (!array)
2819 return -TARGET_EFAULT;
2820
2821 for(i=0; i<nsems; i++) {
2822 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002823 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302824 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002825 unlock_user(array, target_addr, 1);
2826
bellard579a97f2007-11-11 14:26:47 +00002827 return 0;
ths3eb6b042007-06-03 14:26:27 +00002828}
2829
aurel32e5289082009-04-18 16:16:12 +00002830static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01002831 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00002832{
Stefan Weild1c002b2015-02-08 15:40:58 +01002833 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00002834 union semun arg;
2835 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302836 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002837 struct seminfo seminfo;
2838 abi_long ret = -TARGET_EINVAL;
2839 abi_long err;
2840 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002841
2842 switch( cmd ) {
2843 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002844 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002845 /* In 64 bit cross-endian situations, we will erroneously pick up
2846 * the wrong half of the union for the "val" element. To rectify
2847 * this, the entire 8-byte structure is byteswapped, followed by
2848 * a swap of the 4 byte val field. In other cases, the data is
2849 * already in proper host byte order. */
2850 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2851 target_su.buf = tswapal(target_su.buf);
2852 arg.val = tswap32(target_su.val);
2853 } else {
2854 arg.val = target_su.val;
2855 }
aurel32e5289082009-04-18 16:16:12 +00002856 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002857 break;
2858 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002859 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002860 err = target_to_host_semarray(semid, &array, target_su.array);
2861 if (err)
2862 return err;
2863 arg.array = array;
2864 ret = get_errno(semctl(semid, semnum, cmd, arg));
2865 err = host_to_target_semarray(semid, target_su.array, &array);
2866 if (err)
2867 return err;
ths3eb6b042007-06-03 14:26:27 +00002868 break;
2869 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002870 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002871 case SEM_STAT:
2872 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2873 if (err)
2874 return err;
2875 arg.buf = &dsarg;
2876 ret = get_errno(semctl(semid, semnum, cmd, arg));
2877 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2878 if (err)
2879 return err;
ths3eb6b042007-06-03 14:26:27 +00002880 break;
aurel32e5289082009-04-18 16:16:12 +00002881 case IPC_INFO:
2882 case SEM_INFO:
2883 arg.__buf = &seminfo;
2884 ret = get_errno(semctl(semid, semnum, cmd, arg));
2885 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2886 if (err)
2887 return err;
2888 break;
2889 case IPC_RMID:
2890 case GETPID:
2891 case GETNCNT:
2892 case GETZCNT:
2893 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2894 break;
ths3eb6b042007-06-03 14:26:27 +00002895 }
2896
2897 return ret;
2898}
2899
aurel32e5289082009-04-18 16:16:12 +00002900struct target_sembuf {
2901 unsigned short sem_num;
2902 short sem_op;
2903 short sem_flg;
2904};
2905
2906static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2907 abi_ulong target_addr,
2908 unsigned nsops)
2909{
2910 struct target_sembuf *target_sembuf;
2911 int i;
2912
2913 target_sembuf = lock_user(VERIFY_READ, target_addr,
2914 nsops*sizeof(struct target_sembuf), 1);
2915 if (!target_sembuf)
2916 return -TARGET_EFAULT;
2917
2918 for(i=0; i<nsops; i++) {
2919 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2920 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2921 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2922 }
2923
2924 unlock_user(target_sembuf, target_addr, 0);
2925
2926 return 0;
2927}
2928
2929static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2930{
2931 struct sembuf sops[nsops];
2932
2933 if (target_to_host_sembuf(sops, ptr, nsops))
2934 return -TARGET_EFAULT;
2935
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002936 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002937}
2938
ths1bc012f2007-06-03 14:27:49 +00002939struct target_msqid_ds
2940{
aurel321c54ff92008-10-13 21:08:44 +00002941 struct target_ipc_perm msg_perm;
2942 abi_ulong msg_stime;
2943#if TARGET_ABI_BITS == 32
2944 abi_ulong __unused1;
2945#endif
2946 abi_ulong msg_rtime;
2947#if TARGET_ABI_BITS == 32
2948 abi_ulong __unused2;
2949#endif
2950 abi_ulong msg_ctime;
2951#if TARGET_ABI_BITS == 32
2952 abi_ulong __unused3;
2953#endif
2954 abi_ulong __msg_cbytes;
2955 abi_ulong msg_qnum;
2956 abi_ulong msg_qbytes;
2957 abi_ulong msg_lspid;
2958 abi_ulong msg_lrpid;
2959 abi_ulong __unused4;
2960 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002961};
2962
bellard579a97f2007-11-11 14:26:47 +00002963static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2964 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002965{
2966 struct target_msqid_ds *target_md;
2967
bellard579a97f2007-11-11 14:26:47 +00002968 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2969 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002970 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2971 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002972 host_md->msg_stime = tswapal(target_md->msg_stime);
2973 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2974 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2975 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2976 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2977 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2978 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2979 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002980 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002981 return 0;
ths1bc012f2007-06-03 14:27:49 +00002982}
2983
bellard579a97f2007-11-11 14:26:47 +00002984static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2985 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002986{
2987 struct target_msqid_ds *target_md;
2988
bellard579a97f2007-11-11 14:26:47 +00002989 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2990 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002991 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2992 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002993 target_md->msg_stime = tswapal(host_md->msg_stime);
2994 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2995 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2996 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2997 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2998 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2999 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3000 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003001 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003002 return 0;
ths1bc012f2007-06-03 14:27:49 +00003003}
3004
aurel321c54ff92008-10-13 21:08:44 +00003005struct target_msginfo {
3006 int msgpool;
3007 int msgmap;
3008 int msgmax;
3009 int msgmnb;
3010 int msgmni;
3011 int msgssz;
3012 int msgtql;
3013 unsigned short int msgseg;
3014};
3015
3016static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3017 struct msginfo *host_msginfo)
3018{
3019 struct target_msginfo *target_msginfo;
3020 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3021 return -TARGET_EFAULT;
3022 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3023 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3024 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3025 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3026 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3027 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3028 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3029 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3030 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003031 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003032}
3033
3034static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003035{
3036 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003037 struct msginfo msginfo;
3038 abi_long ret = -TARGET_EINVAL;
3039
3040 cmd &= 0xff;
3041
3042 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003043 case IPC_STAT:
3044 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003045 case MSG_STAT:
3046 if (target_to_host_msqid_ds(&dsarg,ptr))
3047 return -TARGET_EFAULT;
3048 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3049 if (host_to_target_msqid_ds(ptr,&dsarg))
3050 return -TARGET_EFAULT;
3051 break;
3052 case IPC_RMID:
3053 ret = get_errno(msgctl(msgid, cmd, NULL));
3054 break;
3055 case IPC_INFO:
3056 case MSG_INFO:
3057 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3058 if (host_to_target_msginfo(ptr, &msginfo))
3059 return -TARGET_EFAULT;
3060 break;
ths1bc012f2007-06-03 14:27:49 +00003061 }
aurel321c54ff92008-10-13 21:08:44 +00003062
ths1bc012f2007-06-03 14:27:49 +00003063 return ret;
3064}
3065
3066struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003067 abi_long mtype;
3068 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003069};
3070
blueswir1992f48a2007-10-14 16:27:31 +00003071static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003072 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003073{
3074 struct target_msgbuf *target_mb;
3075 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003076 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003077
Tom Mustaedcc5f92014-08-12 13:53:37 -05003078 if (msgsz < 0) {
3079 return -TARGET_EINVAL;
3080 }
3081
bellard579a97f2007-11-11 14:26:47 +00003082 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3083 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303084 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003085 if (!host_mb) {
3086 unlock_user_struct(target_mb, msgp, 0);
3087 return -TARGET_ENOMEM;
3088 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003089 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003090 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00003091 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303092 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003093 unlock_user_struct(target_mb, msgp, 0);
3094
3095 return ret;
3096}
3097
blueswir1992f48a2007-10-14 16:27:31 +00003098static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00003099 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003100 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003101{
3102 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003103 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003104 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003105 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003106
bellard579a97f2007-11-11 14:26:47 +00003107 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3108 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003109
Jim Meyering0d07fe42012-08-22 13:55:53 +02003110 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003111 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003112
bellard579a97f2007-11-11 14:26:47 +00003113 if (ret > 0) {
3114 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3115 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3116 if (!target_mtext) {
3117 ret = -TARGET_EFAULT;
3118 goto end;
3119 }
aurel321c54ff92008-10-13 21:08:44 +00003120 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003121 unlock_user(target_mtext, target_mtext_addr, ret);
3122 }
aurel321c54ff92008-10-13 21:08:44 +00003123
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003124 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003125
bellard579a97f2007-11-11 14:26:47 +00003126end:
3127 if (target_mb)
3128 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003129 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003130 return ret;
3131}
3132
Riku Voipio88a8c982009-04-03 10:42:00 +03003133static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3134 abi_ulong target_addr)
3135{
3136 struct target_shmid_ds *target_sd;
3137
3138 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3139 return -TARGET_EFAULT;
3140 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3141 return -TARGET_EFAULT;
3142 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3143 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3144 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3145 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3146 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3147 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3148 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3149 unlock_user_struct(target_sd, target_addr, 0);
3150 return 0;
3151}
3152
3153static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3154 struct shmid_ds *host_sd)
3155{
3156 struct target_shmid_ds *target_sd;
3157
3158 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3159 return -TARGET_EFAULT;
3160 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3161 return -TARGET_EFAULT;
3162 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3163 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3164 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3165 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3166 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3167 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3168 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3169 unlock_user_struct(target_sd, target_addr, 1);
3170 return 0;
3171}
3172
3173struct target_shminfo {
3174 abi_ulong shmmax;
3175 abi_ulong shmmin;
3176 abi_ulong shmmni;
3177 abi_ulong shmseg;
3178 abi_ulong shmall;
3179};
3180
3181static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3182 struct shminfo *host_shminfo)
3183{
3184 struct target_shminfo *target_shminfo;
3185 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3186 return -TARGET_EFAULT;
3187 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3188 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3189 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3190 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3191 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3192 unlock_user_struct(target_shminfo, target_addr, 1);
3193 return 0;
3194}
3195
3196struct target_shm_info {
3197 int used_ids;
3198 abi_ulong shm_tot;
3199 abi_ulong shm_rss;
3200 abi_ulong shm_swp;
3201 abi_ulong swap_attempts;
3202 abi_ulong swap_successes;
3203};
3204
3205static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3206 struct shm_info *host_shm_info)
3207{
3208 struct target_shm_info *target_shm_info;
3209 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3210 return -TARGET_EFAULT;
3211 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3212 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3213 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3214 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3215 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3216 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3217 unlock_user_struct(target_shm_info, target_addr, 1);
3218 return 0;
3219}
3220
3221static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3222{
3223 struct shmid_ds dsarg;
3224 struct shminfo shminfo;
3225 struct shm_info shm_info;
3226 abi_long ret = -TARGET_EINVAL;
3227
3228 cmd &= 0xff;
3229
3230 switch(cmd) {
3231 case IPC_STAT:
3232 case IPC_SET:
3233 case SHM_STAT:
3234 if (target_to_host_shmid_ds(&dsarg, buf))
3235 return -TARGET_EFAULT;
3236 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3237 if (host_to_target_shmid_ds(buf, &dsarg))
3238 return -TARGET_EFAULT;
3239 break;
3240 case IPC_INFO:
3241 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3242 if (host_to_target_shminfo(buf, &shminfo))
3243 return -TARGET_EFAULT;
3244 break;
3245 case SHM_INFO:
3246 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3247 if (host_to_target_shm_info(buf, &shm_info))
3248 return -TARGET_EFAULT;
3249 break;
3250 case IPC_RMID:
3251 case SHM_LOCK:
3252 case SHM_UNLOCK:
3253 ret = get_errno(shmctl(shmid, cmd, NULL));
3254 break;
3255 }
3256
3257 return ret;
3258}
3259
3260static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3261{
3262 abi_long raddr;
3263 void *host_raddr;
3264 struct shmid_ds shm_info;
3265 int i,ret;
3266
3267 /* find out the length of the shared memory segment */
3268 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3269 if (is_error(ret)) {
3270 /* can't get length, bail out */
3271 return ret;
3272 }
3273
3274 mmap_lock();
3275
3276 if (shmaddr)
3277 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3278 else {
3279 abi_ulong mmap_start;
3280
3281 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3282
3283 if (mmap_start == -1) {
3284 errno = ENOMEM;
3285 host_raddr = (void *)-1;
3286 } else
3287 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3288 }
3289
3290 if (host_raddr == (void *)-1) {
3291 mmap_unlock();
3292 return get_errno((long)host_raddr);
3293 }
3294 raddr=h2g((unsigned long)host_raddr);
3295
3296 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3297 PAGE_VALID | PAGE_READ |
3298 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3299
3300 for (i = 0; i < N_SHM_REGIONS; i++) {
3301 if (shm_regions[i].start == 0) {
3302 shm_regions[i].start = raddr;
3303 shm_regions[i].size = shm_info.shm_segsz;
3304 break;
3305 }
3306 }
3307
3308 mmap_unlock();
3309 return raddr;
3310
3311}
3312
3313static inline abi_long do_shmdt(abi_ulong shmaddr)
3314{
3315 int i;
3316
3317 for (i = 0; i < N_SHM_REGIONS; ++i) {
3318 if (shm_regions[i].start == shmaddr) {
3319 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003320 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003321 break;
3322 }
3323 }
3324
3325 return get_errno(shmdt(g2h(shmaddr)));
3326}
3327
aurel321c54ff92008-10-13 21:08:44 +00003328#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003329/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003330/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003331static abi_long do_ipc(unsigned int call, abi_long first,
3332 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003333 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003334{
3335 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003336 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003337
3338 version = call >> 16;
3339 call &= 0xffff;
3340
3341 switch (call) {
thsfa294812007-02-02 22:05:00 +00003342 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003343 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003344 break;
3345
3346 case IPCOP_semget:
3347 ret = get_errno(semget(first, second, third));
3348 break;
3349
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003350 case IPCOP_semctl: {
3351 /* The semun argument to semctl is passed by value, so dereference the
3352 * ptr argument. */
3353 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003354 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01003355 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00003356 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003357 }
thsd96372e2007-02-02 22:05:44 +00003358
aurel321c54ff92008-10-13 21:08:44 +00003359 case IPCOP_msgget:
3360 ret = get_errno(msgget(first, second));
3361 break;
thsd96372e2007-02-02 22:05:44 +00003362
aurel321c54ff92008-10-13 21:08:44 +00003363 case IPCOP_msgsnd:
3364 ret = do_msgsnd(first, ptr, second, third);
3365 break;
thsd96372e2007-02-02 22:05:44 +00003366
aurel321c54ff92008-10-13 21:08:44 +00003367 case IPCOP_msgctl:
3368 ret = do_msgctl(first, second, ptr);
3369 break;
thsd96372e2007-02-02 22:05:44 +00003370
aurel321c54ff92008-10-13 21:08:44 +00003371 case IPCOP_msgrcv:
3372 switch (version) {
3373 case 0:
3374 {
3375 struct target_ipc_kludge {
3376 abi_long msgp;
3377 abi_long msgtyp;
3378 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003379
aurel321c54ff92008-10-13 21:08:44 +00003380 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3381 ret = -TARGET_EFAULT;
3382 break;
ths1bc012f2007-06-03 14:27:49 +00003383 }
aurel321c54ff92008-10-13 21:08:44 +00003384
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003385 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003386
3387 unlock_user_struct(tmp, ptr, 0);
3388 break;
3389 }
3390 default:
3391 ret = do_msgrcv(first, ptr, second, fifth, third);
3392 }
3393 break;
thsd96372e2007-02-02 22:05:44 +00003394
bellard8853f862004-02-22 14:57:26 +00003395 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003396 switch (version) {
3397 default:
bellard5a4a8982007-11-11 17:39:18 +00003398 {
3399 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003400 raddr = do_shmat(first, ptr, second);
3401 if (is_error(raddr))
3402 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003403 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003404 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003405 break;
3406 }
3407 case 1:
3408 ret = -TARGET_EINVAL;
3409 break;
bellard5a4a8982007-11-11 17:39:18 +00003410 }
bellard8853f862004-02-22 14:57:26 +00003411 break;
3412 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003413 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003414 break;
3415
3416 case IPCOP_shmget:
3417 /* IPC_* flag values are the same on all linux platforms */
3418 ret = get_errno(shmget(first, second, third));
3419 break;
3420
3421 /* IPC_* and SHM_* command values are the same on all linux platforms */
3422 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003423 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003424 break;
3425 default:
j_mayer32407102007-09-26 23:01:49 +00003426 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003427 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003428 break;
3429 }
3430 return ret;
3431}
j_mayer32407102007-09-26 23:01:49 +00003432#endif
bellard8853f862004-02-22 14:57:26 +00003433
bellard31e31b82003-02-18 22:55:36 +00003434/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003435
Blue Swirl001faf32009-05-13 17:53:17 +00003436#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003437#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3438enum {
3439#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02003440STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00003441};
3442#undef STRUCT
3443#undef STRUCT_SPECIAL
3444
Blue Swirl001faf32009-05-13 17:53:17 +00003445#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003446#define STRUCT_SPECIAL(name)
3447#include "syscall_types.h"
3448#undef STRUCT
3449#undef STRUCT_SPECIAL
3450
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003451typedef struct IOCTLEntry IOCTLEntry;
3452
3453typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003454 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003455
3456struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08003457 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00003458 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003459 const char *name;
3460 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003461 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003462 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003463};
bellard31e31b82003-02-18 22:55:36 +00003464
3465#define IOC_R 0x0001
3466#define IOC_W 0x0002
3467#define IOC_RW (IOC_R | IOC_W)
3468
3469#define MAX_STRUCT_SIZE 4096
3470
Peter Maydelldace20d2011-01-10 13:11:24 +00003471#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003472/* So fiemap access checks don't overflow on 32 bit systems.
3473 * This is very slightly smaller than the limit imposed by
3474 * the underlying kernel.
3475 */
3476#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3477 / sizeof(struct fiemap_extent))
3478
3479static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003480 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00003481{
3482 /* The parameter for this ioctl is a struct fiemap followed
3483 * by an array of struct fiemap_extent whose size is set
3484 * in fiemap->fm_extent_count. The array is filled in by the
3485 * ioctl.
3486 */
3487 int target_size_in, target_size_out;
3488 struct fiemap *fm;
3489 const argtype *arg_type = ie->arg_type;
3490 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3491 void *argptr, *p;
3492 abi_long ret;
3493 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3494 uint32_t outbufsz;
3495 int free_fm = 0;
3496
3497 assert(arg_type[0] == TYPE_PTR);
3498 assert(ie->access == IOC_RW);
3499 arg_type++;
3500 target_size_in = thunk_type_size(arg_type, 0);
3501 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3502 if (!argptr) {
3503 return -TARGET_EFAULT;
3504 }
3505 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3506 unlock_user(argptr, arg, 0);
3507 fm = (struct fiemap *)buf_temp;
3508 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3509 return -TARGET_EINVAL;
3510 }
3511
3512 outbufsz = sizeof (*fm) +
3513 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3514
3515 if (outbufsz > MAX_STRUCT_SIZE) {
3516 /* We can't fit all the extents into the fixed size buffer.
3517 * Allocate one that is large enough and use it instead.
3518 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303519 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00003520 if (!fm) {
3521 return -TARGET_ENOMEM;
3522 }
3523 memcpy(fm, buf_temp, sizeof(struct fiemap));
3524 free_fm = 1;
3525 }
3526 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3527 if (!is_error(ret)) {
3528 target_size_out = target_size_in;
3529 /* An extent_count of 0 means we were only counting the extents
3530 * so there are no structs to copy
3531 */
3532 if (fm->fm_extent_count != 0) {
3533 target_size_out += fm->fm_mapped_extents * extent_size;
3534 }
3535 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3536 if (!argptr) {
3537 ret = -TARGET_EFAULT;
3538 } else {
3539 /* Convert the struct fiemap */
3540 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3541 if (fm->fm_extent_count != 0) {
3542 p = argptr + target_size_in;
3543 /* ...and then all the struct fiemap_extents */
3544 for (i = 0; i < fm->fm_mapped_extents; i++) {
3545 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3546 THUNK_TARGET);
3547 p += extent_size;
3548 }
3549 }
3550 unlock_user(argptr, arg, target_size_out);
3551 }
3552 }
3553 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303554 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00003555 }
3556 return ret;
3557}
Peter Maydelldace20d2011-01-10 13:11:24 +00003558#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003559
Laurent Vivier059c2f22011-03-30 00:12:12 +02003560static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003561 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02003562{
3563 const argtype *arg_type = ie->arg_type;
3564 int target_size;
3565 void *argptr;
3566 int ret;
3567 struct ifconf *host_ifconf;
3568 uint32_t outbufsz;
3569 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3570 int target_ifreq_size;
3571 int nb_ifreq;
3572 int free_buf = 0;
3573 int i;
3574 int target_ifc_len;
3575 abi_long target_ifc_buf;
3576 int host_ifc_len;
3577 char *host_ifc_buf;
3578
3579 assert(arg_type[0] == TYPE_PTR);
3580 assert(ie->access == IOC_RW);
3581
3582 arg_type++;
3583 target_size = thunk_type_size(arg_type, 0);
3584
3585 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3586 if (!argptr)
3587 return -TARGET_EFAULT;
3588 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3589 unlock_user(argptr, arg, 0);
3590
3591 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3592 target_ifc_len = host_ifconf->ifc_len;
3593 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3594
3595 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3596 nb_ifreq = target_ifc_len / target_ifreq_size;
3597 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3598
3599 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3600 if (outbufsz > MAX_STRUCT_SIZE) {
3601 /* We can't fit all the extents into the fixed size buffer.
3602 * Allocate one that is large enough and use it instead.
3603 */
3604 host_ifconf = malloc(outbufsz);
3605 if (!host_ifconf) {
3606 return -TARGET_ENOMEM;
3607 }
3608 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3609 free_buf = 1;
3610 }
3611 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3612
3613 host_ifconf->ifc_len = host_ifc_len;
3614 host_ifconf->ifc_buf = host_ifc_buf;
3615
3616 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3617 if (!is_error(ret)) {
3618 /* convert host ifc_len to target ifc_len */
3619
3620 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3621 target_ifc_len = nb_ifreq * target_ifreq_size;
3622 host_ifconf->ifc_len = target_ifc_len;
3623
3624 /* restore target ifc_buf */
3625
3626 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3627
3628 /* copy struct ifconf to target user */
3629
3630 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3631 if (!argptr)
3632 return -TARGET_EFAULT;
3633 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3634 unlock_user(argptr, arg, target_size);
3635
3636 /* copy ifreq[] to target user */
3637
3638 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3639 for (i = 0; i < nb_ifreq ; i++) {
3640 thunk_convert(argptr + i * target_ifreq_size,
3641 host_ifc_buf + i * sizeof(struct ifreq),
3642 ifreq_arg_type, THUNK_TARGET);
3643 }
3644 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3645 }
3646
3647 if (free_buf) {
3648 free(host_ifconf);
3649 }
3650
3651 return ret;
3652}
3653
Alexander Graf56e904e2012-01-31 18:42:06 +01003654static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003655 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01003656{
3657 void *argptr;
3658 struct dm_ioctl *host_dm;
3659 abi_long guest_data;
3660 uint32_t guest_data_size;
3661 int target_size;
3662 const argtype *arg_type = ie->arg_type;
3663 abi_long ret;
3664 void *big_buf = NULL;
3665 char *host_data;
3666
3667 arg_type++;
3668 target_size = thunk_type_size(arg_type, 0);
3669 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3670 if (!argptr) {
3671 ret = -TARGET_EFAULT;
3672 goto out;
3673 }
3674 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3675 unlock_user(argptr, arg, 0);
3676
3677 /* buf_temp is too small, so fetch things into a bigger buffer */
3678 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3679 memcpy(big_buf, buf_temp, target_size);
3680 buf_temp = big_buf;
3681 host_dm = big_buf;
3682
3683 guest_data = arg + host_dm->data_start;
3684 if ((guest_data - arg) < 0) {
3685 ret = -EINVAL;
3686 goto out;
3687 }
3688 guest_data_size = host_dm->data_size - host_dm->data_start;
3689 host_data = (char*)host_dm + host_dm->data_start;
3690
3691 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3692 switch (ie->host_cmd) {
3693 case DM_REMOVE_ALL:
3694 case DM_LIST_DEVICES:
3695 case DM_DEV_CREATE:
3696 case DM_DEV_REMOVE:
3697 case DM_DEV_SUSPEND:
3698 case DM_DEV_STATUS:
3699 case DM_DEV_WAIT:
3700 case DM_TABLE_STATUS:
3701 case DM_TABLE_CLEAR:
3702 case DM_TABLE_DEPS:
3703 case DM_LIST_VERSIONS:
3704 /* no input data */
3705 break;
3706 case DM_DEV_RENAME:
3707 case DM_DEV_SET_GEOMETRY:
3708 /* data contains only strings */
3709 memcpy(host_data, argptr, guest_data_size);
3710 break;
3711 case DM_TARGET_MSG:
3712 memcpy(host_data, argptr, guest_data_size);
3713 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3714 break;
3715 case DM_TABLE_LOAD:
3716 {
3717 void *gspec = argptr;
3718 void *cur_data = host_data;
3719 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3720 int spec_size = thunk_type_size(arg_type, 0);
3721 int i;
3722
3723 for (i = 0; i < host_dm->target_count; i++) {
3724 struct dm_target_spec *spec = cur_data;
3725 uint32_t next;
3726 int slen;
3727
3728 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3729 slen = strlen((char*)gspec + spec_size) + 1;
3730 next = spec->next;
3731 spec->next = sizeof(*spec) + slen;
3732 strcpy((char*)&spec[1], gspec + spec_size);
3733 gspec += next;
3734 cur_data += spec->next;
3735 }
3736 break;
3737 }
3738 default:
3739 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08003740 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003741 goto out;
3742 }
3743 unlock_user(argptr, guest_data, 0);
3744
3745 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3746 if (!is_error(ret)) {
3747 guest_data = arg + host_dm->data_start;
3748 guest_data_size = host_dm->data_size - host_dm->data_start;
3749 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3750 switch (ie->host_cmd) {
3751 case DM_REMOVE_ALL:
3752 case DM_DEV_CREATE:
3753 case DM_DEV_REMOVE:
3754 case DM_DEV_RENAME:
3755 case DM_DEV_SUSPEND:
3756 case DM_DEV_STATUS:
3757 case DM_TABLE_LOAD:
3758 case DM_TABLE_CLEAR:
3759 case DM_TARGET_MSG:
3760 case DM_DEV_SET_GEOMETRY:
3761 /* no return data */
3762 break;
3763 case DM_LIST_DEVICES:
3764 {
3765 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3766 uint32_t remaining_data = guest_data_size;
3767 void *cur_data = argptr;
3768 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3769 int nl_size = 12; /* can't use thunk_size due to alignment */
3770
3771 while (1) {
3772 uint32_t next = nl->next;
3773 if (next) {
3774 nl->next = nl_size + (strlen(nl->name) + 1);
3775 }
3776 if (remaining_data < nl->next) {
3777 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3778 break;
3779 }
3780 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3781 strcpy(cur_data + nl_size, nl->name);
3782 cur_data += nl->next;
3783 remaining_data -= nl->next;
3784 if (!next) {
3785 break;
3786 }
3787 nl = (void*)nl + next;
3788 }
3789 break;
3790 }
3791 case DM_DEV_WAIT:
3792 case DM_TABLE_STATUS:
3793 {
3794 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3795 void *cur_data = argptr;
3796 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3797 int spec_size = thunk_type_size(arg_type, 0);
3798 int i;
3799
3800 for (i = 0; i < host_dm->target_count; i++) {
3801 uint32_t next = spec->next;
3802 int slen = strlen((char*)&spec[1]) + 1;
3803 spec->next = (cur_data - argptr) + spec_size + slen;
3804 if (guest_data_size < spec->next) {
3805 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3806 break;
3807 }
3808 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3809 strcpy(cur_data + spec_size, (char*)&spec[1]);
3810 cur_data = argptr + spec->next;
3811 spec = (void*)host_dm + host_dm->data_start + next;
3812 }
3813 break;
3814 }
3815 case DM_TABLE_DEPS:
3816 {
3817 void *hdata = (void*)host_dm + host_dm->data_start;
3818 int count = *(uint32_t*)hdata;
3819 uint64_t *hdev = hdata + 8;
3820 uint64_t *gdev = argptr + 8;
3821 int i;
3822
3823 *(uint32_t*)argptr = tswap32(count);
3824 for (i = 0; i < count; i++) {
3825 *gdev = tswap64(*hdev);
3826 gdev++;
3827 hdev++;
3828 }
3829 break;
3830 }
3831 case DM_LIST_VERSIONS:
3832 {
3833 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3834 uint32_t remaining_data = guest_data_size;
3835 void *cur_data = argptr;
3836 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3837 int vers_size = thunk_type_size(arg_type, 0);
3838
3839 while (1) {
3840 uint32_t next = vers->next;
3841 if (next) {
3842 vers->next = vers_size + (strlen(vers->name) + 1);
3843 }
3844 if (remaining_data < vers->next) {
3845 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3846 break;
3847 }
3848 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3849 strcpy(cur_data + vers_size, vers->name);
3850 cur_data += vers->next;
3851 remaining_data -= vers->next;
3852 if (!next) {
3853 break;
3854 }
3855 vers = (void*)vers + next;
3856 }
3857 break;
3858 }
3859 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08003860 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01003861 ret = -TARGET_EINVAL;
3862 goto out;
3863 }
3864 unlock_user(argptr, guest_data, guest_data_size);
3865
3866 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3867 if (!argptr) {
3868 ret = -TARGET_EFAULT;
3869 goto out;
3870 }
3871 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3872 unlock_user(argptr, arg, target_size);
3873 }
3874out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003875 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003876 return ret;
3877}
3878
Alexander Grafa59b5e32014-08-22 13:15:50 +02003879static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003880 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02003881{
3882 void *argptr;
3883 int target_size;
3884 const argtype *arg_type = ie->arg_type;
3885 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3886 abi_long ret;
3887
3888 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3889 struct blkpg_partition host_part;
3890
3891 /* Read and convert blkpg */
3892 arg_type++;
3893 target_size = thunk_type_size(arg_type, 0);
3894 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3895 if (!argptr) {
3896 ret = -TARGET_EFAULT;
3897 goto out;
3898 }
3899 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3900 unlock_user(argptr, arg, 0);
3901
3902 switch (host_blkpg->op) {
3903 case BLKPG_ADD_PARTITION:
3904 case BLKPG_DEL_PARTITION:
3905 /* payload is struct blkpg_partition */
3906 break;
3907 default:
3908 /* Unknown opcode */
3909 ret = -TARGET_EINVAL;
3910 goto out;
3911 }
3912
3913 /* Read and convert blkpg->data */
3914 arg = (abi_long)(uintptr_t)host_blkpg->data;
3915 target_size = thunk_type_size(part_arg_type, 0);
3916 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3917 if (!argptr) {
3918 ret = -TARGET_EFAULT;
3919 goto out;
3920 }
3921 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3922 unlock_user(argptr, arg, 0);
3923
3924 /* Swizzle the data pointer to our local copy and call! */
3925 host_blkpg->data = &host_part;
3926 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3927
3928out:
3929 return ret;
3930}
3931
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003932static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003933 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003934{
3935 const argtype *arg_type = ie->arg_type;
3936 const StructEntry *se;
3937 const argtype *field_types;
3938 const int *dst_offsets, *src_offsets;
3939 int target_size;
3940 void *argptr;
3941 abi_ulong *target_rt_dev_ptr;
3942 unsigned long *host_rt_dev_ptr;
3943 abi_long ret;
3944 int i;
3945
3946 assert(ie->access == IOC_W);
3947 assert(*arg_type == TYPE_PTR);
3948 arg_type++;
3949 assert(*arg_type == TYPE_STRUCT);
3950 target_size = thunk_type_size(arg_type, 0);
3951 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3952 if (!argptr) {
3953 return -TARGET_EFAULT;
3954 }
3955 arg_type++;
3956 assert(*arg_type == (int)STRUCT_rtentry);
3957 se = struct_entries + *arg_type++;
3958 assert(se->convert[0] == NULL);
3959 /* convert struct here to be able to catch rt_dev string */
3960 field_types = se->field_types;
3961 dst_offsets = se->field_offsets[THUNK_HOST];
3962 src_offsets = se->field_offsets[THUNK_TARGET];
3963 for (i = 0; i < se->nb_fields; i++) {
3964 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3965 assert(*field_types == TYPE_PTRVOID);
3966 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3967 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3968 if (*target_rt_dev_ptr != 0) {
3969 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3970 tswapal(*target_rt_dev_ptr));
3971 if (!*host_rt_dev_ptr) {
3972 unlock_user(argptr, arg, 0);
3973 return -TARGET_EFAULT;
3974 }
3975 } else {
3976 *host_rt_dev_ptr = 0;
3977 }
3978 field_types++;
3979 continue;
3980 }
3981 field_types = thunk_convert(buf_temp + dst_offsets[i],
3982 argptr + src_offsets[i],
3983 field_types, THUNK_HOST);
3984 }
3985 unlock_user(argptr, arg, 0);
3986
3987 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3988 if (*host_rt_dev_ptr != 0) {
3989 unlock_user((void *)*host_rt_dev_ptr,
3990 *target_rt_dev_ptr, 0);
3991 }
3992 return ret;
3993}
3994
Paul Burtonca56f5b2014-06-22 11:25:47 +01003995static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02003996 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01003997{
3998 int sig = target_to_host_signal(arg);
3999 return get_errno(ioctl(fd, ie->host_cmd, sig));
4000}
4001
blueswir19f106a72008-10-05 10:52:52 +00004002static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004003#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004004 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4005#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4006 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004007#include "ioctls.h"
4008 { 0, 0, },
4009};
4010
pbrook53a59602006-03-25 19:31:22 +00004011/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004012/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004013static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004014{
4015 const IOCTLEntry *ie;
4016 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004017 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004018 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004019 int target_size;
4020 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004021
4022 ie = ioctl_entries;
4023 for(;;) {
4024 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004025 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004026 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004027 }
4028 if (ie->target_cmd == cmd)
4029 break;
4030 ie++;
4031 }
4032 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004033#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004034 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004035#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004036 if (ie->do_ioctl) {
4037 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4038 }
4039
bellard31e31b82003-02-18 22:55:36 +00004040 switch(arg_type[0]) {
4041 case TYPE_NULL:
4042 /* no argument */
4043 ret = get_errno(ioctl(fd, ie->host_cmd));
4044 break;
4045 case TYPE_PTRVOID:
4046 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004047 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4048 break;
4049 case TYPE_PTR:
4050 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004051 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004052 switch(ie->access) {
4053 case IOC_R:
4054 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4055 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004056 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4057 if (!argptr)
4058 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004059 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4060 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004061 }
4062 break;
4063 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004064 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4065 if (!argptr)
4066 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004067 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4068 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004069 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4070 break;
4071 default:
4072 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004073 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4074 if (!argptr)
4075 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004076 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4077 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004078 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4079 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004080 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4081 if (!argptr)
4082 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004083 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4084 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004085 }
4086 break;
4087 }
4088 break;
4089 default:
j_mayer32407102007-09-26 23:01:49 +00004090 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4091 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004092 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004093 break;
4094 }
4095 return ret;
4096}
4097
blueswir1b39bc502008-10-05 10:51:10 +00004098static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004099 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4100 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4101 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4102 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4103 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4104 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4105 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4106 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4107 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4108 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4109 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4110 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4111 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4112 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4113 { 0, 0, 0, 0 }
4114};
4115
blueswir1b39bc502008-10-05 10:51:10 +00004116static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004117 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4118 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4119 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4120 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4121 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4122 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4123 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4124 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4125 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4126 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4127 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4128 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4129 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4130 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4131 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4132 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4133 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4134 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4135 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4136 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4137 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4138 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4139 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4140 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4141 { 0, 0, 0, 0 }
4142};
4143
blueswir1b39bc502008-10-05 10:51:10 +00004144static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004145 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4146 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4147 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4148 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4149 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4150 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4151 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4152 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4153 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4154 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4155 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4156 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4157 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4158 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4159 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4160 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4161 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4162 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4163 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4164 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4165 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4166 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4167 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4168 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4169 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4170 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4171 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4172 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4173 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4174 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4175 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4176 { 0, 0, 0, 0 }
4177};
4178
blueswir1b39bc502008-10-05 10:51:10 +00004179static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004180 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4181 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4182 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4183 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4184 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4185 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4186 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4187 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4188 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4189 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4190 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4191 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4192 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4193 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4194 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4195 { 0, 0, 0, 0 }
4196};
4197
4198static void target_to_host_termios (void *dst, const void *src)
4199{
4200 struct host_termios *host = dst;
4201 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004202
ths5fafdf22007-09-16 21:08:06 +00004203 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004204 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004205 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004206 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004207 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004208 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004209 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004210 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4211 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004212
Arnaud Patard44607122009-04-21 17:39:08 +03004213 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004214 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4215 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004216 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004217 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004218 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004219 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004220 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004221 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004222 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004223 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4224 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004225 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4226 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4227 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4228 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4229 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004230 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004231}
ths3b46e622007-09-17 08:09:54 +00004232
bellard31e31b82003-02-18 22:55:36 +00004233static void host_to_target_termios (void *dst, const void *src)
4234{
4235 struct target_termios *target = dst;
4236 const struct host_termios *host = src;
4237
ths5fafdf22007-09-16 21:08:06 +00004238 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004239 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004240 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004241 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004242 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004243 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004244 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004245 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4246 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004247
Arnaud Patard44607122009-04-21 17:39:08 +03004248 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004249 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4250 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4251 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4252 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4253 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4254 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4255 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4256 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4257 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4258 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4259 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4260 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4261 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4262 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4263 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4264 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4265 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4266}
4267
blueswir18e853dc2008-10-05 10:49:32 +00004268static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004269 .convert = { host_to_target_termios, target_to_host_termios },
4270 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4271 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4272};
4273
bellard5286db72003-06-05 00:57:30 +00004274static bitmask_transtbl mmap_flags_tbl[] = {
4275 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4276 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4277 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4278 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4279 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4280 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4281 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4282 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004283 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4284 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004285 { 0, 0, 0, 0 }
4286};
4287
bellard2ab83ea2003-06-15 19:56:46 +00004288#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004289
4290/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004291static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004292
bellard03acab62007-11-11 14:57:14 +00004293static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004294{
4295 int size;
pbrook53a59602006-03-25 19:31:22 +00004296 void *p;
bellard6dbad632003-03-16 18:05:05 +00004297
4298 if (!ldt_table)
4299 return 0;
4300 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4301 if (size > bytecount)
4302 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004303 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4304 if (!p)
bellard03acab62007-11-11 14:57:14 +00004305 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004306 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004307 memcpy(p, ldt_table, size);
4308 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004309 return size;
4310}
4311
4312/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004313static abi_long write_ldt(CPUX86State *env,
4314 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004315{
4316 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004317 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004318 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004319 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004320 uint32_t *lp, entry_1, entry_2;
4321
4322 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004323 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004324 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004325 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004326 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004327 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004328 ldt_info.limit = tswap32(target_ldt_info->limit);
4329 ldt_info.flags = tswap32(target_ldt_info->flags);
4330 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004331
bellard6dbad632003-03-16 18:05:05 +00004332 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004333 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004334 seg_32bit = ldt_info.flags & 1;
4335 contents = (ldt_info.flags >> 1) & 3;
4336 read_exec_only = (ldt_info.flags >> 3) & 1;
4337 limit_in_pages = (ldt_info.flags >> 4) & 1;
4338 seg_not_present = (ldt_info.flags >> 5) & 1;
4339 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004340#ifdef TARGET_ABI32
4341 lm = 0;
4342#else
4343 lm = (ldt_info.flags >> 7) & 1;
4344#endif
bellard6dbad632003-03-16 18:05:05 +00004345 if (contents == 3) {
4346 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004347 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004348 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004349 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004350 }
4351 /* allocate the LDT */
4352 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004353 env->ldt.base = target_mmap(0,
4354 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4355 PROT_READ|PROT_WRITE,
4356 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4357 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004358 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004359 memset(g2h(env->ldt.base), 0,
4360 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004361 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004362 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004363 }
4364
4365 /* NOTE: same code as Linux kernel */
4366 /* Allow LDTs to be cleared by the user. */
4367 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4368 if (oldmode ||
4369 (contents == 0 &&
4370 read_exec_only == 1 &&
4371 seg_32bit == 0 &&
4372 limit_in_pages == 0 &&
4373 seg_not_present == 1 &&
4374 useable == 0 )) {
4375 entry_1 = 0;
4376 entry_2 = 0;
4377 goto install;
4378 }
4379 }
ths3b46e622007-09-17 08:09:54 +00004380
bellard6dbad632003-03-16 18:05:05 +00004381 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4382 (ldt_info.limit & 0x0ffff);
4383 entry_2 = (ldt_info.base_addr & 0xff000000) |
4384 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4385 (ldt_info.limit & 0xf0000) |
4386 ((read_exec_only ^ 1) << 9) |
4387 (contents << 10) |
4388 ((seg_not_present ^ 1) << 15) |
4389 (seg_32bit << 22) |
4390 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004391 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004392 0x7000;
4393 if (!oldmode)
4394 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004395
bellard6dbad632003-03-16 18:05:05 +00004396 /* Install the new entry ... */
4397install:
4398 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4399 lp[0] = tswap32(entry_1);
4400 lp[1] = tswap32(entry_2);
4401 return 0;
4402}
4403
4404/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004405static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4406 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004407{
bellard03acab62007-11-11 14:57:14 +00004408 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004409
bellard6dbad632003-03-16 18:05:05 +00004410 switch (func) {
4411 case 0:
4412 ret = read_ldt(ptr, bytecount);
4413 break;
4414 case 1:
4415 ret = write_ldt(env, ptr, bytecount, 1);
4416 break;
4417 case 0x11:
4418 ret = write_ldt(env, ptr, bytecount, 0);
4419 break;
bellard03acab62007-11-11 14:57:14 +00004420 default:
4421 ret = -TARGET_ENOSYS;
4422 break;
bellard6dbad632003-03-16 18:05:05 +00004423 }
4424 return ret;
4425}
bellard1b6b0292003-03-22 17:31:38 +00004426
blueswir14583f582008-08-24 10:35:55 +00004427#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004428abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004429{
4430 uint64_t *gdt_table = g2h(env->gdt.base);
4431 struct target_modify_ldt_ldt_s ldt_info;
4432 struct target_modify_ldt_ldt_s *target_ldt_info;
4433 int seg_32bit, contents, read_exec_only, limit_in_pages;
4434 int seg_not_present, useable, lm;
4435 uint32_t *lp, entry_1, entry_2;
4436 int i;
4437
4438 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4439 if (!target_ldt_info)
4440 return -TARGET_EFAULT;
4441 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004442 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004443 ldt_info.limit = tswap32(target_ldt_info->limit);
4444 ldt_info.flags = tswap32(target_ldt_info->flags);
4445 if (ldt_info.entry_number == -1) {
4446 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4447 if (gdt_table[i] == 0) {
4448 ldt_info.entry_number = i;
4449 target_ldt_info->entry_number = tswap32(i);
4450 break;
4451 }
4452 }
4453 }
4454 unlock_user_struct(target_ldt_info, ptr, 1);
4455
4456 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4457 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4458 return -TARGET_EINVAL;
4459 seg_32bit = ldt_info.flags & 1;
4460 contents = (ldt_info.flags >> 1) & 3;
4461 read_exec_only = (ldt_info.flags >> 3) & 1;
4462 limit_in_pages = (ldt_info.flags >> 4) & 1;
4463 seg_not_present = (ldt_info.flags >> 5) & 1;
4464 useable = (ldt_info.flags >> 6) & 1;
4465#ifdef TARGET_ABI32
4466 lm = 0;
4467#else
4468 lm = (ldt_info.flags >> 7) & 1;
4469#endif
4470
4471 if (contents == 3) {
4472 if (seg_not_present == 0)
4473 return -TARGET_EINVAL;
4474 }
4475
4476 /* NOTE: same code as Linux kernel */
4477 /* Allow LDTs to be cleared by the user. */
4478 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4479 if ((contents == 0 &&
4480 read_exec_only == 1 &&
4481 seg_32bit == 0 &&
4482 limit_in_pages == 0 &&
4483 seg_not_present == 1 &&
4484 useable == 0 )) {
4485 entry_1 = 0;
4486 entry_2 = 0;
4487 goto install;
4488 }
4489 }
4490
4491 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4492 (ldt_info.limit & 0x0ffff);
4493 entry_2 = (ldt_info.base_addr & 0xff000000) |
4494 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4495 (ldt_info.limit & 0xf0000) |
4496 ((read_exec_only ^ 1) << 9) |
4497 (contents << 10) |
4498 ((seg_not_present ^ 1) << 15) |
4499 (seg_32bit << 22) |
4500 (limit_in_pages << 23) |
4501 (useable << 20) |
4502 (lm << 21) |
4503 0x7000;
4504
4505 /* Install the new entry ... */
4506install:
4507 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4508 lp[0] = tswap32(entry_1);
4509 lp[1] = tswap32(entry_2);
4510 return 0;
4511}
4512
blueswir18fcd3692008-08-17 20:26:25 +00004513static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004514{
4515 struct target_modify_ldt_ldt_s *target_ldt_info;
4516 uint64_t *gdt_table = g2h(env->gdt.base);
4517 uint32_t base_addr, limit, flags;
4518 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4519 int seg_not_present, useable, lm;
4520 uint32_t *lp, entry_1, entry_2;
4521
4522 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4523 if (!target_ldt_info)
4524 return -TARGET_EFAULT;
4525 idx = tswap32(target_ldt_info->entry_number);
4526 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4527 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4528 unlock_user_struct(target_ldt_info, ptr, 1);
4529 return -TARGET_EINVAL;
4530 }
4531 lp = (uint32_t *)(gdt_table + idx);
4532 entry_1 = tswap32(lp[0]);
4533 entry_2 = tswap32(lp[1]);
4534
4535 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4536 contents = (entry_2 >> 10) & 3;
4537 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4538 seg_32bit = (entry_2 >> 22) & 1;
4539 limit_in_pages = (entry_2 >> 23) & 1;
4540 useable = (entry_2 >> 20) & 1;
4541#ifdef TARGET_ABI32
4542 lm = 0;
4543#else
4544 lm = (entry_2 >> 21) & 1;
4545#endif
4546 flags = (seg_32bit << 0) | (contents << 1) |
4547 (read_exec_only << 3) | (limit_in_pages << 4) |
4548 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4549 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4550 base_addr = (entry_1 >> 16) |
4551 (entry_2 & 0xff000000) |
4552 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004553 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004554 target_ldt_info->limit = tswap32(limit);
4555 target_ldt_info->flags = tswap32(flags);
4556 unlock_user_struct(target_ldt_info, ptr, 1);
4557 return 0;
4558}
blueswir14583f582008-08-24 10:35:55 +00004559#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004560
bellardd2fd1af2007-11-14 18:08:56 +00004561#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004562abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004563{
Juan Quintela1add8692011-06-16 17:37:09 +01004564 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004565 abi_ulong val;
4566 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004567
bellardd2fd1af2007-11-14 18:08:56 +00004568 switch(code) {
4569 case TARGET_ARCH_SET_GS:
4570 case TARGET_ARCH_SET_FS:
4571 if (code == TARGET_ARCH_SET_GS)
4572 idx = R_GS;
4573 else
4574 idx = R_FS;
4575 cpu_x86_load_seg(env, idx, 0);
4576 env->segs[idx].base = addr;
4577 break;
4578 case TARGET_ARCH_GET_GS:
4579 case TARGET_ARCH_GET_FS:
4580 if (code == TARGET_ARCH_GET_GS)
4581 idx = R_GS;
4582 else
4583 idx = R_FS;
4584 val = env->segs[idx].base;
4585 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004586 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004587 break;
4588 default:
4589 ret = -TARGET_EINVAL;
4590 break;
4591 }
Juan Quintela1add8692011-06-16 17:37:09 +01004592 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004593}
4594#endif
4595
bellard2ab83ea2003-06-15 19:56:46 +00004596#endif /* defined(TARGET_I386) */
4597
Riku Voipio05098a92011-03-04 15:27:29 +02004598#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004599
pbrookd865bab2008-06-07 22:12:17 +00004600
4601static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4602typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004603 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004604 pthread_mutex_t mutex;
4605 pthread_cond_t cond;
4606 pthread_t thread;
4607 uint32_t tid;
4608 abi_ulong child_tidptr;
4609 abi_ulong parent_tidptr;
4610 sigset_t sigmask;
4611} new_thread_info;
4612
4613static void *clone_func(void *arg)
4614{
4615 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004616 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004617 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004618 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004619
Emilio G. Cota70903762015-08-23 20:23:41 -04004620 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00004621 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004622 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004623 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004624 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004625 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004626 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004627 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004628 if (info->child_tidptr)
4629 put_user_u32(info->tid, info->child_tidptr);
4630 if (info->parent_tidptr)
4631 put_user_u32(info->tid, info->parent_tidptr);
4632 /* Enable signals. */
4633 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4634 /* Signal to the parent that we're ready. */
4635 pthread_mutex_lock(&info->mutex);
4636 pthread_cond_broadcast(&info->cond);
4637 pthread_mutex_unlock(&info->mutex);
4638 /* Wait until the parent has finshed initializing the tls state. */
4639 pthread_mutex_lock(&clone_lock);
4640 pthread_mutex_unlock(&clone_lock);
4641 cpu_loop(env);
4642 /* never exits */
4643 return NULL;
4644}
bellard1b6b0292003-03-22 17:31:38 +00004645
ths0da46a62007-10-20 20:23:07 +00004646/* do_fork() Must return host values and target errnos (unlike most
4647 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004648static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004649 abi_ulong parent_tidptr, target_ulong newtls,
4650 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004651{
Andreas Färber0429a972013-08-26 18:14:44 +02004652 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004653 int ret;
bellard5cd43932003-03-29 16:54:36 +00004654 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004655 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004656 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004657 unsigned int nptl_flags;
4658 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004659
balrog436d1242008-09-21 02:39:45 +00004660 /* Emulate vfork() with fork() */
4661 if (flags & CLONE_VFORK)
4662 flags &= ~(CLONE_VFORK | CLONE_VM);
4663
bellard1b6b0292003-03-22 17:31:38 +00004664 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004665 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004666 new_thread_info info;
4667 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004668
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02004669 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00004670 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004671 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004672 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004673 /* Init regs that differ from the parent. */
4674 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004675 new_cpu = ENV_GET_CPU(new_env);
4676 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004677 ts->bprm = parent_ts->bprm;
4678 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004679 nptl_flags = flags;
4680 flags &= ~CLONE_NPTL_FLAGS2;
4681
pbrookc2764712009-03-07 15:24:59 +00004682 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4683 ts->child_tidptr = child_tidptr;
4684 }
4685
pbrookd865bab2008-06-07 22:12:17 +00004686 if (nptl_flags & CLONE_SETTLS)
4687 cpu_set_tls (new_env, newtls);
4688
4689 /* Grab a mutex so that thread setup appears atomic. */
4690 pthread_mutex_lock(&clone_lock);
4691
4692 memset(&info, 0, sizeof(info));
4693 pthread_mutex_init(&info.mutex, NULL);
4694 pthread_mutex_lock(&info.mutex);
4695 pthread_cond_init(&info.cond, NULL);
4696 info.env = new_env;
4697 if (nptl_flags & CLONE_CHILD_SETTID)
4698 info.child_tidptr = child_tidptr;
4699 if (nptl_flags & CLONE_PARENT_SETTID)
4700 info.parent_tidptr = parent_tidptr;
4701
4702 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004703 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4704 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004705 /* It is not safe to deliver signals until the child has finished
4706 initializing, so temporarily block all signals. */
4707 sigfillset(&sigmask);
4708 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4709
4710 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004711 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004712
4713 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4714 pthread_attr_destroy(&attr);
4715 if (ret == 0) {
4716 /* Wait for the child to initialize. */
4717 pthread_cond_wait(&info.cond, &info.mutex);
4718 ret = info.tid;
4719 if (flags & CLONE_PARENT_SETTID)
4720 put_user_u32(ret, parent_tidptr);
4721 } else {
4722 ret = -1;
4723 }
4724 pthread_mutex_unlock(&info.mutex);
4725 pthread_cond_destroy(&info.cond);
4726 pthread_mutex_destroy(&info.mutex);
4727 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004728 } else {
4729 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01004730 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
4731 return -TARGET_EINVAL;
4732 }
pbrookd865bab2008-06-07 22:12:17 +00004733 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004734 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004735 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004736 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02004737 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00004738 cpu_clone_regs(env, newsp);
4739 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004740 /* There is a race condition here. The parent process could
4741 theoretically read the TID in the child process before the child
4742 tid is set. This would require using either ptrace
4743 (not implemented) or having *_tidptr to point at a shared memory
4744 mapping. We can't repeat the spinlock hack used above because
4745 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004746 if (flags & CLONE_CHILD_SETTID)
4747 put_user_u32(gettid(), child_tidptr);
4748 if (flags & CLONE_PARENT_SETTID)
4749 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004750 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004751 if (flags & CLONE_SETTLS)
4752 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004753 if (flags & CLONE_CHILD_CLEARTID)
4754 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004755 } else {
4756 fork_end(0);
4757 }
bellard1b6b0292003-03-22 17:31:38 +00004758 }
4759 return ret;
4760}
4761
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004762/* warning : doesn't handle linux specific flags... */
4763static int target_to_host_fcntl_cmd(int cmd)
4764{
4765 switch(cmd) {
4766 case TARGET_F_DUPFD:
4767 case TARGET_F_GETFD:
4768 case TARGET_F_SETFD:
4769 case TARGET_F_GETFL:
4770 case TARGET_F_SETFL:
4771 return cmd;
4772 case TARGET_F_GETLK:
4773 return F_GETLK;
4774 case TARGET_F_SETLK:
4775 return F_SETLK;
4776 case TARGET_F_SETLKW:
4777 return F_SETLKW;
4778 case TARGET_F_GETOWN:
4779 return F_GETOWN;
4780 case TARGET_F_SETOWN:
4781 return F_SETOWN;
4782 case TARGET_F_GETSIG:
4783 return F_GETSIG;
4784 case TARGET_F_SETSIG:
4785 return F_SETSIG;
4786#if TARGET_ABI_BITS == 32
4787 case TARGET_F_GETLK64:
4788 return F_GETLK64;
4789 case TARGET_F_SETLK64:
4790 return F_SETLK64;
4791 case TARGET_F_SETLKW64:
4792 return F_SETLKW64;
4793#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004794 case TARGET_F_SETLEASE:
4795 return F_SETLEASE;
4796 case TARGET_F_GETLEASE:
4797 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004798#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004799 case TARGET_F_DUPFD_CLOEXEC:
4800 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004801#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004802 case TARGET_F_NOTIFY:
4803 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004804#ifdef F_GETOWN_EX
4805 case TARGET_F_GETOWN_EX:
4806 return F_GETOWN_EX;
4807#endif
4808#ifdef F_SETOWN_EX
4809 case TARGET_F_SETOWN_EX:
4810 return F_SETOWN_EX;
4811#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004812 default:
4813 return -TARGET_EINVAL;
4814 }
4815 return -TARGET_EINVAL;
4816}
4817
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004818#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4819static const bitmask_transtbl flock_tbl[] = {
4820 TRANSTBL_CONVERT(F_RDLCK),
4821 TRANSTBL_CONVERT(F_WRLCK),
4822 TRANSTBL_CONVERT(F_UNLCK),
4823 TRANSTBL_CONVERT(F_EXLCK),
4824 TRANSTBL_CONVERT(F_SHLCK),
4825 { 0, 0, 0, 0 }
4826};
4827
blueswir1992f48a2007-10-14 16:27:31 +00004828static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004829{
4830 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004831 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004832 struct flock64 fl64;
4833 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004834#ifdef F_GETOWN_EX
4835 struct f_owner_ex fox;
4836 struct target_f_owner_ex *target_fox;
4837#endif
blueswir1992f48a2007-10-14 16:27:31 +00004838 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004839 int host_cmd = target_to_host_fcntl_cmd(cmd);
4840
4841 if (host_cmd == -TARGET_EINVAL)
4842 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004843
bellard7775e9e2003-05-14 22:46:48 +00004844 switch(cmd) {
4845 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004846 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4847 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004848 fl.l_type =
4849 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004850 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004851 fl.l_start = tswapal(target_fl->l_start);
4852 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004853 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004854 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004855 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004856 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004857 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4858 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004859 target_fl->l_type =
4860 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004861 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004862 target_fl->l_start = tswapal(fl.l_start);
4863 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004864 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004865 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004866 }
4867 break;
ths3b46e622007-09-17 08:09:54 +00004868
bellard7775e9e2003-05-14 22:46:48 +00004869 case TARGET_F_SETLK:
4870 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004871 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4872 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004873 fl.l_type =
4874 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004875 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004876 fl.l_start = tswapal(target_fl->l_start);
4877 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004878 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004879 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004880 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004881 break;
ths3b46e622007-09-17 08:09:54 +00004882
bellard7775e9e2003-05-14 22:46:48 +00004883 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004884 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4885 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004886 fl64.l_type =
4887 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004888 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004889 fl64.l_start = tswap64(target_fl64->l_start);
4890 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004891 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004892 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004893 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004894 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004895 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4896 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004897 target_fl64->l_type =
4898 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004899 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004900 target_fl64->l_start = tswap64(fl64.l_start);
4901 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004902 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004903 unlock_user_struct(target_fl64, arg, 1);
4904 }
bellard9ee1fa22007-11-11 15:11:19 +00004905 break;
bellard7775e9e2003-05-14 22:46:48 +00004906 case TARGET_F_SETLK64:
4907 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004908 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4909 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004910 fl64.l_type =
4911 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004912 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004913 fl64.l_start = tswap64(target_fl64->l_start);
4914 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004915 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004916 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004917 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004918 break;
4919
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004920 case TARGET_F_GETFL:
4921 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004922 if (ret >= 0) {
4923 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4924 }
bellardffa65c32004-01-04 23:57:22 +00004925 break;
4926
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004927 case TARGET_F_SETFL:
4928 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4929 break;
4930
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004931#ifdef F_GETOWN_EX
4932 case TARGET_F_GETOWN_EX:
4933 ret = get_errno(fcntl(fd, host_cmd, &fox));
4934 if (ret >= 0) {
4935 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4936 return -TARGET_EFAULT;
4937 target_fox->type = tswap32(fox.type);
4938 target_fox->pid = tswap32(fox.pid);
4939 unlock_user_struct(target_fox, arg, 1);
4940 }
4941 break;
4942#endif
4943
4944#ifdef F_SETOWN_EX
4945 case TARGET_F_SETOWN_EX:
4946 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4947 return -TARGET_EFAULT;
4948 fox.type = tswap32(target_fox->type);
4949 fox.pid = tswap32(target_fox->pid);
4950 unlock_user_struct(target_fox, arg, 0);
4951 ret = get_errno(fcntl(fd, host_cmd, &fox));
4952 break;
4953#endif
4954
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004955 case TARGET_F_SETOWN:
4956 case TARGET_F_GETOWN:
4957 case TARGET_F_SETSIG:
4958 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004959 case TARGET_F_SETLEASE:
4960 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004961 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004962 break;
4963
bellard7775e9e2003-05-14 22:46:48 +00004964 default:
bellard9ee1fa22007-11-11 15:11:19 +00004965 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004966 break;
4967 }
4968 return ret;
4969}
4970
bellard67867302003-11-23 17:05:30 +00004971#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004972
bellard67867302003-11-23 17:05:30 +00004973static inline int high2lowuid(int uid)
4974{
4975 if (uid > 65535)
4976 return 65534;
4977 else
4978 return uid;
4979}
4980
4981static inline int high2lowgid(int gid)
4982{
4983 if (gid > 65535)
4984 return 65534;
4985 else
4986 return gid;
4987}
4988
4989static inline int low2highuid(int uid)
4990{
4991 if ((int16_t)uid == -1)
4992 return -1;
4993 else
4994 return uid;
4995}
4996
4997static inline int low2highgid(int gid)
4998{
4999 if ((int16_t)gid == -1)
5000 return -1;
5001 else
5002 return gid;
5003}
Riku Voipio0c866a72011-04-18 15:23:06 +03005004static inline int tswapid(int id)
5005{
5006 return tswap16(id);
5007}
Peter Maydell76ca3102014-03-02 19:36:41 +00005008
5009#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5010
Riku Voipio0c866a72011-04-18 15:23:06 +03005011#else /* !USE_UID16 */
5012static inline int high2lowuid(int uid)
5013{
5014 return uid;
5015}
5016static inline int high2lowgid(int gid)
5017{
5018 return gid;
5019}
5020static inline int low2highuid(int uid)
5021{
5022 return uid;
5023}
5024static inline int low2highgid(int gid)
5025{
5026 return gid;
5027}
5028static inline int tswapid(int id)
5029{
5030 return tswap32(id);
5031}
Peter Maydell76ca3102014-03-02 19:36:41 +00005032
5033#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5034
bellard67867302003-11-23 17:05:30 +00005035#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005036
bellard31e31b82003-02-18 22:55:36 +00005037void syscall_init(void)
5038{
bellard2ab83ea2003-06-15 19:56:46 +00005039 IOCTLEntry *ie;
5040 const argtype *arg_type;
5041 int size;
thsb92c47c2007-11-01 00:07:38 +00005042 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005043
Alexander Graf8be656b2015-05-06 23:47:32 +02005044 thunk_init(STRUCT_MAX);
5045
Blue Swirl001faf32009-05-13 17:53:17 +00005046#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005047#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005048#include "syscall_types.h"
5049#undef STRUCT
5050#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005051
Peter Maydelldd6e9572012-07-23 08:07:22 +00005052 /* Build target_to_host_errno_table[] table from
5053 * host_to_target_errno_table[]. */
5054 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5055 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5056 }
5057
bellard2ab83ea2003-06-15 19:56:46 +00005058 /* we patch the ioctl size if necessary. We rely on the fact that
5059 no ioctl has all the bits at '1' in the size field */
5060 ie = ioctl_entries;
5061 while (ie->target_cmd != 0) {
5062 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5063 TARGET_IOC_SIZEMASK) {
5064 arg_type = ie->arg_type;
5065 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005066 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005067 ie->target_cmd);
5068 exit(1);
5069 }
5070 arg_type++;
5071 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005072 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005073 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5074 (size << TARGET_IOC_SIZESHIFT);
5075 }
thsb92c47c2007-11-01 00:07:38 +00005076
bellard2ab83ea2003-06-15 19:56:46 +00005077 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005078#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5079 (defined(__x86_64__) && defined(TARGET_X86_64))
5080 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5081 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5082 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005083 }
5084#endif
5085 ie++;
5086 }
bellard31e31b82003-02-18 22:55:36 +00005087}
bellardc573ff62004-01-04 15:51:36 +00005088
blueswir1992f48a2007-10-14 16:27:31 +00005089#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005090static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5091{
thsaf325d32008-06-10 15:29:15 +00005092#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005093 return ((uint64_t)word0 << 32) | word1;
5094#else
5095 return ((uint64_t)word1 << 32) | word0;
5096#endif
5097}
blueswir1992f48a2007-10-14 16:27:31 +00005098#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005099static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5100{
5101 return word0;
5102}
blueswir1992f48a2007-10-14 16:27:31 +00005103#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005104
5105#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005106static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5107 abi_long arg2,
5108 abi_long arg3,
5109 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005110{
Riku Voipio48e515d2011-07-12 15:40:51 +03005111 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005112 arg2 = arg3;
5113 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005114 }
pbrookce4defa2006-02-09 16:49:55 +00005115 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5116}
5117#endif
5118
5119#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005120static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5121 abi_long arg2,
5122 abi_long arg3,
5123 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005124{
Riku Voipio48e515d2011-07-12 15:40:51 +03005125 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005126 arg2 = arg3;
5127 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005128 }
pbrookce4defa2006-02-09 16:49:55 +00005129 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5130}
5131#endif
5132
bellard579a97f2007-11-11 14:26:47 +00005133static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5134 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005135{
5136 struct target_timespec *target_ts;
5137
bellard579a97f2007-11-11 14:26:47 +00005138 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5139 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005140 host_ts->tv_sec = tswapal(target_ts->tv_sec);
5141 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005142 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005143 return 0;
pbrook53a59602006-03-25 19:31:22 +00005144}
5145
bellard579a97f2007-11-11 14:26:47 +00005146static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5147 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005148{
5149 struct target_timespec *target_ts;
5150
bellard579a97f2007-11-11 14:26:47 +00005151 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5152 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005153 target_ts->tv_sec = tswapal(host_ts->tv_sec);
5154 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005155 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005156 return 0;
pbrook53a59602006-03-25 19:31:22 +00005157}
5158
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005159static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5160 abi_ulong target_addr)
5161{
5162 struct target_itimerspec *target_itspec;
5163
5164 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5165 return -TARGET_EFAULT;
5166 }
5167
5168 host_itspec->it_interval.tv_sec =
5169 tswapal(target_itspec->it_interval.tv_sec);
5170 host_itspec->it_interval.tv_nsec =
5171 tswapal(target_itspec->it_interval.tv_nsec);
5172 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5173 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5174
5175 unlock_user_struct(target_itspec, target_addr, 1);
5176 return 0;
5177}
5178
5179static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5180 struct itimerspec *host_its)
5181{
5182 struct target_itimerspec *target_itspec;
5183
5184 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5185 return -TARGET_EFAULT;
5186 }
5187
5188 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5189 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5190
5191 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5192 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5193
5194 unlock_user_struct(target_itspec, target_addr, 0);
5195 return 0;
5196}
5197
Peter Maydellc0659762014-08-09 15:42:32 +01005198static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5199 abi_ulong target_addr)
5200{
5201 struct target_sigevent *target_sevp;
5202
5203 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5204 return -TARGET_EFAULT;
5205 }
5206
5207 /* This union is awkward on 64 bit systems because it has a 32 bit
5208 * integer and a pointer in it; we follow the conversion approach
5209 * used for handling sigval types in signal.c so the guest should get
5210 * the correct value back even if we did a 64 bit byteswap and it's
5211 * using the 32 bit integer.
5212 */
5213 host_sevp->sigev_value.sival_ptr =
5214 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5215 host_sevp->sigev_signo =
5216 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5217 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5218 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5219
5220 unlock_user_struct(target_sevp, target_addr, 1);
5221 return 0;
5222}
5223
Tom Musta6f6a4032014-08-12 13:53:42 -05005224#if defined(TARGET_NR_mlockall)
5225static inline int target_to_host_mlockall_arg(int arg)
5226{
5227 int result = 0;
5228
5229 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5230 result |= MCL_CURRENT;
5231 }
5232 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5233 result |= MCL_FUTURE;
5234 }
5235 return result;
5236}
5237#endif
5238
aurel329d33b762009-04-08 23:07:05 +00005239#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00005240static inline abi_long host_to_target_stat64(void *cpu_env,
5241 abi_ulong target_addr,
5242 struct stat *host_st)
5243{
Alexander Graf09701192013-09-03 20:12:15 +01005244#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005245 if (((CPUARMState *)cpu_env)->eabi) {
5246 struct target_eabi_stat64 *target_st;
5247
5248 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5249 return -TARGET_EFAULT;
5250 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5251 __put_user(host_st->st_dev, &target_st->st_dev);
5252 __put_user(host_st->st_ino, &target_st->st_ino);
5253#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5254 __put_user(host_st->st_ino, &target_st->__st_ino);
5255#endif
5256 __put_user(host_st->st_mode, &target_st->st_mode);
5257 __put_user(host_st->st_nlink, &target_st->st_nlink);
5258 __put_user(host_st->st_uid, &target_st->st_uid);
5259 __put_user(host_st->st_gid, &target_st->st_gid);
5260 __put_user(host_st->st_rdev, &target_st->st_rdev);
5261 __put_user(host_st->st_size, &target_st->st_size);
5262 __put_user(host_st->st_blksize, &target_st->st_blksize);
5263 __put_user(host_st->st_blocks, &target_st->st_blocks);
5264 __put_user(host_st->st_atime, &target_st->target_st_atime);
5265 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5266 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5267 unlock_user_struct(target_st, target_addr, 1);
5268 } else
5269#endif
5270 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005271#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005272 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005273#else
5274 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005275#endif
balrog6a24a772008-09-20 02:23:36 +00005276
5277 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5278 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005279 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005280 __put_user(host_st->st_dev, &target_st->st_dev);
5281 __put_user(host_st->st_ino, &target_st->st_ino);
5282#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5283 __put_user(host_st->st_ino, &target_st->__st_ino);
5284#endif
5285 __put_user(host_st->st_mode, &target_st->st_mode);
5286 __put_user(host_st->st_nlink, &target_st->st_nlink);
5287 __put_user(host_st->st_uid, &target_st->st_uid);
5288 __put_user(host_st->st_gid, &target_st->st_gid);
5289 __put_user(host_st->st_rdev, &target_st->st_rdev);
5290 /* XXX: better use of kernel struct */
5291 __put_user(host_st->st_size, &target_st->st_size);
5292 __put_user(host_st->st_blksize, &target_st->st_blksize);
5293 __put_user(host_st->st_blocks, &target_st->st_blocks);
5294 __put_user(host_st->st_atime, &target_st->target_st_atime);
5295 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5296 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5297 unlock_user_struct(target_st, target_addr, 1);
5298 }
5299
5300 return 0;
5301}
5302#endif
5303
pbrookbd0c5662008-05-29 14:34:11 +00005304/* ??? Using host futex calls even when target atomic operations
5305 are not really atomic probably breaks things. However implementing
5306 futexes locally would make futexes shared between multiple processes
5307 tricky. However they're probably useless because guest atomic
5308 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005309static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5310 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005311{
5312 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005313 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005314
5315 /* ??? We assume FUTEX_* constants are the same on both host
5316 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005317#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005318 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005319#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005320 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005321#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005322 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005323 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005324 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005325 if (timeout) {
5326 pts = &ts;
5327 target_to_host_timespec(pts, timeout);
5328 } else {
5329 pts = NULL;
5330 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005331 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005332 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005333 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005334 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005335 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005336 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005337 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005338 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005339 case FUTEX_WAKE_OP:
5340 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5341 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5342 But the prototype takes a `struct timespec *'; insert casts
5343 to satisfy the compiler. We do not need to tswap TIMEOUT
5344 since it's not compared to guest memory. */
5345 pts = (struct timespec *)(uintptr_t) timeout;
5346 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5347 g2h(uaddr2),
5348 (base_op == FUTEX_CMP_REQUEUE
5349 ? tswap32(val3)
5350 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005351 default:
5352 return -TARGET_ENOSYS;
5353 }
5354}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005355#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5356static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
5357 abi_long handle, abi_long mount_id,
5358 abi_long flags)
5359{
5360 struct file_handle *target_fh;
5361 struct file_handle *fh;
5362 int mid = 0;
5363 abi_long ret;
5364 char *name;
5365 unsigned int size, total_size;
5366
5367 if (get_user_s32(size, handle)) {
5368 return -TARGET_EFAULT;
5369 }
5370
5371 name = lock_user_string(pathname);
5372 if (!name) {
5373 return -TARGET_EFAULT;
5374 }
5375
5376 total_size = sizeof(struct file_handle) + size;
5377 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
5378 if (!target_fh) {
5379 unlock_user(name, pathname, 0);
5380 return -TARGET_EFAULT;
5381 }
5382
5383 fh = g_malloc0(total_size);
5384 fh->handle_bytes = size;
5385
5386 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
5387 unlock_user(name, pathname, 0);
5388
5389 /* man name_to_handle_at(2):
5390 * Other than the use of the handle_bytes field, the caller should treat
5391 * the file_handle structure as an opaque data type
5392 */
5393
5394 memcpy(target_fh, fh, total_size);
5395 target_fh->handle_bytes = tswap32(fh->handle_bytes);
5396 target_fh->handle_type = tswap32(fh->handle_type);
5397 g_free(fh);
5398 unlock_user(target_fh, handle, total_size);
5399
5400 if (put_user_s32(mid, mount_id)) {
5401 return -TARGET_EFAULT;
5402 }
5403
5404 return ret;
5405
5406}
5407#endif
5408
5409#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5410static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
5411 abi_long flags)
5412{
5413 struct file_handle *target_fh;
5414 struct file_handle *fh;
5415 unsigned int size, total_size;
5416 abi_long ret;
5417
5418 if (get_user_s32(size, handle)) {
5419 return -TARGET_EFAULT;
5420 }
5421
5422 total_size = sizeof(struct file_handle) + size;
5423 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
5424 if (!target_fh) {
5425 return -TARGET_EFAULT;
5426 }
5427
Thomas Huthe9d49d52015-10-09 17:56:38 +02005428 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005429 fh->handle_bytes = size;
5430 fh->handle_type = tswap32(target_fh->handle_type);
5431
5432 ret = get_errno(open_by_handle_at(mount_fd, fh,
5433 target_to_host_bitmask(flags, fcntl_flags_tbl)));
5434
5435 g_free(fh);
5436
5437 unlock_user(target_fh, handle, total_size);
5438
5439 return ret;
5440}
5441#endif
pbrookbd0c5662008-05-29 14:34:11 +00005442
Laurent Viviere36800c2015-10-02 14:48:09 +02005443#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
5444
5445/* signalfd siginfo conversion */
5446
5447static void
5448host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
5449 const struct signalfd_siginfo *info)
5450{
5451 int sig = host_to_target_signal(info->ssi_signo);
5452
5453 /* linux/signalfd.h defines a ssi_addr_lsb
5454 * not defined in sys/signalfd.h but used by some kernels
5455 */
5456
5457#ifdef BUS_MCEERR_AO
5458 if (tinfo->ssi_signo == SIGBUS &&
5459 (tinfo->ssi_code == BUS_MCEERR_AR ||
5460 tinfo->ssi_code == BUS_MCEERR_AO)) {
5461 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
5462 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
5463 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
5464 }
5465#endif
5466
5467 tinfo->ssi_signo = tswap32(sig);
5468 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
5469 tinfo->ssi_code = tswap32(info->ssi_code);
5470 tinfo->ssi_pid = tswap32(info->ssi_pid);
5471 tinfo->ssi_uid = tswap32(info->ssi_uid);
5472 tinfo->ssi_fd = tswap32(info->ssi_fd);
5473 tinfo->ssi_tid = tswap32(info->ssi_tid);
5474 tinfo->ssi_band = tswap32(info->ssi_band);
5475 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
5476 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
5477 tinfo->ssi_status = tswap32(info->ssi_status);
5478 tinfo->ssi_int = tswap32(info->ssi_int);
5479 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
5480 tinfo->ssi_utime = tswap64(info->ssi_utime);
5481 tinfo->ssi_stime = tswap64(info->ssi_stime);
5482 tinfo->ssi_addr = tswap64(info->ssi_addr);
5483}
5484
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005485static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02005486{
5487 int i;
5488
5489 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
5490 host_to_target_signalfd_siginfo(buf + i, buf + i);
5491 }
5492
5493 return len;
5494}
5495
5496static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005497 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02005498};
5499
5500static abi_long do_signalfd4(int fd, abi_long mask, int flags)
5501{
5502 int host_flags;
5503 target_sigset_t *target_mask;
5504 sigset_t host_mask;
5505 abi_long ret;
5506
5507 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
5508 return -TARGET_EINVAL;
5509 }
5510 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
5511 return -TARGET_EFAULT;
5512 }
5513
5514 target_to_host_sigset(&host_mask, target_mask);
5515
5516 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
5517
5518 ret = get_errno(signalfd(fd, &host_mask, host_flags));
5519 if (ret >= 0) {
5520 fd_trans_register(ret, &target_signalfd_trans);
5521 }
5522
5523 unlock_user_struct(target_mask, mask, 0);
5524
5525 return ret;
5526}
5527#endif
5528
pbrook1d9d8b52009-04-16 15:17:02 +00005529/* Map host to target signal numbers for the wait family of syscalls.
5530 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005531int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005532{
5533 if (WIFSIGNALED(status)) {
5534 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5535 }
5536 if (WIFSTOPPED(status)) {
5537 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5538 | (status & 0xff);
5539 }
5540 return status;
5541}
5542
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005543static int open_self_cmdline(void *cpu_env, int fd)
5544{
5545 int fd_orig = -1;
5546 bool word_skipped = false;
5547
5548 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5549 if (fd_orig < 0) {
5550 return fd_orig;
5551 }
5552
5553 while (true) {
5554 ssize_t nb_read;
5555 char buf[128];
5556 char *cp_buf = buf;
5557
5558 nb_read = read(fd_orig, buf, sizeof(buf));
5559 if (nb_read < 0) {
5560 fd_orig = close(fd_orig);
5561 return -1;
5562 } else if (nb_read == 0) {
5563 break;
5564 }
5565
5566 if (!word_skipped) {
5567 /* Skip the first string, which is the path to qemu-*-static
5568 instead of the actual command. */
5569 cp_buf = memchr(buf, 0, sizeof(buf));
5570 if (cp_buf) {
5571 /* Null byte found, skip one string */
5572 cp_buf++;
5573 nb_read -= cp_buf - buf;
5574 word_skipped = true;
5575 }
5576 }
5577
5578 if (word_skipped) {
5579 if (write(fd, cp_buf, nb_read) != nb_read) {
zhanghailiang680dfde2014-08-22 16:23:51 +08005580 close(fd_orig);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005581 return -1;
5582 }
5583 }
5584 }
5585
5586 return close(fd_orig);
5587}
5588
Alexander Graf36c08d42011-11-02 20:23:24 +01005589static int open_self_maps(void *cpu_env, int fd)
5590{
Andreas Färber0429a972013-08-26 18:14:44 +02005591 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5592 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005593 FILE *fp;
5594 char *line = NULL;
5595 size_t len = 0;
5596 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005597
Alexander Graf1a49ef22012-05-01 16:30:28 +01005598 fp = fopen("/proc/self/maps", "r");
5599 if (fp == NULL) {
5600 return -EACCES;
5601 }
5602
5603 while ((read = getline(&line, &len, fp)) != -1) {
5604 int fields, dev_maj, dev_min, inode;
5605 uint64_t min, max, offset;
5606 char flag_r, flag_w, flag_x, flag_p;
5607 char path[512] = "";
5608 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5609 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5610 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5611
5612 if ((fields < 10) || (fields > 11)) {
5613 continue;
5614 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005615 if (h2g_valid(min)) {
5616 int flags = page_get_flags(h2g(min));
5617 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5618 if (page_check_range(h2g(min), max - min, flags) == -1) {
5619 continue;
5620 }
5621 if (h2g(min) == ts->info->stack_limit) {
5622 pstrcpy(path, sizeof(path), " [stack]");
5623 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005624 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005625 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005626 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005627 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005628 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005629 }
5630 }
5631
5632 free(line);
5633 fclose(fp);
5634
Alexander Graf36c08d42011-11-02 20:23:24 +01005635 return 0;
5636}
5637
Alexander Graf480b8e72011-11-02 20:23:25 +01005638static int open_self_stat(void *cpu_env, int fd)
5639{
Andreas Färber0429a972013-08-26 18:14:44 +02005640 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5641 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005642 abi_ulong start_stack = ts->info->start_stack;
5643 int i;
5644
5645 for (i = 0; i < 44; i++) {
5646 char buf[128];
5647 int len;
5648 uint64_t val = 0;
5649
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005650 if (i == 0) {
5651 /* pid */
5652 val = getpid();
5653 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5654 } else if (i == 1) {
5655 /* app name */
5656 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5657 } else if (i == 27) {
5658 /* stack bottom */
5659 val = start_stack;
5660 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5661 } else {
5662 /* for the rest, there is MasterCard */
5663 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005664 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005665
Alexander Graf480b8e72011-11-02 20:23:25 +01005666 len = strlen(buf);
5667 if (write(fd, buf, len) != len) {
5668 return -1;
5669 }
5670 }
5671
5672 return 0;
5673}
5674
Alexander Graf257450e2011-11-02 20:23:26 +01005675static int open_self_auxv(void *cpu_env, int fd)
5676{
Andreas Färber0429a972013-08-26 18:14:44 +02005677 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5678 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005679 abi_ulong auxv = ts->info->saved_auxv;
5680 abi_ulong len = ts->info->auxv_len;
5681 char *ptr;
5682
5683 /*
5684 * Auxiliary vector is stored in target process stack.
5685 * read in whole auxv vector and copy it to file
5686 */
5687 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5688 if (ptr != NULL) {
5689 while (len > 0) {
5690 ssize_t r;
5691 r = write(fd, ptr, len);
5692 if (r <= 0) {
5693 break;
5694 }
5695 len -= r;
5696 ptr += r;
5697 }
5698 lseek(fd, 0, SEEK_SET);
5699 unlock_user(ptr, auxv, len);
5700 }
5701
5702 return 0;
5703}
5704
Andreas Schwab463d8e72013-07-02 14:04:12 +01005705static int is_proc_myself(const char *filename, const char *entry)
5706{
5707 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5708 filename += strlen("/proc/");
5709 if (!strncmp(filename, "self/", strlen("self/"))) {
5710 filename += strlen("self/");
5711 } else if (*filename >= '1' && *filename <= '9') {
5712 char myself[80];
5713 snprintf(myself, sizeof(myself), "%d/", getpid());
5714 if (!strncmp(filename, myself, strlen(myself))) {
5715 filename += strlen(myself);
5716 } else {
5717 return 0;
5718 }
5719 } else {
5720 return 0;
5721 }
5722 if (!strcmp(filename, entry)) {
5723 return 1;
5724 }
5725 }
5726 return 0;
5727}
5728
Laurent Vivierde6b9932013-08-30 01:46:40 +02005729#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5730static int is_proc(const char *filename, const char *entry)
5731{
5732 return strcmp(filename, entry) == 0;
5733}
5734
5735static int open_net_route(void *cpu_env, int fd)
5736{
5737 FILE *fp;
5738 char *line = NULL;
5739 size_t len = 0;
5740 ssize_t read;
5741
5742 fp = fopen("/proc/net/route", "r");
5743 if (fp == NULL) {
5744 return -EACCES;
5745 }
5746
5747 /* read header */
5748
5749 read = getline(&line, &len, fp);
5750 dprintf(fd, "%s", line);
5751
5752 /* read routes */
5753
5754 while ((read = getline(&line, &len, fp)) != -1) {
5755 char iface[16];
5756 uint32_t dest, gw, mask;
5757 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5758 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5759 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5760 &mask, &mtu, &window, &irtt);
5761 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5762 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5763 metric, tswap32(mask), mtu, window, irtt);
5764 }
5765
5766 free(line);
5767 fclose(fp);
5768
5769 return 0;
5770}
5771#endif
5772
Riku Voipio0b2effd2014-08-06 10:36:37 +03005773static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005774{
5775 struct fake_open {
5776 const char *filename;
5777 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005778 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005779 };
5780 const struct fake_open *fake_open;
5781 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005782 { "maps", open_self_maps, is_proc_myself },
5783 { "stat", open_self_stat, is_proc_myself },
5784 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005785 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005786#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5787 { "/proc/net/route", open_net_route, is_proc },
5788#endif
5789 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005790 };
5791
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005792 if (is_proc_myself(pathname, "exe")) {
5793 int execfd = qemu_getauxval(AT_EXECFD);
Riku Voipio0b2effd2014-08-06 10:36:37 +03005794 return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005795 }
5796
Alexander Graf3be14d02011-11-02 20:23:23 +01005797 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005798 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005799 break;
5800 }
5801 }
5802
5803 if (fake_open->filename) {
5804 const char *tmpdir;
5805 char filename[PATH_MAX];
5806 int fd, r;
5807
5808 /* create temporary file to map stat to */
5809 tmpdir = getenv("TMPDIR");
5810 if (!tmpdir)
5811 tmpdir = "/tmp";
5812 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5813 fd = mkstemp(filename);
5814 if (fd < 0) {
5815 return fd;
5816 }
5817 unlink(filename);
5818
5819 if ((r = fake_open->fill(cpu_env, fd))) {
5820 close(fd);
5821 return r;
5822 }
5823 lseek(fd, 0, SEEK_SET);
5824
5825 return fd;
5826 }
5827
Riku Voipio0b2effd2014-08-06 10:36:37 +03005828 return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
Alexander Graf3be14d02011-11-02 20:23:23 +01005829}
5830
Alexander Grafaecc8862014-11-10 21:33:03 +01005831#define TIMER_MAGIC 0x0caf0000
5832#define TIMER_MAGIC_MASK 0xffff0000
5833
5834/* Convert QEMU provided timer ID back to internal 16bit index format */
5835static target_timer_t get_timer_id(abi_long arg)
5836{
5837 target_timer_t timerid = arg;
5838
5839 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
5840 return -TARGET_EINVAL;
5841 }
5842
5843 timerid &= 0xffff;
5844
5845 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
5846 return -TARGET_EINVAL;
5847 }
5848
5849 return timerid;
5850}
5851
ths0da46a62007-10-20 20:23:07 +00005852/* do_syscall() should always have a single exit point at the end so
5853 that actions, such as logging of syscall results, can be performed.
5854 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005855abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5856 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005857 abi_long arg5, abi_long arg6, abi_long arg7,
5858 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005859{
Andreas Färber182735e2013-05-29 22:29:20 +02005860 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005861 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005862 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005863 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005864 void *p;
ths3b46e622007-09-17 08:09:54 +00005865
bellard72f03902003-02-18 23:33:18 +00005866#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005867 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005868#endif
thsb92c47c2007-11-01 00:07:38 +00005869 if(do_strace)
5870 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5871
bellard31e31b82003-02-18 22:55:36 +00005872 switch(num) {
5873 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005874 /* In old applications this may be used to implement _exit(2).
5875 However in threaded applictions it is used for thread termination,
5876 and _exit_group is used for application termination.
5877 Do thread termination if we have more then one thread. */
5878 /* FIXME: This probably breaks if a signal arrives. We should probably
5879 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005880 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005881 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005882
Andreas Färber9b056fc2013-06-24 23:53:10 +02005883 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005884 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005885 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005886 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005887 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005888 if (ts->child_tidptr) {
5889 put_user_u32(0, ts->child_tidptr);
5890 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5891 NULL, NULL, 0);
5892 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005893 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005894 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005895 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04005896 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005897 pthread_exit(NULL);
5898 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005899#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005900 _mcleanup();
5901#endif
bellarde9009672005-04-26 20:42:36 +00005902 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005903 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005904 ret = 0; /* avoid warning */
5905 break;
5906 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005907 if (arg3 == 0)
5908 ret = 0;
5909 else {
5910 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5911 goto efault;
5912 ret = get_errno(read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005913 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01005914 fd_trans_host_to_target_data(arg1)) {
5915 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02005916 }
aurel3238d840e2009-01-30 19:48:17 +00005917 unlock_user(p, arg2, ret);
5918 }
bellard31e31b82003-02-18 22:55:36 +00005919 break;
5920 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005921 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5922 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005923 ret = get_errno(write(arg1, p, arg3));
5924 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005925 break;
Chen Gang704eff62015-08-21 05:37:33 +08005926#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00005927 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005928 if (!(p = lock_user_string(arg1)))
5929 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005930 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
5931 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5932 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02005933 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00005934 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005935 break;
Chen Gang704eff62015-08-21 05:37:33 +08005936#endif
ths82424832007-09-24 09:21:55 +00005937 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005938 if (!(p = lock_user_string(arg2)))
5939 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005940 ret = get_errno(do_openat(cpu_env, arg1, p,
5941 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5942 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02005943 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00005944 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005945 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005946#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5947 case TARGET_NR_name_to_handle_at:
5948 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
5949 break;
5950#endif
5951#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
5952 case TARGET_NR_open_by_handle_at:
5953 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02005954 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02005955 break;
5956#endif
bellard31e31b82003-02-18 22:55:36 +00005957 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02005958 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00005959 ret = get_errno(close(arg1));
5960 break;
5961 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005962 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005963 break;
Chen Gang704eff62015-08-21 05:37:33 +08005964#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00005965 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005966 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005967 break;
Chen Gang704eff62015-08-21 05:37:33 +08005968#endif
thse5febef2007-04-01 18:31:35 +00005969#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005970 case TARGET_NR_waitpid:
5971 {
pbrook53a59602006-03-25 19:31:22 +00005972 int status;
5973 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005974 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005975 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005976 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005977 }
5978 break;
thse5febef2007-04-01 18:31:35 +00005979#endif
pbrookf0cbb612008-05-30 18:20:05 +00005980#ifdef TARGET_NR_waitid
5981 case TARGET_NR_waitid:
5982 {
5983 siginfo_t info;
5984 info.si_pid = 0;
5985 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5986 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005987 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005988 goto efault;
5989 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005990 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005991 }
5992 }
5993 break;
5994#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005995#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005996 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005997 if (!(p = lock_user_string(arg1)))
5998 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005999 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006000 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006001 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006002 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006003#endif
Chen Gang704eff62015-08-21 05:37:33 +08006004#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006005 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006006 {
6007 void * p2;
6008 p = lock_user_string(arg1);
6009 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006010 if (!p || !p2)
6011 ret = -TARGET_EFAULT;
6012 else
6013 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006014 unlock_user(p2, arg2, 0);
6015 unlock_user(p, arg1, 0);
6016 }
bellard31e31b82003-02-18 22:55:36 +00006017 break;
Chen Gang704eff62015-08-21 05:37:33 +08006018#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006019#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006020 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006021 {
6022 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006023 if (!arg2 || !arg4)
6024 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006025 p = lock_user_string(arg2);
6026 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006027 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006028 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006029 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006030 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006031 unlock_user(p, arg2, 0);
6032 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006033 }
6034 break;
6035#endif
Chen Gang704eff62015-08-21 05:37:33 +08006036#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006037 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006038 if (!(p = lock_user_string(arg1)))
6039 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006040 ret = get_errno(unlink(p));
6041 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006042 break;
Chen Gang704eff62015-08-21 05:37:33 +08006043#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006044#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006045 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006046 if (!(p = lock_user_string(arg2)))
6047 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006048 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006049 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006050 break;
balrogb7d35e62007-12-12 00:40:24 +00006051#endif
bellard31e31b82003-02-18 22:55:36 +00006052 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006053 {
6054 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006055 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006056 abi_ulong gp;
6057 abi_ulong guest_argp;
6058 abi_ulong guest_envp;
6059 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006060 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006061 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006062
bellardf7341ff2003-03-30 21:00:25 +00006063 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006064 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006065 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006066 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006067 goto efault;
ths03aa1972007-12-02 06:28:08 +00006068 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006069 break;
bellard7854b052003-03-29 17:22:23 +00006070 argc++;
bellard2f619692007-11-16 10:46:05 +00006071 }
bellardf7341ff2003-03-30 21:00:25 +00006072 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006073 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006074 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006075 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006076 goto efault;
ths03aa1972007-12-02 06:28:08 +00006077 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006078 break;
bellard7854b052003-03-29 17:22:23 +00006079 envc++;
bellard2f619692007-11-16 10:46:05 +00006080 }
bellard7854b052003-03-29 17:22:23 +00006081
bellardf7341ff2003-03-30 21:00:25 +00006082 argp = alloca((argc + 1) * sizeof(void *));
6083 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006084
pbrookda94d262008-05-30 18:24:00 +00006085 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006086 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006087 if (get_user_ual(addr, gp))
6088 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006089 if (!addr)
6090 break;
bellard2f619692007-11-16 10:46:05 +00006091 if (!(*q = lock_user_string(addr)))
6092 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006093 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006094 }
bellardf7341ff2003-03-30 21:00:25 +00006095 *q = NULL;
6096
pbrookda94d262008-05-30 18:24:00 +00006097 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006098 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006099 if (get_user_ual(addr, gp))
6100 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006101 if (!addr)
6102 break;
bellard2f619692007-11-16 10:46:05 +00006103 if (!(*q = lock_user_string(addr)))
6104 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006105 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006106 }
bellardf7341ff2003-03-30 21:00:25 +00006107 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006108
bellard2f619692007-11-16 10:46:05 +00006109 if (!(p = lock_user_string(arg1)))
6110 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006111 ret = get_errno(execve(p, argp, envp));
6112 unlock_user(p, arg1, 0);
6113
bellard2f619692007-11-16 10:46:05 +00006114 goto execve_end;
6115
6116 execve_efault:
6117 ret = -TARGET_EFAULT;
6118
6119 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006120 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006121 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006122 if (get_user_ual(addr, gp)
6123 || !addr)
6124 break;
pbrook53a59602006-03-25 19:31:22 +00006125 unlock_user(*q, addr, 0);
6126 }
6127 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006128 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006129 if (get_user_ual(addr, gp)
6130 || !addr)
6131 break;
pbrook53a59602006-03-25 19:31:22 +00006132 unlock_user(*q, addr, 0);
6133 }
bellard7854b052003-03-29 17:22:23 +00006134 }
bellard31e31b82003-02-18 22:55:36 +00006135 break;
6136 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006137 if (!(p = lock_user_string(arg1)))
6138 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006139 ret = get_errno(chdir(p));
6140 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006141 break;
bellarda315a142005-01-30 22:59:18 +00006142#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006143 case TARGET_NR_time:
6144 {
pbrook53a59602006-03-25 19:31:22 +00006145 time_t host_time;
6146 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006147 if (!is_error(ret)
6148 && arg1
6149 && put_user_sal(host_time, arg1))
6150 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006151 }
6152 break;
bellarda315a142005-01-30 22:59:18 +00006153#endif
Chen Gang704eff62015-08-21 05:37:33 +08006154#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006155 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006156 if (!(p = lock_user_string(arg1)))
6157 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006158 ret = get_errno(mknod(p, arg2, arg3));
6159 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006160 break;
Chen Gang704eff62015-08-21 05:37:33 +08006161#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006162#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006163 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006164 if (!(p = lock_user_string(arg2)))
6165 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006166 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00006167 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00006168 break;
6169#endif
Chen Gang704eff62015-08-21 05:37:33 +08006170#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00006171 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00006172 if (!(p = lock_user_string(arg1)))
6173 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006174 ret = get_errno(chmod(p, arg2));
6175 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006176 break;
Chen Gang704eff62015-08-21 05:37:33 +08006177#endif
bellardebc05482003-09-30 21:08:41 +00006178#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00006179 case TARGET_NR_break:
6180 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006181#endif
6182#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00006183 case TARGET_NR_oldstat:
6184 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006185#endif
bellard31e31b82003-02-18 22:55:36 +00006186 case TARGET_NR_lseek:
6187 ret = get_errno(lseek(arg1, arg2, arg3));
6188 break;
Richard Henderson92317332010-05-03 10:07:53 -07006189#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
6190 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00006191 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07006192 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00006193 ret = get_errno(getpid());
6194 break;
Richard Henderson92317332010-05-03 10:07:53 -07006195#endif
6196#ifdef TARGET_NR_getpid
6197 case TARGET_NR_getpid:
6198 ret = get_errno(getpid());
6199 break;
6200#endif
bellard31e31b82003-02-18 22:55:36 +00006201 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01006202 {
6203 /* need to look at the data field */
6204 void *p2, *p3;
6205
6206 if (arg1) {
6207 p = lock_user_string(arg1);
6208 if (!p) {
6209 goto efault;
6210 }
6211 } else {
6212 p = NULL;
6213 }
6214
6215 p2 = lock_user_string(arg2);
6216 if (!p2) {
6217 if (arg1) {
6218 unlock_user(p, arg1, 0);
6219 }
6220 goto efault;
6221 }
6222
6223 if (arg3) {
6224 p3 = lock_user_string(arg3);
6225 if (!p3) {
6226 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006227 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01006228 }
6229 unlock_user(p2, arg2, 0);
6230 goto efault;
6231 }
6232 } else {
6233 p3 = NULL;
6234 }
6235
6236 /* FIXME - arg5 should be locked, but it isn't clear how to
6237 * do that since it's not guaranteed to be a NULL-terminated
6238 * string.
6239 */
6240 if (!arg5) {
6241 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
6242 } else {
6243 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
6244 }
6245 ret = get_errno(ret);
6246
6247 if (arg1) {
6248 unlock_user(p, arg1, 0);
6249 }
6250 unlock_user(p2, arg2, 0);
6251 if (arg3) {
6252 unlock_user(p3, arg3, 0);
6253 }
6254 }
6255 break;
thse5febef2007-04-01 18:31:35 +00006256#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00006257 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00006258 if (!(p = lock_user_string(arg1)))
6259 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006260 ret = get_errno(umount(p));
6261 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006262 break;
thse5febef2007-04-01 18:31:35 +00006263#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006264#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006265 case TARGET_NR_stime:
6266 {
pbrook53a59602006-03-25 19:31:22 +00006267 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00006268 if (get_user_sal(host_time, arg1))
6269 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006270 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00006271 }
6272 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006273#endif
bellard31e31b82003-02-18 22:55:36 +00006274 case TARGET_NR_ptrace:
6275 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00006276#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006277 case TARGET_NR_alarm:
6278 ret = alarm(arg1);
6279 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006280#endif
bellardebc05482003-09-30 21:08:41 +00006281#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00006282 case TARGET_NR_oldfstat:
6283 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006284#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006285#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006286 case TARGET_NR_pause:
6287 ret = get_errno(pause());
6288 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006289#endif
thse5febef2007-04-01 18:31:35 +00006290#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00006291 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00006292 {
pbrook53a59602006-03-25 19:31:22 +00006293 struct utimbuf tbuf, *host_tbuf;
6294 struct target_utimbuf *target_tbuf;
6295 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006296 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
6297 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006298 tbuf.actime = tswapal(target_tbuf->actime);
6299 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00006300 unlock_user_struct(target_tbuf, arg2, 0);
6301 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00006302 } else {
pbrook53a59602006-03-25 19:31:22 +00006303 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00006304 }
bellard579a97f2007-11-11 14:26:47 +00006305 if (!(p = lock_user_string(arg1)))
6306 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006307 ret = get_errno(utime(p, host_tbuf));
6308 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00006309 }
6310 break;
thse5febef2007-04-01 18:31:35 +00006311#endif
Chen Gang704eff62015-08-21 05:37:33 +08006312#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00006313 case TARGET_NR_utimes:
6314 {
bellard978a66f2004-12-06 22:58:05 +00006315 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00006316 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00006317 if (copy_from_user_timeval(&tv[0], arg2)
6318 || copy_from_user_timeval(&tv[1],
6319 arg2 + sizeof(struct target_timeval)))
6320 goto efault;
bellard978a66f2004-12-06 22:58:05 +00006321 tvp = tv;
6322 } else {
6323 tvp = NULL;
6324 }
bellard579a97f2007-11-11 14:26:47 +00006325 if (!(p = lock_user_string(arg1)))
6326 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006327 ret = get_errno(utimes(p, tvp));
6328 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00006329 }
6330 break;
Chen Gang704eff62015-08-21 05:37:33 +08006331#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006332#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00006333 case TARGET_NR_futimesat:
6334 {
6335 struct timeval *tvp, tv[2];
6336 if (arg3) {
6337 if (copy_from_user_timeval(&tv[0], arg3)
6338 || copy_from_user_timeval(&tv[1],
6339 arg3 + sizeof(struct target_timeval)))
6340 goto efault;
6341 tvp = tv;
6342 } else {
6343 tvp = NULL;
6344 }
6345 if (!(p = lock_user_string(arg2)))
6346 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006347 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00006348 unlock_user(p, arg2, 0);
6349 }
6350 break;
6351#endif
bellardebc05482003-09-30 21:08:41 +00006352#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00006353 case TARGET_NR_stty:
6354 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006355#endif
6356#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00006357 case TARGET_NR_gtty:
6358 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006359#endif
Chen Gang704eff62015-08-21 05:37:33 +08006360#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00006361 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00006362 if (!(p = lock_user_string(arg1)))
6363 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02006364 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00006365 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006366 break;
Chen Gang704eff62015-08-21 05:37:33 +08006367#endif
ths92a34c12007-09-24 09:27:49 +00006368#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
6369 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00006370 if (!(p = lock_user_string(arg2)))
6371 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006372 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006373 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00006374 break;
6375#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006376#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006377 case TARGET_NR_nice:
6378 ret = get_errno(nice(arg1));
6379 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006380#endif
bellardebc05482003-09-30 21:08:41 +00006381#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00006382 case TARGET_NR_ftime:
6383 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006384#endif
bellard31e31b82003-02-18 22:55:36 +00006385 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00006386 sync();
6387 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00006388 break;
6389 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00006390 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00006391 break;
Chen Gang704eff62015-08-21 05:37:33 +08006392#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00006393 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00006394 {
6395 void *p2;
6396 p = lock_user_string(arg1);
6397 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006398 if (!p || !p2)
6399 ret = -TARGET_EFAULT;
6400 else
6401 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006402 unlock_user(p2, arg2, 0);
6403 unlock_user(p, arg1, 0);
6404 }
bellard31e31b82003-02-18 22:55:36 +00006405 break;
Chen Gang704eff62015-08-21 05:37:33 +08006406#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006407#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006408 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006409 {
bellard579a97f2007-11-11 14:26:47 +00006410 void *p2;
ths722183f2007-09-24 09:24:37 +00006411 p = lock_user_string(arg2);
6412 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006413 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006414 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006415 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006416 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006417 unlock_user(p2, arg4, 0);
6418 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006419 }
6420 break;
6421#endif
Chen Gang704eff62015-08-21 05:37:33 +08006422#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00006423 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006424 if (!(p = lock_user_string(arg1)))
6425 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006426 ret = get_errno(mkdir(p, arg2));
6427 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006428 break;
Chen Gang704eff62015-08-21 05:37:33 +08006429#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006430#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006431 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006432 if (!(p = lock_user_string(arg2)))
6433 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006434 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006435 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006436 break;
6437#endif
Chen Gang704eff62015-08-21 05:37:33 +08006438#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00006439 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006440 if (!(p = lock_user_string(arg1)))
6441 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006442 ret = get_errno(rmdir(p));
6443 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006444 break;
Chen Gang704eff62015-08-21 05:37:33 +08006445#endif
bellard31e31b82003-02-18 22:55:36 +00006446 case TARGET_NR_dup:
6447 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02006448 if (ret >= 0) {
6449 fd_trans_dup(arg1, ret);
6450 }
bellard31e31b82003-02-18 22:55:36 +00006451 break;
Chen Gang704eff62015-08-21 05:37:33 +08006452#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00006453 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006454 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006455 break;
Chen Gang704eff62015-08-21 05:37:33 +08006456#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03006457#ifdef TARGET_NR_pipe2
6458 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006459 ret = do_pipe(cpu_env, arg1,
6460 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006461 break;
6462#endif
bellard31e31b82003-02-18 22:55:36 +00006463 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006464 {
pbrook53a59602006-03-25 19:31:22 +00006465 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006466 struct tms tms;
6467 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006468 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006469 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6470 if (!tmsp)
6471 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006472 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6473 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6474 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6475 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006476 }
bellardc596ed12003-07-13 17:32:31 +00006477 if (!is_error(ret))
6478 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006479 }
6480 break;
bellardebc05482003-09-30 21:08:41 +00006481#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006482 case TARGET_NR_prof:
6483 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006484#endif
thse5febef2007-04-01 18:31:35 +00006485#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006486 case TARGET_NR_signal:
6487 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006488#endif
bellard31e31b82003-02-18 22:55:36 +00006489 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006490 if (arg1 == 0) {
6491 ret = get_errno(acct(NULL));
6492 } else {
6493 if (!(p = lock_user_string(arg1)))
6494 goto efault;
6495 ret = get_errno(acct(path(p)));
6496 unlock_user(p, arg1, 0);
6497 }
pbrook24836682006-04-16 14:14:53 +00006498 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006499#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006500 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006501 if (!(p = lock_user_string(arg1)))
6502 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006503 ret = get_errno(umount2(p, arg2));
6504 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006505 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006506#endif
bellardebc05482003-09-30 21:08:41 +00006507#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006508 case TARGET_NR_lock:
6509 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006510#endif
bellard31e31b82003-02-18 22:55:36 +00006511 case TARGET_NR_ioctl:
6512 ret = do_ioctl(arg1, arg2, arg3);
6513 break;
6514 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006515 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006516 break;
bellardebc05482003-09-30 21:08:41 +00006517#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006518 case TARGET_NR_mpx:
6519 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006520#endif
bellard31e31b82003-02-18 22:55:36 +00006521 case TARGET_NR_setpgid:
6522 ret = get_errno(setpgid(arg1, arg2));
6523 break;
bellardebc05482003-09-30 21:08:41 +00006524#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006525 case TARGET_NR_ulimit:
6526 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006527#endif
6528#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006529 case TARGET_NR_oldolduname:
6530 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006531#endif
bellard31e31b82003-02-18 22:55:36 +00006532 case TARGET_NR_umask:
6533 ret = get_errno(umask(arg1));
6534 break;
6535 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006536 if (!(p = lock_user_string(arg1)))
6537 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006538 ret = get_errno(chroot(p));
6539 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006540 break;
Chen Gang704eff62015-08-21 05:37:33 +08006541#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00006542 case TARGET_NR_ustat:
6543 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08006544#endif
6545#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00006546 case TARGET_NR_dup2:
6547 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006548 if (ret >= 0) {
6549 fd_trans_dup(arg1, arg2);
6550 }
bellard31e31b82003-02-18 22:55:36 +00006551 break;
Chen Gang704eff62015-08-21 05:37:33 +08006552#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03006553#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6554 case TARGET_NR_dup3:
6555 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006556 if (ret >= 0) {
6557 fd_trans_dup(arg1, arg2);
6558 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03006559 break;
6560#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006561#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006562 case TARGET_NR_getppid:
6563 ret = get_errno(getppid());
6564 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006565#endif
Chen Gang704eff62015-08-21 05:37:33 +08006566#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00006567 case TARGET_NR_getpgrp:
6568 ret = get_errno(getpgrp());
6569 break;
Chen Gang704eff62015-08-21 05:37:33 +08006570#endif
bellard31e31b82003-02-18 22:55:36 +00006571 case TARGET_NR_setsid:
6572 ret = get_errno(setsid());
6573 break;
thse5febef2007-04-01 18:31:35 +00006574#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006575 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006576 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006577#if defined(TARGET_ALPHA)
6578 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006579 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006580 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006581 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6582 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006583 act._sa_handler = old_act->_sa_handler;
6584 target_siginitset(&act.sa_mask, old_act->sa_mask);
6585 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006586 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006587 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006588 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006589 }
6590 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006591 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006592 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6593 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006594 old_act->_sa_handler = oact._sa_handler;
6595 old_act->sa_mask = oact.sa_mask.sig[0];
6596 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006597 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006598 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006599#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006600 struct target_sigaction act, oact, *pact, *old_act;
6601
6602 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006603 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6604 goto efault;
bellard106ec872006-06-27 21:08:10 +00006605 act._sa_handler = old_act->_sa_handler;
6606 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6607 act.sa_flags = old_act->sa_flags;
6608 unlock_user_struct(old_act, arg2, 0);
6609 pact = &act;
6610 } else {
6611 pact = NULL;
6612 }
6613
6614 ret = get_errno(do_sigaction(arg1, pact, &oact));
6615
6616 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006617 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6618 goto efault;
bellard106ec872006-06-27 21:08:10 +00006619 old_act->_sa_handler = oact._sa_handler;
6620 old_act->sa_flags = oact.sa_flags;
6621 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6622 old_act->sa_mask.sig[1] = 0;
6623 old_act->sa_mask.sig[2] = 0;
6624 old_act->sa_mask.sig[3] = 0;
6625 unlock_user_struct(old_act, arg3, 1);
6626 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006627#else
6628 struct target_old_sigaction *old_act;
6629 struct target_sigaction act, oact, *pact;
6630 if (arg2) {
6631 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6632 goto efault;
6633 act._sa_handler = old_act->_sa_handler;
6634 target_siginitset(&act.sa_mask, old_act->sa_mask);
6635 act.sa_flags = old_act->sa_flags;
6636 act.sa_restorer = old_act->sa_restorer;
6637 unlock_user_struct(old_act, arg2, 0);
6638 pact = &act;
6639 } else {
6640 pact = NULL;
6641 }
6642 ret = get_errno(do_sigaction(arg1, pact, &oact));
6643 if (!is_error(ret) && arg3) {
6644 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6645 goto efault;
6646 old_act->_sa_handler = oact._sa_handler;
6647 old_act->sa_mask = oact.sa_mask.sig[0];
6648 old_act->sa_flags = oact.sa_flags;
6649 old_act->sa_restorer = oact.sa_restorer;
6650 unlock_user_struct(old_act, arg3, 1);
6651 }
ths388bb212007-05-13 13:58:00 +00006652#endif
bellard31e31b82003-02-18 22:55:36 +00006653 }
6654 break;
thse5febef2007-04-01 18:31:35 +00006655#endif
bellard66fb9762003-03-23 01:06:05 +00006656 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006657 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006658#if defined(TARGET_ALPHA)
6659 struct target_sigaction act, oact, *pact = 0;
6660 struct target_rt_sigaction *rt_act;
6661 /* ??? arg4 == sizeof(sigset_t). */
6662 if (arg2) {
6663 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6664 goto efault;
6665 act._sa_handler = rt_act->_sa_handler;
6666 act.sa_mask = rt_act->sa_mask;
6667 act.sa_flags = rt_act->sa_flags;
6668 act.sa_restorer = arg5;
6669 unlock_user_struct(rt_act, arg2, 0);
6670 pact = &act;
6671 }
6672 ret = get_errno(do_sigaction(arg1, pact, &oact));
6673 if (!is_error(ret) && arg3) {
6674 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6675 goto efault;
6676 rt_act->_sa_handler = oact._sa_handler;
6677 rt_act->sa_mask = oact.sa_mask;
6678 rt_act->sa_flags = oact.sa_flags;
6679 unlock_user_struct(rt_act, arg3, 1);
6680 }
6681#else
pbrook53a59602006-03-25 19:31:22 +00006682 struct target_sigaction *act;
6683 struct target_sigaction *oact;
6684
bellard579a97f2007-11-11 14:26:47 +00006685 if (arg2) {
6686 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6687 goto efault;
6688 } else
pbrook53a59602006-03-25 19:31:22 +00006689 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006690 if (arg3) {
6691 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6692 ret = -TARGET_EFAULT;
6693 goto rt_sigaction_fail;
6694 }
6695 } else
pbrook53a59602006-03-25 19:31:22 +00006696 oact = NULL;
6697 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006698 rt_sigaction_fail:
6699 if (act)
pbrook53a59602006-03-25 19:31:22 +00006700 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006701 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006702 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006703#endif
pbrook53a59602006-03-25 19:31:22 +00006704 }
bellard66fb9762003-03-23 01:06:05 +00006705 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006706#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006707 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006708 {
6709 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006710 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006711 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006712 host_to_target_old_sigset(&target_set, &cur_set);
6713 ret = target_set;
6714 }
6715 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006716#endif
6717#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006718 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006719 {
6720 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006721 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006722 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006723 target_to_host_old_sigset(&set, &target_set);
6724 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006725 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006726 host_to_target_old_sigset(&target_set, &oset);
6727 ret = target_set;
6728 }
6729 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006730#endif
thse5febef2007-04-01 18:31:35 +00006731#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006732 case TARGET_NR_sigprocmask:
6733 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006734#if defined(TARGET_ALPHA)
6735 sigset_t set, oldset;
6736 abi_ulong mask;
6737 int how;
6738
6739 switch (arg1) {
6740 case TARGET_SIG_BLOCK:
6741 how = SIG_BLOCK;
6742 break;
6743 case TARGET_SIG_UNBLOCK:
6744 how = SIG_UNBLOCK;
6745 break;
6746 case TARGET_SIG_SETMASK:
6747 how = SIG_SETMASK;
6748 break;
6749 default:
6750 ret = -TARGET_EINVAL;
6751 goto fail;
6752 }
6753 mask = arg2;
6754 target_to_host_old_sigset(&set, &mask);
6755
Alex Barcelo1c275922014-03-14 14:36:55 +00006756 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006757 if (!is_error(ret)) {
6758 host_to_target_old_sigset(&mask, &oldset);
6759 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006760 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006761 }
6762#else
bellard66fb9762003-03-23 01:06:05 +00006763 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006764 int how;
ths3b46e622007-09-17 08:09:54 +00006765
pbrook53a59602006-03-25 19:31:22 +00006766 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006767 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006768 case TARGET_SIG_BLOCK:
6769 how = SIG_BLOCK;
6770 break;
6771 case TARGET_SIG_UNBLOCK:
6772 how = SIG_UNBLOCK;
6773 break;
6774 case TARGET_SIG_SETMASK:
6775 how = SIG_SETMASK;
6776 break;
6777 default:
ths0da46a62007-10-20 20:23:07 +00006778 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006779 goto fail;
6780 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006781 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006782 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006783 target_to_host_old_sigset(&set, p);
6784 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006785 set_ptr = &set;
6786 } else {
6787 how = 0;
6788 set_ptr = NULL;
6789 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006790 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006791 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006792 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006793 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006794 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006795 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006796 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006797#endif
bellard66fb9762003-03-23 01:06:05 +00006798 }
6799 break;
thse5febef2007-04-01 18:31:35 +00006800#endif
bellard66fb9762003-03-23 01:06:05 +00006801 case TARGET_NR_rt_sigprocmask:
6802 {
6803 int how = arg1;
6804 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006805
pbrook53a59602006-03-25 19:31:22 +00006806 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006807 switch(how) {
6808 case TARGET_SIG_BLOCK:
6809 how = SIG_BLOCK;
6810 break;
6811 case TARGET_SIG_UNBLOCK:
6812 how = SIG_UNBLOCK;
6813 break;
6814 case TARGET_SIG_SETMASK:
6815 how = SIG_SETMASK;
6816 break;
6817 default:
ths0da46a62007-10-20 20:23:07 +00006818 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006819 goto fail;
6820 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006821 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006823 target_to_host_sigset(&set, p);
6824 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006825 set_ptr = &set;
6826 } else {
6827 how = 0;
6828 set_ptr = NULL;
6829 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006830 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006831 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006832 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006833 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006834 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006835 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006836 }
6837 }
6838 break;
thse5febef2007-04-01 18:31:35 +00006839#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006840 case TARGET_NR_sigpending:
6841 {
6842 sigset_t set;
6843 ret = get_errno(sigpending(&set));
6844 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006845 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006846 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006847 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006848 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006849 }
6850 }
6851 break;
thse5febef2007-04-01 18:31:35 +00006852#endif
bellard66fb9762003-03-23 01:06:05 +00006853 case TARGET_NR_rt_sigpending:
6854 {
6855 sigset_t set;
6856 ret = get_errno(sigpending(&set));
6857 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006858 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006859 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006860 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006861 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006862 }
6863 }
6864 break;
thse5febef2007-04-01 18:31:35 +00006865#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006866 case TARGET_NR_sigsuspend:
6867 {
6868 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006869#if defined(TARGET_ALPHA)
6870 abi_ulong mask = arg1;
6871 target_to_host_old_sigset(&set, &mask);
6872#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006873 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006874 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006875 target_to_host_old_sigset(&set, p);
6876 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006877#endif
bellard66fb9762003-03-23 01:06:05 +00006878 ret = get_errno(sigsuspend(&set));
6879 }
6880 break;
thse5febef2007-04-01 18:31:35 +00006881#endif
bellard66fb9762003-03-23 01:06:05 +00006882 case TARGET_NR_rt_sigsuspend:
6883 {
6884 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006885 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006886 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006887 target_to_host_sigset(&set, p);
6888 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006889 ret = get_errno(sigsuspend(&set));
6890 }
6891 break;
6892 case TARGET_NR_rt_sigtimedwait:
6893 {
bellard66fb9762003-03-23 01:06:05 +00006894 sigset_t set;
6895 struct timespec uts, *puts;
6896 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006897
Anthony Liguoric227f092009-10-01 16:12:16 -05006898 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006899 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006900 target_to_host_sigset(&set, p);
6901 unlock_user(p, arg1, 0);
6902 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006903 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006904 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006905 } else {
6906 puts = NULL;
6907 }
6908 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006909 if (!is_error(ret)) {
6910 if (arg2) {
6911 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6912 0);
6913 if (!p) {
6914 goto efault;
6915 }
6916 host_to_target_siginfo(p, &uinfo);
6917 unlock_user(p, arg2, sizeof(target_siginfo_t));
6918 }
6919 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006920 }
6921 }
6922 break;
6923 case TARGET_NR_rt_sigqueueinfo:
6924 {
6925 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006926 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006927 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006928 target_to_host_siginfo(&uinfo, p);
6929 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006930 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6931 }
6932 break;
thse5febef2007-04-01 18:31:35 +00006933#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006934 case TARGET_NR_sigreturn:
6935 /* NOTE: ret is eax, so not transcoding must be done */
6936 ret = do_sigreturn(cpu_env);
6937 break;
thse5febef2007-04-01 18:31:35 +00006938#endif
bellard66fb9762003-03-23 01:06:05 +00006939 case TARGET_NR_rt_sigreturn:
6940 /* NOTE: ret is eax, so not transcoding must be done */
6941 ret = do_rt_sigreturn(cpu_env);
6942 break;
bellard31e31b82003-02-18 22:55:36 +00006943 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006944 if (!(p = lock_user_string(arg1)))
6945 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006946 ret = get_errno(sethostname(p, arg2));
6947 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006948 break;
6949 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006950 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006951 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006952 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006953 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006954 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6955 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006956 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6957 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006958 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006959 ret = get_errno(setrlimit(resource, &rlim));
6960 }
6961 break;
bellard31e31b82003-02-18 22:55:36 +00006962 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006963 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006964 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006965 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006966 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006967
bellard9de5e442003-03-23 16:49:39 +00006968 ret = get_errno(getrlimit(resource, &rlim));
6969 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006970 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6971 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006972 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6973 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006974 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006975 }
6976 }
6977 break;
bellard31e31b82003-02-18 22:55:36 +00006978 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006979 {
6980 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006981 ret = get_errno(getrusage(arg1, &rusage));
6982 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006983 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006984 }
6985 }
6986 break;
bellard31e31b82003-02-18 22:55:36 +00006987 case TARGET_NR_gettimeofday:
6988 {
bellard31e31b82003-02-18 22:55:36 +00006989 struct timeval tv;
6990 ret = get_errno(gettimeofday(&tv, NULL));
6991 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006992 if (copy_to_user_timeval(arg1, &tv))
6993 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006994 }
6995 }
6996 break;
6997 case TARGET_NR_settimeofday:
6998 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006999 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007000 struct timezone tz, *ptz = NULL;
7001
Paul Burtonb67d8032014-06-22 11:25:41 +01007002 if (arg1) {
7003 if (copy_from_user_timeval(&tv, arg1)) {
7004 goto efault;
7005 }
7006 ptv = &tv;
7007 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007008
7009 if (arg2) {
7010 if (copy_from_user_timezone(&tz, arg2)) {
7011 goto efault;
7012 }
7013 ptz = &tz;
7014 }
7015
Paul Burtonb67d8032014-06-22 11:25:41 +01007016 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007017 }
7018 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007019#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007020 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007021#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7022 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7023#else
bellardf2674e32003-07-09 12:26:09 +00007024 {
pbrook53a59602006-03-25 19:31:22 +00007025 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007026 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007027 long nsel;
7028
bellard579a97f2007-11-11 14:26:47 +00007029 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7030 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007031 nsel = tswapal(sel->n);
7032 inp = tswapal(sel->inp);
7033 outp = tswapal(sel->outp);
7034 exp = tswapal(sel->exp);
7035 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007036 unlock_user_struct(sel, arg1, 0);
7037 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007038 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007039#endif
bellardf2674e32003-07-09 12:26:09 +00007040 break;
bellard048f6b42005-11-26 18:47:20 +00007041#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007042#ifdef TARGET_NR_pselect6
7043 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007044 {
7045 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7046 fd_set rfds, wfds, efds;
7047 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7048 struct timespec ts, *ts_ptr;
7049
7050 /*
7051 * The 6th arg is actually two args smashed together,
7052 * so we cannot use the C library.
7053 */
7054 sigset_t set;
7055 struct {
7056 sigset_t *set;
7057 size_t size;
7058 } sig, *sig_ptr;
7059
7060 abi_ulong arg_sigset, arg_sigsize, *arg7;
7061 target_sigset_t *target_sigset;
7062
7063 n = arg1;
7064 rfd_addr = arg2;
7065 wfd_addr = arg3;
7066 efd_addr = arg4;
7067 ts_addr = arg5;
7068
7069 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7070 if (ret) {
7071 goto fail;
7072 }
7073 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7074 if (ret) {
7075 goto fail;
7076 }
7077 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7078 if (ret) {
7079 goto fail;
7080 }
7081
7082 /*
7083 * This takes a timespec, and not a timeval, so we cannot
7084 * use the do_select() helper ...
7085 */
7086 if (ts_addr) {
7087 if (target_to_host_timespec(&ts, ts_addr)) {
7088 goto efault;
7089 }
7090 ts_ptr = &ts;
7091 } else {
7092 ts_ptr = NULL;
7093 }
7094
7095 /* Extract the two packed args for the sigset */
7096 if (arg6) {
7097 sig_ptr = &sig;
7098 sig.size = _NSIG / 8;
7099
7100 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7101 if (!arg7) {
7102 goto efault;
7103 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007104 arg_sigset = tswapal(arg7[0]);
7105 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007106 unlock_user(arg7, arg6, 0);
7107
7108 if (arg_sigset) {
7109 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007110 if (arg_sigsize != sizeof(*target_sigset)) {
7111 /* Like the kernel, we enforce correct size sigsets */
7112 ret = -TARGET_EINVAL;
7113 goto fail;
7114 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007115 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7116 sizeof(*target_sigset), 1);
7117 if (!target_sigset) {
7118 goto efault;
7119 }
7120 target_to_host_sigset(&set, target_sigset);
7121 unlock_user(target_sigset, arg_sigset, 0);
7122 } else {
7123 sig.set = NULL;
7124 }
7125 } else {
7126 sig_ptr = NULL;
7127 }
7128
7129 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7130 ts_ptr, sig_ptr));
7131
7132 if (!is_error(ret)) {
7133 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7134 goto efault;
7135 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7136 goto efault;
7137 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7138 goto efault;
7139
7140 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
7141 goto efault;
7142 }
7143 }
7144 break;
Riku Voipio9e423822010-05-07 12:28:05 +00007145#endif
Chen Gang704eff62015-08-21 05:37:33 +08007146#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00007147 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00007148 {
7149 void *p2;
7150 p = lock_user_string(arg1);
7151 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007152 if (!p || !p2)
7153 ret = -TARGET_EFAULT;
7154 else
7155 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007156 unlock_user(p2, arg2, 0);
7157 unlock_user(p, arg1, 0);
7158 }
bellard31e31b82003-02-18 22:55:36 +00007159 break;
Chen Gang704eff62015-08-21 05:37:33 +08007160#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007161#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00007162 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00007163 {
bellard579a97f2007-11-11 14:26:47 +00007164 void *p2;
thsf0b62432007-09-24 09:25:40 +00007165 p = lock_user_string(arg1);
7166 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00007167 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007168 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00007169 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007170 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00007171 unlock_user(p2, arg3, 0);
7172 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00007173 }
7174 break;
7175#endif
bellardebc05482003-09-30 21:08:41 +00007176#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00007177 case TARGET_NR_oldlstat:
7178 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007179#endif
Chen Gang704eff62015-08-21 05:37:33 +08007180#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00007181 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00007182 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01007183 void *p2;
pbrook53a59602006-03-25 19:31:22 +00007184 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00007185 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007186 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00007187 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09007188 } else if (!arg3) {
7189 /* Short circuit this for the magic exe check. */
7190 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01007191 } else if (is_proc_myself((const char *)p, "exe")) {
7192 char real[PATH_MAX], *temp;
7193 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09007194 /* Return value is # of bytes that we wrote to the buffer. */
7195 if (temp == NULL) {
7196 ret = get_errno(-1);
7197 } else {
7198 /* Don't worry about sign mismatch as earlier mapping
7199 * logic would have thrown a bad address error. */
7200 ret = MIN(strlen(real), arg3);
7201 /* We cannot NUL terminate the string. */
7202 memcpy(p2, real, ret);
7203 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01007204 } else {
7205 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00007206 }
pbrook53a59602006-03-25 19:31:22 +00007207 unlock_user(p2, arg2, ret);
7208 unlock_user(p, arg1, 0);
7209 }
bellard31e31b82003-02-18 22:55:36 +00007210 break;
Chen Gang704eff62015-08-21 05:37:33 +08007211#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007212#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00007213 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00007214 {
bellard579a97f2007-11-11 14:26:47 +00007215 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00007216 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007217 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01007218 if (!p || !p2) {
7219 ret = -TARGET_EFAULT;
7220 } else if (is_proc_myself((const char *)p, "exe")) {
7221 char real[PATH_MAX], *temp;
7222 temp = realpath(exec_path, real);
7223 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
7224 snprintf((char *)p2, arg4, "%s", real);
7225 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01007226 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01007227 }
bellard579a97f2007-11-11 14:26:47 +00007228 unlock_user(p2, arg3, ret);
7229 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00007230 }
7231 break;
7232#endif
thse5febef2007-04-01 18:31:35 +00007233#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00007234 case TARGET_NR_uselib:
7235 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007236#endif
7237#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00007238 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00007239 if (!(p = lock_user_string(arg1)))
7240 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007241 ret = get_errno(swapon(p, arg2));
7242 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007243 break;
thse5febef2007-04-01 18:31:35 +00007244#endif
bellard31e31b82003-02-18 22:55:36 +00007245 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00007246 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
7247 /* arg4 must be ignored in all other cases */
7248 p = lock_user_string(arg4);
7249 if (!p) {
7250 goto efault;
7251 }
7252 ret = get_errno(reboot(arg1, arg2, arg3, p));
7253 unlock_user(p, arg4, 0);
7254 } else {
7255 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
7256 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02007257 break;
thse5febef2007-04-01 18:31:35 +00007258#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00007259 case TARGET_NR_readdir:
7260 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007261#endif
7262#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00007263 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01007264#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
7265 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007266 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
7267 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00007268 {
blueswir1992f48a2007-10-14 16:27:31 +00007269 abi_ulong *v;
7270 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00007271 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
7272 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007273 v1 = tswapal(v[0]);
7274 v2 = tswapal(v[1]);
7275 v3 = tswapal(v[2]);
7276 v4 = tswapal(v[3]);
7277 v5 = tswapal(v[4]);
7278 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00007279 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00007280 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00007281 target_to_host_bitmask(v4, mmap_flags_tbl),
7282 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00007283 }
bellard31e31b82003-02-18 22:55:36 +00007284#else
ths5fafdf22007-09-16 21:08:06 +00007285 ret = get_errno(target_mmap(arg1, arg2, arg3,
7286 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00007287 arg5,
7288 arg6));
bellard31e31b82003-02-18 22:55:36 +00007289#endif
bellard6fb883e2003-07-09 17:12:39 +00007290 break;
thse5febef2007-04-01 18:31:35 +00007291#endif
bellarda315a142005-01-30 22:59:18 +00007292#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00007293 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00007294#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00007295#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00007296#endif
ths5fafdf22007-09-16 21:08:06 +00007297 ret = get_errno(target_mmap(arg1, arg2, arg3,
7298 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00007299 arg5,
bellardc573ff62004-01-04 15:51:36 +00007300 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00007301 break;
bellarda315a142005-01-30 22:59:18 +00007302#endif
bellard31e31b82003-02-18 22:55:36 +00007303 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00007304 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007305 break;
bellard9de5e442003-03-23 16:49:39 +00007306 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01007307 {
Andreas Färber0429a972013-08-26 18:14:44 +02007308 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01007309 /* Special hack to detect libc making the stack executable. */
7310 if ((arg3 & PROT_GROWSDOWN)
7311 && arg1 >= ts->info->stack_limit
7312 && arg1 <= ts->info->start_stack) {
7313 arg3 &= ~PROT_GROWSDOWN;
7314 arg2 = arg2 + arg1 - ts->info->stack_limit;
7315 arg1 = ts->info->stack_limit;
7316 }
7317 }
bellard54936002003-05-13 00:25:15 +00007318 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007319 break;
thse5febef2007-04-01 18:31:35 +00007320#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00007321 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00007322 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00007323 break;
thse5febef2007-04-01 18:31:35 +00007324#endif
pbrook53a59602006-03-25 19:31:22 +00007325 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00007326#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00007327 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00007328 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00007329 break;
thse5febef2007-04-01 18:31:35 +00007330#endif
7331#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00007332 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00007333 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007334 break;
thse5febef2007-04-01 18:31:35 +00007335#endif
7336#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00007337 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00007338 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00007339 break;
thse5febef2007-04-01 18:31:35 +00007340#endif
7341#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00007342 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05007343 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00007344 break;
thse5febef2007-04-01 18:31:35 +00007345#endif
7346#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00007347 case TARGET_NR_munlockall:
7348 ret = get_errno(munlockall());
7349 break;
thse5febef2007-04-01 18:31:35 +00007350#endif
bellard31e31b82003-02-18 22:55:36 +00007351 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00007352 if (!(p = lock_user_string(arg1)))
7353 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007354 ret = get_errno(truncate(p, arg2));
7355 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007356 break;
7357 case TARGET_NR_ftruncate:
7358 ret = get_errno(ftruncate(arg1, arg2));
7359 break;
7360 case TARGET_NR_fchmod:
7361 ret = get_errno(fchmod(arg1, arg2));
7362 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007363#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00007364 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00007365 if (!(p = lock_user_string(arg2)))
7366 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007367 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007368 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00007369 break;
7370#endif
bellard31e31b82003-02-18 22:55:36 +00007371 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07007372 /* Note that negative values are valid for getpriority, so we must
7373 differentiate based on errno settings. */
7374 errno = 0;
7375 ret = getpriority(arg1, arg2);
7376 if (ret == -1 && errno != 0) {
7377 ret = -host_to_target_errno(errno);
7378 break;
7379 }
7380#ifdef TARGET_ALPHA
7381 /* Return value is the unbiased priority. Signal no error. */
7382 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
7383#else
7384 /* Return value is a biased priority to avoid negative numbers. */
7385 ret = 20 - ret;
7386#endif
bellard31e31b82003-02-18 22:55:36 +00007387 break;
7388 case TARGET_NR_setpriority:
7389 ret = get_errno(setpriority(arg1, arg2, arg3));
7390 break;
bellardebc05482003-09-30 21:08:41 +00007391#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00007392 case TARGET_NR_profil:
7393 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007394#endif
bellard31e31b82003-02-18 22:55:36 +00007395 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00007396 if (!(p = lock_user_string(arg1)))
7397 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007398 ret = get_errno(statfs(path(p), &stfs));
7399 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007400 convert_statfs:
7401 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007402 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007403
bellard579a97f2007-11-11 14:26:47 +00007404 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
7405 goto efault;
7406 __put_user(stfs.f_type, &target_stfs->f_type);
7407 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7408 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7409 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7410 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7411 __put_user(stfs.f_files, &target_stfs->f_files);
7412 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7413 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7414 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7415 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007416 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7417 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00007418 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007419 }
7420 break;
7421 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00007422 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00007423 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00007424#ifdef TARGET_NR_statfs64
7425 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00007426 if (!(p = lock_user_string(arg1)))
7427 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007428 ret = get_errno(statfs(path(p), &stfs));
7429 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00007430 convert_statfs64:
7431 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007432 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007433
bellard579a97f2007-11-11 14:26:47 +00007434 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7435 goto efault;
7436 __put_user(stfs.f_type, &target_stfs->f_type);
7437 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7438 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7439 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7440 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7441 __put_user(stfs.f_files, &target_stfs->f_files);
7442 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7443 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7444 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7445 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007446 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7447 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007448 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007449 }
7450 break;
7451 case TARGET_NR_fstatfs64:
7452 ret = get_errno(fstatfs(arg1, &stfs));
7453 goto convert_statfs64;
7454#endif
bellardebc05482003-09-30 21:08:41 +00007455#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007456 case TARGET_NR_ioperm:
7457 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007458#endif
thse5febef2007-04-01 18:31:35 +00007459#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007460 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007461 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007462 break;
thse5febef2007-04-01 18:31:35 +00007463#endif
bellard3532fa72006-06-24 15:06:03 +00007464#ifdef TARGET_NR_accept
7465 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007466 ret = do_accept4(arg1, arg2, arg3, 0);
7467 break;
7468#endif
7469#ifdef TARGET_NR_accept4
7470 case TARGET_NR_accept4:
7471#ifdef CONFIG_ACCEPT4
7472 ret = do_accept4(arg1, arg2, arg3, arg4);
7473#else
7474 goto unimplemented;
7475#endif
bellard3532fa72006-06-24 15:06:03 +00007476 break;
7477#endif
7478#ifdef TARGET_NR_bind
7479 case TARGET_NR_bind:
7480 ret = do_bind(arg1, arg2, arg3);
7481 break;
7482#endif
7483#ifdef TARGET_NR_connect
7484 case TARGET_NR_connect:
7485 ret = do_connect(arg1, arg2, arg3);
7486 break;
7487#endif
7488#ifdef TARGET_NR_getpeername
7489 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007490 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007491 break;
7492#endif
7493#ifdef TARGET_NR_getsockname
7494 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007495 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007496 break;
7497#endif
7498#ifdef TARGET_NR_getsockopt
7499 case TARGET_NR_getsockopt:
7500 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7501 break;
7502#endif
7503#ifdef TARGET_NR_listen
7504 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007505 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007506 break;
7507#endif
7508#ifdef TARGET_NR_recv
7509 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007510 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007511 break;
7512#endif
7513#ifdef TARGET_NR_recvfrom
7514 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007515 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007516 break;
7517#endif
7518#ifdef TARGET_NR_recvmsg
7519 case TARGET_NR_recvmsg:
7520 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7521 break;
7522#endif
7523#ifdef TARGET_NR_send
7524 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007525 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007526 break;
7527#endif
7528#ifdef TARGET_NR_sendmsg
7529 case TARGET_NR_sendmsg:
7530 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7531 break;
7532#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007533#ifdef TARGET_NR_sendmmsg
7534 case TARGET_NR_sendmmsg:
7535 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7536 break;
7537 case TARGET_NR_recvmmsg:
7538 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7539 break;
7540#endif
bellard3532fa72006-06-24 15:06:03 +00007541#ifdef TARGET_NR_sendto
7542 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007543 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007544 break;
7545#endif
7546#ifdef TARGET_NR_shutdown
7547 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007548 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007549 break;
7550#endif
7551#ifdef TARGET_NR_socket
7552 case TARGET_NR_socket:
7553 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02007554 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00007555 break;
7556#endif
7557#ifdef TARGET_NR_socketpair
7558 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007559 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007560 break;
7561#endif
7562#ifdef TARGET_NR_setsockopt
7563 case TARGET_NR_setsockopt:
7564 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7565 break;
7566#endif
ths7494b0f2007-02-11 18:26:53 +00007567
bellard31e31b82003-02-18 22:55:36 +00007568 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007569 if (!(p = lock_user_string(arg2)))
7570 goto efault;
thse5574482007-02-11 20:03:13 +00007571 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7572 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007573 break;
7574
bellard31e31b82003-02-18 22:55:36 +00007575 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007576 {
bellard66fb9762003-03-23 01:06:05 +00007577 struct itimerval value, ovalue, *pvalue;
7578
pbrook53a59602006-03-25 19:31:22 +00007579 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007580 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007581 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7582 || copy_from_user_timeval(&pvalue->it_value,
7583 arg2 + sizeof(struct target_timeval)))
7584 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007585 } else {
7586 pvalue = NULL;
7587 }
7588 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007589 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007590 if (copy_to_user_timeval(arg3,
7591 &ovalue.it_interval)
7592 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7593 &ovalue.it_value))
7594 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007595 }
7596 }
7597 break;
bellard31e31b82003-02-18 22:55:36 +00007598 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007599 {
bellard66fb9762003-03-23 01:06:05 +00007600 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007601
bellard66fb9762003-03-23 01:06:05 +00007602 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007603 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007604 if (copy_to_user_timeval(arg2,
7605 &value.it_interval)
7606 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7607 &value.it_value))
7608 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007609 }
7610 }
7611 break;
Chen Gang704eff62015-08-21 05:37:33 +08007612#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00007613 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007614 if (!(p = lock_user_string(arg1)))
7615 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007616 ret = get_errno(stat(path(p), &st));
7617 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007618 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007619#endif
7620#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00007621 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007622 if (!(p = lock_user_string(arg1)))
7623 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007624 ret = get_errno(lstat(path(p), &st));
7625 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007626 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08007627#endif
bellard31e31b82003-02-18 22:55:36 +00007628 case TARGET_NR_fstat:
7629 {
7630 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08007631#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00007632 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08007633#endif
bellard31e31b82003-02-18 22:55:36 +00007634 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007635 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007636
bellard579a97f2007-11-11 14:26:47 +00007637 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7638 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007639 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007640 __put_user(st.st_dev, &target_st->st_dev);
7641 __put_user(st.st_ino, &target_st->st_ino);
7642 __put_user(st.st_mode, &target_st->st_mode);
7643 __put_user(st.st_uid, &target_st->st_uid);
7644 __put_user(st.st_gid, &target_st->st_gid);
7645 __put_user(st.st_nlink, &target_st->st_nlink);
7646 __put_user(st.st_rdev, &target_st->st_rdev);
7647 __put_user(st.st_size, &target_st->st_size);
7648 __put_user(st.st_blksize, &target_st->st_blksize);
7649 __put_user(st.st_blocks, &target_st->st_blocks);
7650 __put_user(st.st_atime, &target_st->target_st_atime);
7651 __put_user(st.st_mtime, &target_st->target_st_mtime);
7652 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007653 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007654 }
7655 }
7656 break;
bellardebc05482003-09-30 21:08:41 +00007657#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007658 case TARGET_NR_olduname:
7659 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007660#endif
7661#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007662 case TARGET_NR_iopl:
7663 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007664#endif
bellard31e31b82003-02-18 22:55:36 +00007665 case TARGET_NR_vhangup:
7666 ret = get_errno(vhangup());
7667 break;
bellardebc05482003-09-30 21:08:41 +00007668#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007669 case TARGET_NR_idle:
7670 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007671#endif
bellard42ad6ae2005-01-03 22:48:11 +00007672#ifdef TARGET_NR_syscall
7673 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007674 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7675 arg6, arg7, arg8, 0);
7676 break;
bellard42ad6ae2005-01-03 22:48:11 +00007677#endif
bellard31e31b82003-02-18 22:55:36 +00007678 case TARGET_NR_wait4:
7679 {
7680 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007681 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007682 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007683 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007684 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007685 if (target_rusage)
7686 rusage_ptr = &rusage;
7687 else
7688 rusage_ptr = NULL;
7689 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7690 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007691 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007692 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007693 if (put_user_s32(status, status_ptr))
7694 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007695 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007696 if (target_rusage) {
7697 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7698 if (rusage_err) {
7699 ret = rusage_err;
7700 }
7701 }
bellard31e31b82003-02-18 22:55:36 +00007702 }
7703 }
7704 break;
thse5febef2007-04-01 18:31:35 +00007705#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007706 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007707 if (!(p = lock_user_string(arg1)))
7708 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007709 ret = get_errno(swapoff(p));
7710 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007711 break;
thse5febef2007-04-01 18:31:35 +00007712#endif
bellard31e31b82003-02-18 22:55:36 +00007713 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007714 {
pbrook53a59602006-03-25 19:31:22 +00007715 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007716 struct sysinfo value;
7717 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007718 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007719 {
bellard579a97f2007-11-11 14:26:47 +00007720 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7721 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007722 __put_user(value.uptime, &target_value->uptime);
7723 __put_user(value.loads[0], &target_value->loads[0]);
7724 __put_user(value.loads[1], &target_value->loads[1]);
7725 __put_user(value.loads[2], &target_value->loads[2]);
7726 __put_user(value.totalram, &target_value->totalram);
7727 __put_user(value.freeram, &target_value->freeram);
7728 __put_user(value.sharedram, &target_value->sharedram);
7729 __put_user(value.bufferram, &target_value->bufferram);
7730 __put_user(value.totalswap, &target_value->totalswap);
7731 __put_user(value.freeswap, &target_value->freeswap);
7732 __put_user(value.procs, &target_value->procs);
7733 __put_user(value.totalhigh, &target_value->totalhigh);
7734 __put_user(value.freehigh, &target_value->freehigh);
7735 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007736 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007737 }
7738 }
7739 break;
thse5febef2007-04-01 18:31:35 +00007740#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007741 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007742 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7743 break;
thse5febef2007-04-01 18:31:35 +00007744#endif
aurel32e5289082009-04-18 16:16:12 +00007745#ifdef TARGET_NR_semget
7746 case TARGET_NR_semget:
7747 ret = get_errno(semget(arg1, arg2, arg3));
7748 break;
7749#endif
7750#ifdef TARGET_NR_semop
7751 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007752 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007753 break;
7754#endif
7755#ifdef TARGET_NR_semctl
7756 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01007757 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00007758 break;
7759#endif
aurel32eeb438c2008-10-13 21:08:55 +00007760#ifdef TARGET_NR_msgctl
7761 case TARGET_NR_msgctl:
7762 ret = do_msgctl(arg1, arg2, arg3);
7763 break;
7764#endif
7765#ifdef TARGET_NR_msgget
7766 case TARGET_NR_msgget:
7767 ret = get_errno(msgget(arg1, arg2));
7768 break;
7769#endif
7770#ifdef TARGET_NR_msgrcv
7771 case TARGET_NR_msgrcv:
7772 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7773 break;
7774#endif
7775#ifdef TARGET_NR_msgsnd
7776 case TARGET_NR_msgsnd:
7777 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7778 break;
7779#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007780#ifdef TARGET_NR_shmget
7781 case TARGET_NR_shmget:
7782 ret = get_errno(shmget(arg1, arg2, arg3));
7783 break;
7784#endif
7785#ifdef TARGET_NR_shmctl
7786 case TARGET_NR_shmctl:
7787 ret = do_shmctl(arg1, arg2, arg3);
7788 break;
7789#endif
7790#ifdef TARGET_NR_shmat
7791 case TARGET_NR_shmat:
7792 ret = do_shmat(arg1, arg2, arg3);
7793 break;
7794#endif
7795#ifdef TARGET_NR_shmdt
7796 case TARGET_NR_shmdt:
7797 ret = do_shmdt(arg1);
7798 break;
7799#endif
bellard31e31b82003-02-18 22:55:36 +00007800 case TARGET_NR_fsync:
7801 ret = get_errno(fsync(arg1));
7802 break;
bellard31e31b82003-02-18 22:55:36 +00007803 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007804 /* Linux manages to have three different orderings for its
7805 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7806 * match the kernel's CONFIG_CLONE_* settings.
7807 * Microblaze is further special in that it uses a sixth
7808 * implicit argument to clone for the TLS pointer.
7809 */
7810#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007811 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007812#elif defined(TARGET_CLONE_BACKWARDS)
7813 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7814#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007815 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007816#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007817 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007818#endif
bellard1b6b0292003-03-22 17:31:38 +00007819 break;
bellardec86b0f2003-04-11 00:15:04 +00007820#ifdef __NR_exit_group
7821 /* new thread calls */
7822 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007823#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007824 _mcleanup();
7825#endif
bellarde9009672005-04-26 20:42:36 +00007826 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007827 ret = get_errno(exit_group(arg1));
7828 break;
7829#endif
bellard31e31b82003-02-18 22:55:36 +00007830 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007831 if (!(p = lock_user_string(arg1)))
7832 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007833 ret = get_errno(setdomainname(p, arg2));
7834 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007835 break;
7836 case TARGET_NR_uname:
7837 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007838 {
7839 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007840
bellard579a97f2007-11-11 14:26:47 +00007841 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7842 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007843 ret = get_errno(sys_uname(buf));
7844 if (!is_error(ret)) {
7845 /* Overrite the native machine name with whatever is being
7846 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007847 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007848 /* Allow the user to override the reported release. */
7849 if (qemu_uname_release && *qemu_uname_release)
7850 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007851 }
pbrook53a59602006-03-25 19:31:22 +00007852 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007853 }
bellard31e31b82003-02-18 22:55:36 +00007854 break;
bellard6dbad632003-03-16 18:05:05 +00007855#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007856 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007857 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007858 break;
j_mayer84409dd2007-04-06 08:56:50 +00007859#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007860 case TARGET_NR_vm86old:
7861 goto unimplemented;
7862 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007863 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007864 break;
7865#endif
j_mayer84409dd2007-04-06 08:56:50 +00007866#endif
bellard31e31b82003-02-18 22:55:36 +00007867 case TARGET_NR_adjtimex:
7868 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007869#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007870 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007871#endif
bellard31e31b82003-02-18 22:55:36 +00007872 case TARGET_NR_init_module:
7873 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007874#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007875 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007876#endif
bellard31e31b82003-02-18 22:55:36 +00007877 goto unimplemented;
7878 case TARGET_NR_quotactl:
7879 goto unimplemented;
7880 case TARGET_NR_getpgid:
7881 ret = get_errno(getpgid(arg1));
7882 break;
7883 case TARGET_NR_fchdir:
7884 ret = get_errno(fchdir(arg1));
7885 break;
j_mayer84409dd2007-04-06 08:56:50 +00007886#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007887 case TARGET_NR_bdflush:
7888 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007889#endif
thse5febef2007-04-01 18:31:35 +00007890#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007891 case TARGET_NR_sysfs:
7892 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007893#endif
bellard31e31b82003-02-18 22:55:36 +00007894 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007895 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007896 break;
thse5febef2007-04-01 18:31:35 +00007897#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007898 case TARGET_NR_afs_syscall:
7899 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007900#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007901#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007902 case TARGET_NR__llseek:
7903 {
7904 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007905#if !defined(__NR_llseek)
7906 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7907 if (res == -1) {
7908 ret = get_errno(res);
7909 } else {
7910 ret = 0;
7911 }
7912#else
bellard31e31b82003-02-18 22:55:36 +00007913 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007914#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007915 if ((ret == 0) && put_user_s64(res, arg4)) {
7916 goto efault;
7917 }
bellard31e31b82003-02-18 22:55:36 +00007918 }
7919 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007920#endif
Chen Gang704eff62015-08-21 05:37:33 +08007921#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00007922 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007923#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007924#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007925 {
pbrook53a59602006-03-25 19:31:22 +00007926 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007927 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007928 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007929
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05307930 dirp = g_try_malloc(count);
7931 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007932 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007933 goto fail;
7934 }
ths3b46e622007-09-17 08:09:54 +00007935
bellard4add45b2003-06-05 01:52:59 +00007936 ret = get_errno(sys_getdents(arg1, dirp, count));
7937 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007938 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007939 struct target_dirent *tde;
7940 int len = ret;
7941 int reclen, treclen;
7942 int count1, tnamelen;
7943
7944 count1 = 0;
7945 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007946 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7947 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007948 tde = target_dirp;
7949 while (len > 0) {
7950 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007951 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7952 assert(tnamelen >= 0);
7953 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7954 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007955 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007956 tde->d_ino = tswapal(de->d_ino);
7957 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007958 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007959 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007960 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007961 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007962 count1 += treclen;
7963 }
7964 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007965 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007966 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05307967 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00007968 }
7969#else
bellard31e31b82003-02-18 22:55:36 +00007970 {
aurel326556a832008-10-13 21:08:17 +00007971 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007972 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007973
bellard579a97f2007-11-11 14:26:47 +00007974 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7975 goto efault;
bellard72f03902003-02-18 23:33:18 +00007976 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007977 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007978 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007979 int len = ret;
7980 int reclen;
7981 de = dirp;
7982 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007983 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007984 if (reclen > len)
7985 break;
bellard8083a3e2003-03-24 23:12:16 +00007986 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007987 tswapls(&de->d_ino);
7988 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007989 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007990 len -= reclen;
7991 }
7992 }
pbrook53a59602006-03-25 19:31:22 +00007993 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007994 }
bellard4add45b2003-06-05 01:52:59 +00007995#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007996#else
7997 /* Implement getdents in terms of getdents64 */
7998 {
7999 struct linux_dirent64 *dirp;
8000 abi_long count = arg3;
8001
8002 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8003 if (!dirp) {
8004 goto efault;
8005 }
8006 ret = get_errno(sys_getdents64(arg1, dirp, count));
8007 if (!is_error(ret)) {
8008 /* Convert the dirent64 structs to target dirent. We do this
8009 * in-place, since we can guarantee that a target_dirent is no
8010 * larger than a dirent64; however this means we have to be
8011 * careful to read everything before writing in the new format.
8012 */
8013 struct linux_dirent64 *de;
8014 struct target_dirent *tde;
8015 int len = ret;
8016 int tlen = 0;
8017
8018 de = dirp;
8019 tde = (struct target_dirent *)dirp;
8020 while (len > 0) {
8021 int namelen, treclen;
8022 int reclen = de->d_reclen;
8023 uint64_t ino = de->d_ino;
8024 int64_t off = de->d_off;
8025 uint8_t type = de->d_type;
8026
8027 namelen = strlen(de->d_name);
8028 treclen = offsetof(struct target_dirent, d_name)
8029 + namelen + 2;
8030 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8031
8032 memmove(tde->d_name, de->d_name, namelen + 1);
8033 tde->d_ino = tswapal(ino);
8034 tde->d_off = tswapal(off);
8035 tde->d_reclen = tswap16(treclen);
8036 /* The target_dirent type is in what was formerly a padding
8037 * byte at the end of the structure:
8038 */
8039 *(((char *)tde) + treclen - 1) = type;
8040
8041 de = (struct linux_dirent64 *)((char *)de + reclen);
8042 tde = (struct target_dirent *)((char *)tde + treclen);
8043 len -= reclen;
8044 tlen += treclen;
8045 }
8046 ret = tlen;
8047 }
8048 unlock_user(dirp, arg2, ret);
8049 }
8050#endif
bellard31e31b82003-02-18 22:55:36 +00008051 break;
Chen Gang704eff62015-08-21 05:37:33 +08008052#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008053#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008054 case TARGET_NR_getdents64:
8055 {
aurel326556a832008-10-13 21:08:17 +00008056 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008057 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008058 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8059 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008060 ret = get_errno(sys_getdents64(arg1, dirp, count));
8061 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008062 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008063 int len = ret;
8064 int reclen;
8065 de = dirp;
8066 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008067 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008068 if (reclen > len)
8069 break;
bellard8083a3e2003-03-24 23:12:16 +00008070 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008071 tswap64s((uint64_t *)&de->d_ino);
8072 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008073 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008074 len -= reclen;
8075 }
8076 }
pbrook53a59602006-03-25 19:31:22 +00008077 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008078 }
8079 break;
bellarda541f292004-04-12 20:39:29 +00008080#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008081#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008082 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008083 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008084 break;
thse5febef2007-04-01 18:31:35 +00008085#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008086#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8087# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008088 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008089# endif
8090# ifdef TARGET_NR_ppoll
8091 case TARGET_NR_ppoll:
8092# endif
bellard9de5e442003-03-23 16:49:39 +00008093 {
pbrook53a59602006-03-25 19:31:22 +00008094 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008095 unsigned int nfds = arg2;
8096 int timeout = arg3;
8097 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008098 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008099
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008100 pfd = NULL;
8101 target_pfd = NULL;
8102 if (nfds) {
8103 target_pfd = lock_user(VERIFY_WRITE, arg1,
8104 sizeof(struct target_pollfd) * nfds, 1);
8105 if (!target_pfd) {
8106 goto efault;
8107 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008108
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008109 pfd = alloca(sizeof(struct pollfd) * nfds);
8110 for (i = 0; i < nfds; i++) {
8111 pfd[i].fd = tswap32(target_pfd[i].fd);
8112 pfd[i].events = tswap16(target_pfd[i].events);
8113 }
bellard9de5e442003-03-23 16:49:39 +00008114 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008115
8116# ifdef TARGET_NR_ppoll
8117 if (num == TARGET_NR_ppoll) {
8118 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8119 target_sigset_t *target_set;
8120 sigset_t _set, *set = &_set;
8121
8122 if (arg3) {
8123 if (target_to_host_timespec(timeout_ts, arg3)) {
8124 unlock_user(target_pfd, arg1, 0);
8125 goto efault;
8126 }
8127 } else {
8128 timeout_ts = NULL;
8129 }
8130
8131 if (arg4) {
8132 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
8133 if (!target_set) {
8134 unlock_user(target_pfd, arg1, 0);
8135 goto efault;
8136 }
8137 target_to_host_sigset(set, target_set);
8138 } else {
8139 set = NULL;
8140 }
8141
8142 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
8143
8144 if (!is_error(ret) && arg3) {
8145 host_to_target_timespec(arg3, timeout_ts);
8146 }
8147 if (arg4) {
8148 unlock_user(target_set, arg4, 0);
8149 }
8150 } else
8151# endif
8152 ret = get_errno(poll(pfd, nfds, timeout));
8153
bellard9de5e442003-03-23 16:49:39 +00008154 if (!is_error(ret)) {
8155 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00008156 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00008157 }
8158 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00008159 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00008160 }
8161 break;
thse5febef2007-04-01 18:31:35 +00008162#endif
bellard31e31b82003-02-18 22:55:36 +00008163 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00008164 /* NOTE: the flock constant seems to be the same for every
8165 Linux platform */
8166 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008167 break;
8168 case TARGET_NR_readv:
8169 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008170 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
8171 if (vec != NULL) {
8172 ret = get_errno(readv(arg1, vec, arg3));
8173 unlock_iovec(vec, arg2, arg3, 1);
8174 } else {
8175 ret = -host_to_target_errno(errno);
8176 }
bellard31e31b82003-02-18 22:55:36 +00008177 }
8178 break;
8179 case TARGET_NR_writev:
8180 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008181 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8182 if (vec != NULL) {
8183 ret = get_errno(writev(arg1, vec, arg3));
8184 unlock_iovec(vec, arg2, arg3, 0);
8185 } else {
8186 ret = -host_to_target_errno(errno);
8187 }
bellard31e31b82003-02-18 22:55:36 +00008188 }
8189 break;
8190 case TARGET_NR_getsid:
8191 ret = get_errno(getsid(arg1));
8192 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008193#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00008194 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00008195 ret = get_errno(fdatasync(arg1));
8196 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008197#endif
Chen Gang704eff62015-08-21 05:37:33 +08008198#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00008199 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00008200 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00008201 return value. */
ths0da46a62007-10-20 20:23:07 +00008202 ret = -TARGET_ENOTDIR;
8203 break;
Chen Gang704eff62015-08-21 05:37:33 +08008204#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05008205 case TARGET_NR_sched_getaffinity:
8206 {
8207 unsigned int mask_size;
8208 unsigned long *mask;
8209
8210 /*
8211 * sched_getaffinity needs multiples of ulong, so need to take
8212 * care of mismatches between target ulong and host ulong sizes.
8213 */
8214 if (arg2 & (sizeof(abi_ulong) - 1)) {
8215 ret = -TARGET_EINVAL;
8216 break;
8217 }
8218 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8219
8220 mask = alloca(mask_size);
8221 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
8222
8223 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01008224 if (ret > arg2) {
8225 /* More data returned than the caller's buffer will fit.
8226 * This only happens if sizeof(abi_long) < sizeof(long)
8227 * and the caller passed us a buffer holding an odd number
8228 * of abi_longs. If the host kernel is actually using the
8229 * extra 4 bytes then fail EINVAL; otherwise we can just
8230 * ignore them and only copy the interesting part.
8231 */
8232 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
8233 if (numcpus > arg2 * 8) {
8234 ret = -TARGET_EINVAL;
8235 break;
8236 }
8237 ret = arg2;
8238 }
8239
Mike McCormackcd18f052011-04-18 14:43:36 +09008240 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05008241 goto efault;
8242 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05008243 }
8244 }
8245 break;
8246 case TARGET_NR_sched_setaffinity:
8247 {
8248 unsigned int mask_size;
8249 unsigned long *mask;
8250
8251 /*
8252 * sched_setaffinity needs multiples of ulong, so need to take
8253 * care of mismatches between target ulong and host ulong sizes.
8254 */
8255 if (arg2 & (sizeof(abi_ulong) - 1)) {
8256 ret = -TARGET_EINVAL;
8257 break;
8258 }
8259 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
8260
8261 mask = alloca(mask_size);
8262 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
8263 goto efault;
8264 }
8265 memcpy(mask, p, arg2);
8266 unlock_user_struct(p, arg2, 0);
8267
8268 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
8269 }
8270 break;
bellard31e31b82003-02-18 22:55:36 +00008271 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00008272 {
pbrook53a59602006-03-25 19:31:22 +00008273 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008274 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00008275
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008276 if (arg2 == 0) {
8277 return -TARGET_EINVAL;
8278 }
bellard579a97f2007-11-11 14:26:47 +00008279 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
8280 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008281 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008282 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00008283 ret = get_errno(sched_setparam(arg1, &schp));
8284 }
8285 break;
bellard31e31b82003-02-18 22:55:36 +00008286 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00008287 {
pbrook53a59602006-03-25 19:31:22 +00008288 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008289 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008290
8291 if (arg2 == 0) {
8292 return -TARGET_EINVAL;
8293 }
bellard5cd43932003-03-29 16:54:36 +00008294 ret = get_errno(sched_getparam(arg1, &schp));
8295 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008296 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
8297 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008298 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008299 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00008300 }
8301 }
8302 break;
bellard31e31b82003-02-18 22:55:36 +00008303 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00008304 {
pbrook53a59602006-03-25 19:31:22 +00008305 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00008306 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05008307 if (arg3 == 0) {
8308 return -TARGET_EINVAL;
8309 }
bellard579a97f2007-11-11 14:26:47 +00008310 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
8311 goto efault;
bellard5cd43932003-03-29 16:54:36 +00008312 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00008313 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00008314 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
8315 }
8316 break;
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00008318 ret = get_errno(sched_getscheduler(arg1));
8319 break;
bellard31e31b82003-02-18 22:55:36 +00008320 case TARGET_NR_sched_yield:
8321 ret = get_errno(sched_yield());
8322 break;
8323 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00008324 ret = get_errno(sched_get_priority_max(arg1));
8325 break;
bellard31e31b82003-02-18 22:55:36 +00008326 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00008327 ret = get_errno(sched_get_priority_min(arg1));
8328 break;
bellard31e31b82003-02-18 22:55:36 +00008329 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00008330 {
bellard5cd43932003-03-29 16:54:36 +00008331 struct timespec ts;
8332 ret = get_errno(sched_rr_get_interval(arg1, &ts));
8333 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05008334 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00008335 }
8336 }
8337 break;
bellard31e31b82003-02-18 22:55:36 +00008338 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00008339 {
bellard1b6b0292003-03-22 17:31:38 +00008340 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00008341 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00008342 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00008343 if (is_error(ret) && arg2) {
8344 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00008345 }
8346 }
8347 break;
thse5febef2007-04-01 18:31:35 +00008348#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00008349 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00008350 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008351#endif
8352#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00008353 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00008354 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008355#endif
bellard31e31b82003-02-18 22:55:36 +00008356 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00008357 switch (arg1) {
8358 case PR_GET_PDEATHSIG:
8359 {
8360 int deathsig;
8361 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
8362 if (!is_error(ret) && arg2
8363 && put_user_ual(deathsig, arg2)) {
8364 goto efault;
thse5574482007-02-11 20:03:13 +00008365 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00008366 break;
8367 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00008368#ifdef PR_GET_NAME
8369 case PR_GET_NAME:
8370 {
8371 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
8372 if (!name) {
8373 goto efault;
8374 }
8375 ret = get_errno(prctl(arg1, (unsigned long)name,
8376 arg3, arg4, arg5));
8377 unlock_user(name, arg2, 16);
8378 break;
8379 }
8380 case PR_SET_NAME:
8381 {
8382 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
8383 if (!name) {
8384 goto efault;
8385 }
8386 ret = get_errno(prctl(arg1, (unsigned long)name,
8387 arg3, arg4, arg5));
8388 unlock_user(name, arg2, 0);
8389 break;
8390 }
8391#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00008392 default:
8393 /* Most prctl options have no pointer arguments */
8394 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
8395 break;
8396 }
ths39b9aae2007-02-11 18:36:44 +00008397 break;
bellardd2fd1af2007-11-14 18:08:56 +00008398#ifdef TARGET_NR_arch_prctl
8399 case TARGET_NR_arch_prctl:
8400#if defined(TARGET_I386) && !defined(TARGET_ABI32)
8401 ret = do_arch_prctl(cpu_env, arg1, arg2);
8402 break;
8403#else
8404 goto unimplemented;
8405#endif
8406#endif
aurel32f2c7ba12008-03-28 22:32:06 +00008407#ifdef TARGET_NR_pread64
8408 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00008409 if (regpairs_aligned(cpu_env)) {
8410 arg4 = arg5;
8411 arg5 = arg6;
8412 }
aurel32f2c7ba12008-03-28 22:32:06 +00008413 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
8414 goto efault;
8415 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
8416 unlock_user(p, arg2, ret);
8417 break;
8418 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00008419 if (regpairs_aligned(cpu_env)) {
8420 arg4 = arg5;
8421 arg5 = arg6;
8422 }
aurel32f2c7ba12008-03-28 22:32:06 +00008423 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8424 goto efault;
8425 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
8426 unlock_user(p, arg2, 0);
8427 break;
8428#endif
bellard31e31b82003-02-18 22:55:36 +00008429 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00008430 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
8431 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008432 ret = get_errno(sys_getcwd1(p, arg2));
8433 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00008434 break;
8435 case TARGET_NR_capget:
8436 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00008437 {
8438 struct target_user_cap_header *target_header;
8439 struct target_user_cap_data *target_data = NULL;
8440 struct __user_cap_header_struct header;
8441 struct __user_cap_data_struct data[2];
8442 struct __user_cap_data_struct *dataptr = NULL;
8443 int i, target_datalen;
8444 int data_items = 1;
8445
8446 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
8447 goto efault;
8448 }
8449 header.version = tswap32(target_header->version);
8450 header.pid = tswap32(target_header->pid);
8451
Peter Maydellec864872014-03-19 16:07:30 +00008452 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008453 /* Version 2 and up takes pointer to two user_data structs */
8454 data_items = 2;
8455 }
8456
8457 target_datalen = sizeof(*target_data) * data_items;
8458
8459 if (arg2) {
8460 if (num == TARGET_NR_capget) {
8461 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8462 } else {
8463 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8464 }
8465 if (!target_data) {
8466 unlock_user_struct(target_header, arg1, 0);
8467 goto efault;
8468 }
8469
8470 if (num == TARGET_NR_capset) {
8471 for (i = 0; i < data_items; i++) {
8472 data[i].effective = tswap32(target_data[i].effective);
8473 data[i].permitted = tswap32(target_data[i].permitted);
8474 data[i].inheritable = tswap32(target_data[i].inheritable);
8475 }
8476 }
8477
8478 dataptr = data;
8479 }
8480
8481 if (num == TARGET_NR_capget) {
8482 ret = get_errno(capget(&header, dataptr));
8483 } else {
8484 ret = get_errno(capset(&header, dataptr));
8485 }
8486
8487 /* The kernel always updates version for both capget and capset */
8488 target_header->version = tswap32(header.version);
8489 unlock_user_struct(target_header, arg1, 1);
8490
8491 if (arg2) {
8492 if (num == TARGET_NR_capget) {
8493 for (i = 0; i < data_items; i++) {
8494 target_data[i].effective = tswap32(data[i].effective);
8495 target_data[i].permitted = tswap32(data[i].permitted);
8496 target_data[i].inheritable = tswap32(data[i].inheritable);
8497 }
8498 unlock_user(target_data, arg2, target_datalen);
8499 } else {
8500 unlock_user(target_data, arg2, 0);
8501 }
8502 }
8503 break;
8504 }
bellard31e31b82003-02-18 22:55:36 +00008505 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00008506#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02008507 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08008508 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01008509 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008510 break;
8511#else
bellard5cd43932003-03-29 16:54:36 +00008512 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00008513#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008514
8515#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008516 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008517 {
8518 off_t *offp = NULL;
8519 off_t off;
8520 if (arg3) {
8521 ret = get_user_sal(off, arg3);
8522 if (is_error(ret)) {
8523 break;
8524 }
8525 offp = &off;
8526 }
8527 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8528 if (!is_error(ret) && arg3) {
8529 abi_long ret2 = put_user_sal(off, arg3);
8530 if (is_error(ret2)) {
8531 ret = ret2;
8532 }
8533 }
8534 break;
8535 }
8536#ifdef TARGET_NR_sendfile64
8537 case TARGET_NR_sendfile64:
8538 {
8539 off_t *offp = NULL;
8540 off_t off;
8541 if (arg3) {
8542 ret = get_user_s64(off, arg3);
8543 if (is_error(ret)) {
8544 break;
8545 }
8546 offp = &off;
8547 }
8548 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8549 if (!is_error(ret) && arg3) {
8550 abi_long ret2 = put_user_s64(off, arg3);
8551 if (is_error(ret2)) {
8552 ret = ret2;
8553 }
8554 }
8555 break;
8556 }
8557#endif
8558#else
8559 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008560#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008561 case TARGET_NR_sendfile64:
8562#endif
bellard5cd43932003-03-29 16:54:36 +00008563 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008564#endif
8565
bellardebc05482003-09-30 21:08:41 +00008566#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008567 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008568 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008569#endif
8570#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008571 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008572 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008573#endif
bellard048f6b42005-11-26 18:47:20 +00008574#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008575 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008576 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8577 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008578 break;
bellard048f6b42005-11-26 18:47:20 +00008579#endif
bellardebc05482003-09-30 21:08:41 +00008580#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008581 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008582 {
8583 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008584 int resource = target_to_host_resource(arg1);
8585 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008586 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008587 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008588 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8589 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008590 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8591 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008592 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008593 }
8594 break;
8595 }
bellardebc05482003-09-30 21:08:41 +00008596#endif
bellarda315a142005-01-30 22:59:18 +00008597#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008598 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008599 if (!(p = lock_user_string(arg1)))
8600 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008601 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8602 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008603 break;
bellarda315a142005-01-30 22:59:18 +00008604#endif
8605#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008606 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008607 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008608 break;
bellarda315a142005-01-30 22:59:18 +00008609#endif
8610#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008611 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008612 if (!(p = lock_user_string(arg1)))
8613 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008614 ret = get_errno(stat(path(p), &st));
8615 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008616 if (!is_error(ret))
8617 ret = host_to_target_stat64(cpu_env, arg2, &st);
8618 break;
bellarda315a142005-01-30 22:59:18 +00008619#endif
8620#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008621 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008622 if (!(p = lock_user_string(arg1)))
8623 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008624 ret = get_errno(lstat(path(p), &st));
8625 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008626 if (!is_error(ret))
8627 ret = host_to_target_stat64(cpu_env, arg2, &st);
8628 break;
bellarda315a142005-01-30 22:59:18 +00008629#endif
8630#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008631 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008632 ret = get_errno(fstat(arg1, &st));
8633 if (!is_error(ret))
8634 ret = host_to_target_stat64(cpu_env, arg2, &st);
8635 break;
bellardec86b0f2003-04-11 00:15:04 +00008636#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008637#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008638#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008639 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008640#endif
8641#ifdef TARGET_NR_newfstatat
8642 case TARGET_NR_newfstatat:
8643#endif
balrog6a24a772008-09-20 02:23:36 +00008644 if (!(p = lock_user_string(arg2)))
8645 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008646 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008647 if (!is_error(ret))
8648 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008649 break;
bellarda315a142005-01-30 22:59:18 +00008650#endif
Chen Gang704eff62015-08-21 05:37:33 +08008651#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00008652 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008653 if (!(p = lock_user_string(arg1)))
8654 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008655 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8656 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008657 break;
Chen Gang704eff62015-08-21 05:37:33 +08008658#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03008659#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008660 case TARGET_NR_getuid:
8661 ret = get_errno(high2lowuid(getuid()));
8662 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008663#endif
8664#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008665 case TARGET_NR_getgid:
8666 ret = get_errno(high2lowgid(getgid()));
8667 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008668#endif
8669#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008670 case TARGET_NR_geteuid:
8671 ret = get_errno(high2lowuid(geteuid()));
8672 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008673#endif
8674#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008675 case TARGET_NR_getegid:
8676 ret = get_errno(high2lowgid(getegid()));
8677 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008678#endif
bellard67867302003-11-23 17:05:30 +00008679 case TARGET_NR_setreuid:
8680 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8681 break;
8682 case TARGET_NR_setregid:
8683 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8684 break;
8685 case TARGET_NR_getgroups:
8686 {
8687 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008688 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008689 gid_t *grouplist;
8690 int i;
8691
8692 grouplist = alloca(gidsetsize * sizeof(gid_t));
8693 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008694 if (gidsetsize == 0)
8695 break;
bellard67867302003-11-23 17:05:30 +00008696 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008697 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008698 if (!target_grouplist)
8699 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008700 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008701 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008702 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008703 }
8704 }
8705 break;
8706 case TARGET_NR_setgroups:
8707 {
8708 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008709 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008710 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008711 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008712 if (gidsetsize) {
8713 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008714 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008715 if (!target_grouplist) {
8716 ret = -TARGET_EFAULT;
8717 goto fail;
8718 }
8719 for (i = 0; i < gidsetsize; i++) {
8720 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8721 }
8722 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008723 }
bellard67867302003-11-23 17:05:30 +00008724 ret = get_errno(setgroups(gidsetsize, grouplist));
8725 }
8726 break;
8727 case TARGET_NR_fchown:
8728 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8729 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008730#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008731 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008732 if (!(p = lock_user_string(arg2)))
8733 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008734 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8735 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008736 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008737 break;
8738#endif
bellard67867302003-11-23 17:05:30 +00008739#ifdef TARGET_NR_setresuid
8740 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008741 ret = get_errno(setresuid(low2highuid(arg1),
8742 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008743 low2highuid(arg3)));
8744 break;
8745#endif
8746#ifdef TARGET_NR_getresuid
8747 case TARGET_NR_getresuid:
8748 {
pbrook53a59602006-03-25 19:31:22 +00008749 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008750 ret = get_errno(getresuid(&ruid, &euid, &suid));
8751 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008752 if (put_user_id(high2lowuid(ruid), arg1)
8753 || put_user_id(high2lowuid(euid), arg2)
8754 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008755 goto efault;
bellard67867302003-11-23 17:05:30 +00008756 }
8757 }
8758 break;
8759#endif
8760#ifdef TARGET_NR_getresgid
8761 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008762 ret = get_errno(setresgid(low2highgid(arg1),
8763 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008764 low2highgid(arg3)));
8765 break;
8766#endif
8767#ifdef TARGET_NR_getresgid
8768 case TARGET_NR_getresgid:
8769 {
pbrook53a59602006-03-25 19:31:22 +00008770 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008771 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8772 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008773 if (put_user_id(high2lowgid(rgid), arg1)
8774 || put_user_id(high2lowgid(egid), arg2)
8775 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008776 goto efault;
bellard67867302003-11-23 17:05:30 +00008777 }
8778 }
8779 break;
8780#endif
Chen Gang704eff62015-08-21 05:37:33 +08008781#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00008782 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008783 if (!(p = lock_user_string(arg1)))
8784 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008785 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8786 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008787 break;
Chen Gang704eff62015-08-21 05:37:33 +08008788#endif
bellard67867302003-11-23 17:05:30 +00008789 case TARGET_NR_setuid:
8790 ret = get_errno(setuid(low2highuid(arg1)));
8791 break;
8792 case TARGET_NR_setgid:
8793 ret = get_errno(setgid(low2highgid(arg1)));
8794 break;
8795 case TARGET_NR_setfsuid:
8796 ret = get_errno(setfsuid(arg1));
8797 break;
8798 case TARGET_NR_setfsgid:
8799 ret = get_errno(setfsgid(arg1));
8800 break;
bellard67867302003-11-23 17:05:30 +00008801
bellarda315a142005-01-30 22:59:18 +00008802#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008803 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008804 if (!(p = lock_user_string(arg1)))
8805 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008806 ret = get_errno(lchown(p, arg2, arg3));
8807 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008808 break;
bellarda315a142005-01-30 22:59:18 +00008809#endif
8810#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008811 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008812 ret = get_errno(getuid());
8813 break;
bellarda315a142005-01-30 22:59:18 +00008814#endif
aurel3264b4d282008-11-14 17:20:15 +00008815
8816#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8817 /* Alpha specific */
8818 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008819 {
8820 uid_t euid;
8821 euid=geteuid();
8822 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8823 }
aurel3264b4d282008-11-14 17:20:15 +00008824 ret = get_errno(getuid());
8825 break;
8826#endif
8827#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8828 /* Alpha specific */
8829 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008830 {
8831 uid_t egid;
8832 egid=getegid();
8833 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8834 }
aurel3264b4d282008-11-14 17:20:15 +00008835 ret = get_errno(getgid());
8836 break;
8837#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008838#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8839 /* Alpha specific */
8840 case TARGET_NR_osf_getsysinfo:
8841 ret = -TARGET_EOPNOTSUPP;
8842 switch (arg1) {
8843 case TARGET_GSI_IEEE_FP_CONTROL:
8844 {
8845 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8846
8847 /* Copied from linux ieee_fpcr_to_swcr. */
8848 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8849 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8850 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8851 | SWCR_TRAP_ENABLE_DZE
8852 | SWCR_TRAP_ENABLE_OVF);
8853 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8854 | SWCR_TRAP_ENABLE_INE);
8855 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8856 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8857
8858 if (put_user_u64 (swcr, arg2))
8859 goto efault;
8860 ret = 0;
8861 }
8862 break;
8863
8864 /* case GSI_IEEE_STATE_AT_SIGNAL:
8865 -- Not implemented in linux kernel.
8866 case GSI_UACPROC:
8867 -- Retrieves current unaligned access state; not much used.
8868 case GSI_PROC_TYPE:
8869 -- Retrieves implver information; surely not used.
8870 case GSI_GET_HWRPB:
8871 -- Grabs a copy of the HWRPB; surely not used.
8872 */
8873 }
8874 break;
8875#endif
8876#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8877 /* Alpha specific */
8878 case TARGET_NR_osf_setsysinfo:
8879 ret = -TARGET_EOPNOTSUPP;
8880 switch (arg1) {
8881 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008882 {
8883 uint64_t swcr, fpcr, orig_fpcr;
8884
Richard Henderson6e06d512012-06-01 09:08:21 -07008885 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008886 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008887 }
8888 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008889 fpcr = orig_fpcr & FPCR_DYN_MASK;
8890
8891 /* Copied from linux ieee_swcr_to_fpcr. */
8892 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8893 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8894 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8895 | SWCR_TRAP_ENABLE_DZE
8896 | SWCR_TRAP_ENABLE_OVF)) << 48;
8897 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8898 | SWCR_TRAP_ENABLE_INE)) << 57;
8899 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8900 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8901
Richard Henderson6e06d512012-06-01 09:08:21 -07008902 cpu_alpha_store_fpcr(cpu_env, fpcr);
8903 ret = 0;
8904 }
8905 break;
8906
8907 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8908 {
8909 uint64_t exc, fpcr, orig_fpcr;
8910 int si_code;
8911
8912 if (get_user_u64(exc, arg2)) {
8913 goto efault;
8914 }
8915
8916 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8917
8918 /* We only add to the exception status here. */
8919 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8920
8921 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008922 ret = 0;
8923
Richard Henderson6e06d512012-06-01 09:08:21 -07008924 /* Old exceptions are not signaled. */
8925 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008926
Richard Henderson6e06d512012-06-01 09:08:21 -07008927 /* If any exceptions set by this call,
8928 and are unmasked, send a signal. */
8929 si_code = 0;
8930 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8931 si_code = TARGET_FPE_FLTRES;
8932 }
8933 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8934 si_code = TARGET_FPE_FLTUND;
8935 }
8936 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8937 si_code = TARGET_FPE_FLTOVF;
8938 }
8939 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8940 si_code = TARGET_FPE_FLTDIV;
8941 }
8942 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8943 si_code = TARGET_FPE_FLTINV;
8944 }
8945 if (si_code != 0) {
8946 target_siginfo_t info;
8947 info.si_signo = SIGFPE;
8948 info.si_errno = 0;
8949 info.si_code = si_code;
8950 info._sifields._sigfault._addr
8951 = ((CPUArchState *)cpu_env)->pc;
8952 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008953 }
8954 }
8955 break;
8956
8957 /* case SSI_NVPAIRS:
8958 -- Used with SSIN_UACPROC to enable unaligned accesses.
8959 case SSI_IEEE_STATE_AT_SIGNAL:
8960 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8961 -- Not implemented in linux kernel
8962 */
8963 }
8964 break;
8965#endif
8966#ifdef TARGET_NR_osf_sigprocmask
8967 /* Alpha specific. */
8968 case TARGET_NR_osf_sigprocmask:
8969 {
8970 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008971 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008972 sigset_t set, oldset;
8973
8974 switch(arg1) {
8975 case TARGET_SIG_BLOCK:
8976 how = SIG_BLOCK;
8977 break;
8978 case TARGET_SIG_UNBLOCK:
8979 how = SIG_UNBLOCK;
8980 break;
8981 case TARGET_SIG_SETMASK:
8982 how = SIG_SETMASK;
8983 break;
8984 default:
8985 ret = -TARGET_EINVAL;
8986 goto fail;
8987 }
8988 mask = arg2;
8989 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008990 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008991 host_to_target_old_sigset(&mask, &oldset);
8992 ret = mask;
8993 }
8994 break;
8995#endif
aurel3264b4d282008-11-14 17:20:15 +00008996
bellarda315a142005-01-30 22:59:18 +00008997#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008998 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008999 ret = get_errno(getgid());
9000 break;
bellarda315a142005-01-30 22:59:18 +00009001#endif
9002#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009003 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009004 ret = get_errno(geteuid());
9005 break;
bellarda315a142005-01-30 22:59:18 +00009006#endif
9007#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009008 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009009 ret = get_errno(getegid());
9010 break;
bellarda315a142005-01-30 22:59:18 +00009011#endif
9012#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009013 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009014 ret = get_errno(setreuid(arg1, arg2));
9015 break;
bellarda315a142005-01-30 22:59:18 +00009016#endif
9017#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009018 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009019 ret = get_errno(setregid(arg1, arg2));
9020 break;
bellarda315a142005-01-30 22:59:18 +00009021#endif
9022#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009023 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009024 {
9025 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009026 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009027 gid_t *grouplist;
9028 int i;
9029
9030 grouplist = alloca(gidsetsize * sizeof(gid_t));
9031 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009032 if (gidsetsize == 0)
9033 break;
bellard99c475a2005-01-31 20:45:13 +00009034 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009035 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9036 if (!target_grouplist) {
9037 ret = -TARGET_EFAULT;
9038 goto fail;
9039 }
balroga2155fc2008-09-20 02:12:08 +00009040 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009041 target_grouplist[i] = tswap32(grouplist[i]);
9042 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009043 }
9044 }
9045 break;
bellarda315a142005-01-30 22:59:18 +00009046#endif
9047#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009048 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009049 {
9050 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009051 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009052 gid_t *grouplist;
9053 int i;
ths3b46e622007-09-17 08:09:54 +00009054
bellard99c475a2005-01-31 20:45:13 +00009055 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009056 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9057 if (!target_grouplist) {
9058 ret = -TARGET_EFAULT;
9059 goto fail;
9060 }
bellard99c475a2005-01-31 20:45:13 +00009061 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009062 grouplist[i] = tswap32(target_grouplist[i]);
9063 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009064 ret = get_errno(setgroups(gidsetsize, grouplist));
9065 }
9066 break;
bellarda315a142005-01-30 22:59:18 +00009067#endif
9068#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009069 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009070 ret = get_errno(fchown(arg1, arg2, arg3));
9071 break;
bellarda315a142005-01-30 22:59:18 +00009072#endif
9073#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009074 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009075 ret = get_errno(setresuid(arg1, arg2, arg3));
9076 break;
bellarda315a142005-01-30 22:59:18 +00009077#endif
9078#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009079 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009080 {
pbrook53a59602006-03-25 19:31:22 +00009081 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009082 ret = get_errno(getresuid(&ruid, &euid, &suid));
9083 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009084 if (put_user_u32(ruid, arg1)
9085 || put_user_u32(euid, arg2)
9086 || put_user_u32(suid, arg3))
9087 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009088 }
9089 }
9090 break;
bellarda315a142005-01-30 22:59:18 +00009091#endif
9092#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009093 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009094 ret = get_errno(setresgid(arg1, arg2, arg3));
9095 break;
bellarda315a142005-01-30 22:59:18 +00009096#endif
9097#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009098 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009099 {
pbrook53a59602006-03-25 19:31:22 +00009100 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009101 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9102 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009103 if (put_user_u32(rgid, arg1)
9104 || put_user_u32(egid, arg2)
9105 || put_user_u32(sgid, arg3))
9106 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009107 }
9108 }
9109 break;
bellarda315a142005-01-30 22:59:18 +00009110#endif
9111#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009112 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009113 if (!(p = lock_user_string(arg1)))
9114 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009115 ret = get_errno(chown(p, arg2, arg3));
9116 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009117 break;
bellarda315a142005-01-30 22:59:18 +00009118#endif
9119#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009120 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00009121 ret = get_errno(setuid(arg1));
9122 break;
bellarda315a142005-01-30 22:59:18 +00009123#endif
9124#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009125 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00009126 ret = get_errno(setgid(arg1));
9127 break;
bellarda315a142005-01-30 22:59:18 +00009128#endif
9129#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009130 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009131 ret = get_errno(setfsuid(arg1));
9132 break;
bellarda315a142005-01-30 22:59:18 +00009133#endif
9134#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00009135 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00009136 ret = get_errno(setfsgid(arg1));
9137 break;
bellarda315a142005-01-30 22:59:18 +00009138#endif
bellard67867302003-11-23 17:05:30 +00009139
bellard31e31b82003-02-18 22:55:36 +00009140 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00009141 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00009142#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00009143 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00009144 {
9145 void *a;
9146 ret = -TARGET_EFAULT;
9147 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
9148 goto efault;
9149 if (!(p = lock_user_string(arg3)))
9150 goto mincore_fail;
9151 ret = get_errno(mincore(a, arg2, p));
9152 unlock_user(p, arg3, ret);
9153 mincore_fail:
9154 unlock_user(a, arg1, 0);
9155 }
9156 break;
bellardffa65c32004-01-04 23:57:22 +00009157#endif
aurel32408321b2008-10-01 21:46:32 +00009158#ifdef TARGET_NR_arm_fadvise64_64
9159 case TARGET_NR_arm_fadvise64_64:
9160 {
9161 /*
9162 * arm_fadvise64_64 looks like fadvise64_64 but
9163 * with different argument order
9164 */
9165 abi_long temp;
9166 temp = arg3;
9167 arg3 = arg4;
9168 arg4 = temp;
9169 }
9170#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009171#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00009172#ifdef TARGET_NR_fadvise64_64
9173 case TARGET_NR_fadvise64_64:
9174#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02009175#ifdef TARGET_NR_fadvise64
9176 case TARGET_NR_fadvise64:
9177#endif
9178#ifdef TARGET_S390X
9179 switch (arg4) {
9180 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
9181 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
9182 case 6: arg4 = POSIX_FADV_DONTNEED; break;
9183 case 7: arg4 = POSIX_FADV_NOREUSE; break;
9184 default: break;
9185 }
9186#endif
9187 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00009188 break;
9189#endif
bellardffa65c32004-01-04 23:57:22 +00009190#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00009191 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00009192 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08009193 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00009194 This will break MADV_DONTNEED.
9195 This is a hint, so ignoring and returning success is ok. */
9196 ret = get_errno(0);
9197 break;
bellardffa65c32004-01-04 23:57:22 +00009198#endif
blueswir1992f48a2007-10-14 16:27:31 +00009199#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00009200 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00009201 {
thsb1e341e2007-03-20 21:50:52 +00009202 int cmd;
bellard77e46722003-04-29 20:39:06 +00009203 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00009204 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00009205#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00009206 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00009207#endif
bellard77e46722003-04-29 20:39:06 +00009208
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009209 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00009210 if (cmd == -TARGET_EINVAL) {
9211 ret = cmd;
9212 break;
9213 }
thsb1e341e2007-03-20 21:50:52 +00009214
bellard60cd49d2003-03-16 22:53:56 +00009215 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00009216 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00009217#ifdef TARGET_ARM
9218 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009219 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9220 goto efault;
ths58134272007-03-31 18:59:32 +00009221 fl.l_type = tswap16(target_efl->l_type);
9222 fl.l_whence = tswap16(target_efl->l_whence);
9223 fl.l_start = tswap64(target_efl->l_start);
9224 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009225 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00009226 unlock_user_struct(target_efl, arg3, 0);
9227 } else
9228#endif
9229 {
bellard9ee1fa22007-11-11 15:11:19 +00009230 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9231 goto efault;
ths58134272007-03-31 18:59:32 +00009232 fl.l_type = tswap16(target_fl->l_type);
9233 fl.l_whence = tswap16(target_fl->l_whence);
9234 fl.l_start = tswap64(target_fl->l_start);
9235 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009236 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00009237 unlock_user_struct(target_fl, arg3, 0);
9238 }
thsb1e341e2007-03-20 21:50:52 +00009239 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009240 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00009241#ifdef TARGET_ARM
9242 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009243 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
9244 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009245 target_efl->l_type = tswap16(fl.l_type);
9246 target_efl->l_whence = tswap16(fl.l_whence);
9247 target_efl->l_start = tswap64(fl.l_start);
9248 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009249 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009250 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009251 } else
9252#endif
9253 {
bellard9ee1fa22007-11-11 15:11:19 +00009254 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
9255 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009256 target_fl->l_type = tswap16(fl.l_type);
9257 target_fl->l_whence = tswap16(fl.l_whence);
9258 target_fl->l_start = tswap64(fl.l_start);
9259 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009260 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00009261 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00009262 }
bellard77e46722003-04-29 20:39:06 +00009263 }
9264 break;
9265
thsb1e341e2007-03-20 21:50:52 +00009266 case TARGET_F_SETLK64:
9267 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00009268#ifdef TARGET_ARM
9269 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00009270 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
9271 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009272 fl.l_type = tswap16(target_efl->l_type);
9273 fl.l_whence = tswap16(target_efl->l_whence);
9274 fl.l_start = tswap64(target_efl->l_start);
9275 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009276 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009277 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009278 } else
9279#endif
9280 {
bellard9ee1fa22007-11-11 15:11:19 +00009281 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
9282 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00009283 fl.l_type = tswap16(target_fl->l_type);
9284 fl.l_whence = tswap16(target_fl->l_whence);
9285 fl.l_start = tswap64(target_fl->l_start);
9286 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02009287 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00009288 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00009289 }
thsb1e341e2007-03-20 21:50:52 +00009290 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00009291 break;
bellard60cd49d2003-03-16 22:53:56 +00009292 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02009293 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00009294 break;
9295 }
bellard77e46722003-04-29 20:39:06 +00009296 break;
9297 }
bellard60cd49d2003-03-16 22:53:56 +00009298#endif
ths7d600c82006-12-08 01:32:58 +00009299#ifdef TARGET_NR_cacheflush
9300 case TARGET_NR_cacheflush:
9301 /* self-modifying code is handled automatically, so nothing needed */
9302 ret = 0;
9303 break;
9304#endif
bellardebc05482003-09-30 21:08:41 +00009305#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00009306 case TARGET_NR_security:
9307 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009308#endif
bellardc573ff62004-01-04 15:51:36 +00009309#ifdef TARGET_NR_getpagesize
9310 case TARGET_NR_getpagesize:
9311 ret = TARGET_PAGE_SIZE;
9312 break;
9313#endif
bellard31e31b82003-02-18 22:55:36 +00009314 case TARGET_NR_gettid:
9315 ret = get_errno(gettid());
9316 break;
thse5febef2007-04-01 18:31:35 +00009317#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00009318 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00009319#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03009320 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00009321 arg2 = arg3;
9322 arg3 = arg4;
9323 arg4 = arg5;
9324 }
aurel322054ac92008-10-13 21:08:07 +00009325 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
9326#else
9327 ret = get_errno(readahead(arg1, arg2, arg3));
9328#endif
9329 break;
thse5febef2007-04-01 18:31:35 +00009330#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009331#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00009332#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00009333 case TARGET_NR_listxattr:
9334 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00009335 {
9336 void *p, *b = 0;
9337 if (arg2) {
9338 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9339 if (!b) {
9340 ret = -TARGET_EFAULT;
9341 break;
9342 }
9343 }
9344 p = lock_user_string(arg1);
9345 if (p) {
9346 if (num == TARGET_NR_listxattr) {
9347 ret = get_errno(listxattr(p, b, arg3));
9348 } else {
9349 ret = get_errno(llistxattr(p, b, arg3));
9350 }
9351 } else {
9352 ret = -TARGET_EFAULT;
9353 }
9354 unlock_user(p, arg1, 0);
9355 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03009356 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00009357 }
9358 case TARGET_NR_flistxattr:
9359 {
9360 void *b = 0;
9361 if (arg2) {
9362 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
9363 if (!b) {
9364 ret = -TARGET_EFAULT;
9365 break;
9366 }
9367 }
9368 ret = get_errno(flistxattr(arg1, b, arg3));
9369 unlock_user(b, arg2, arg3);
9370 break;
9371 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009372 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009373 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009374 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009375 void *p, *n, *v = 0;
9376 if (arg3) {
9377 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9378 if (!v) {
9379 ret = -TARGET_EFAULT;
9380 break;
9381 }
9382 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009383 p = lock_user_string(arg1);
9384 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009385 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009386 if (num == TARGET_NR_setxattr) {
9387 ret = get_errno(setxattr(p, n, v, arg4, arg5));
9388 } else {
9389 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
9390 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009391 } else {
9392 ret = -TARGET_EFAULT;
9393 }
9394 unlock_user(p, arg1, 0);
9395 unlock_user(n, arg2, 0);
9396 unlock_user(v, arg3, 0);
9397 }
9398 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009399 case TARGET_NR_fsetxattr:
9400 {
9401 void *n, *v = 0;
9402 if (arg3) {
9403 v = lock_user(VERIFY_READ, arg3, arg4, 1);
9404 if (!v) {
9405 ret = -TARGET_EFAULT;
9406 break;
9407 }
9408 }
9409 n = lock_user_string(arg2);
9410 if (n) {
9411 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
9412 } else {
9413 ret = -TARGET_EFAULT;
9414 }
9415 unlock_user(n, arg2, 0);
9416 unlock_user(v, arg3, 0);
9417 }
9418 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009419 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009420 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009421 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009422 void *p, *n, *v = 0;
9423 if (arg3) {
9424 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9425 if (!v) {
9426 ret = -TARGET_EFAULT;
9427 break;
9428 }
9429 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009430 p = lock_user_string(arg1);
9431 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009432 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009433 if (num == TARGET_NR_getxattr) {
9434 ret = get_errno(getxattr(p, n, v, arg4));
9435 } else {
9436 ret = get_errno(lgetxattr(p, n, v, arg4));
9437 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009438 } else {
9439 ret = -TARGET_EFAULT;
9440 }
9441 unlock_user(p, arg1, 0);
9442 unlock_user(n, arg2, 0);
9443 unlock_user(v, arg3, arg4);
9444 }
9445 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009446 case TARGET_NR_fgetxattr:
9447 {
9448 void *n, *v = 0;
9449 if (arg3) {
9450 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9451 if (!v) {
9452 ret = -TARGET_EFAULT;
9453 break;
9454 }
9455 }
9456 n = lock_user_string(arg2);
9457 if (n) {
9458 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9459 } else {
9460 ret = -TARGET_EFAULT;
9461 }
9462 unlock_user(n, arg2, 0);
9463 unlock_user(v, arg3, arg4);
9464 }
9465 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009466 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009467 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009468 {
9469 void *p, *n;
9470 p = lock_user_string(arg1);
9471 n = lock_user_string(arg2);
9472 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009473 if (num == TARGET_NR_removexattr) {
9474 ret = get_errno(removexattr(p, n));
9475 } else {
9476 ret = get_errno(lremovexattr(p, n));
9477 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009478 } else {
9479 ret = -TARGET_EFAULT;
9480 }
9481 unlock_user(p, arg1, 0);
9482 unlock_user(n, arg2, 0);
9483 }
9484 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009485 case TARGET_NR_fremovexattr:
9486 {
9487 void *n;
9488 n = lock_user_string(arg2);
9489 if (n) {
9490 ret = get_errno(fremovexattr(arg1, n));
9491 } else {
9492 ret = -TARGET_EFAULT;
9493 }
9494 unlock_user(n, arg2, 0);
9495 }
9496 break;
bellardebc05482003-09-30 21:08:41 +00009497#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009498#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009499#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009500 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009501#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009502 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009503 ret = 0;
9504 break;
edgar_iglef967792009-01-07 14:19:38 +00009505#elif defined(TARGET_CRIS)
9506 if (arg1 & 0xff)
9507 ret = -TARGET_EINVAL;
9508 else {
9509 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9510 ret = 0;
9511 }
9512 break;
bellard8d18e892007-11-14 15:18:40 +00009513#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9514 ret = do_set_thread_area(cpu_env, arg1);
9515 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009516#elif defined(TARGET_M68K)
9517 {
Andreas Färber0429a972013-08-26 18:14:44 +02009518 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009519 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009520 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009521 break;
9522 }
ths6f5b89a2007-03-02 20:48:00 +00009523#else
9524 goto unimplemented_nowarn;
9525#endif
9526#endif
9527#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009528 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009529#if defined(TARGET_I386) && defined(TARGET_ABI32)
9530 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009531 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009532#elif defined(TARGET_M68K)
9533 {
Andreas Färber0429a972013-08-26 18:14:44 +02009534 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009535 ret = ts->tp_value;
9536 break;
9537 }
bellard8d18e892007-11-14 15:18:40 +00009538#else
bellard5cd43932003-03-29 16:54:36 +00009539 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009540#endif
bellard8d18e892007-11-14 15:18:40 +00009541#endif
bellard48dc41e2006-06-21 18:15:50 +00009542#ifdef TARGET_NR_getdomainname
9543 case TARGET_NR_getdomainname:
9544 goto unimplemented_nowarn;
9545#endif
ths6f5b89a2007-03-02 20:48:00 +00009546
thsb5906f92007-03-19 13:32:45 +00009547#ifdef TARGET_NR_clock_gettime
9548 case TARGET_NR_clock_gettime:
9549 {
9550 struct timespec ts;
9551 ret = get_errno(clock_gettime(arg1, &ts));
9552 if (!is_error(ret)) {
9553 host_to_target_timespec(arg2, &ts);
9554 }
9555 break;
9556 }
9557#endif
9558#ifdef TARGET_NR_clock_getres
9559 case TARGET_NR_clock_getres:
9560 {
9561 struct timespec ts;
9562 ret = get_errno(clock_getres(arg1, &ts));
9563 if (!is_error(ret)) {
9564 host_to_target_timespec(arg2, &ts);
9565 }
9566 break;
9567 }
9568#endif
pbrook63d76512008-05-29 13:43:29 +00009569#ifdef TARGET_NR_clock_nanosleep
9570 case TARGET_NR_clock_nanosleep:
9571 {
9572 struct timespec ts;
9573 target_to_host_timespec(&ts, arg3);
9574 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9575 if (arg4)
9576 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009577
9578#if defined(TARGET_PPC)
9579 /* clock_nanosleep is odd in that it returns positive errno values.
9580 * On PPC, CR0 bit 3 should be set in such a situation. */
9581 if (ret) {
9582 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9583 }
9584#endif
pbrook63d76512008-05-29 13:43:29 +00009585 break;
9586 }
9587#endif
thsb5906f92007-03-19 13:32:45 +00009588
ths6f5b89a2007-03-02 20:48:00 +00009589#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9590 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009591 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9592 break;
ths6f5b89a2007-03-02 20:48:00 +00009593#endif
9594
ths3ae43202007-09-16 21:39:48 +00009595#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009596 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009597 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009598 break;
9599#endif
9600
ths3ae43202007-09-16 21:39:48 +00009601#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009602 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009603 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9604 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009605 break;
9606#endif
9607
ths4f2b1fe2007-06-21 21:57:12 +00009608#ifdef TARGET_NR_set_robust_list
9609 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009610 case TARGET_NR_get_robust_list:
9611 /* The ABI for supporting robust futexes has userspace pass
9612 * the kernel a pointer to a linked list which is updated by
9613 * userspace after the syscall; the list is walked by the kernel
9614 * when the thread exits. Since the linked list in QEMU guest
9615 * memory isn't a valid linked list for the host and we have
9616 * no way to reliably intercept the thread-death event, we can't
9617 * support these. Silently return ENOSYS so that guest userspace
9618 * falls back to a non-robust futex implementation (which should
9619 * be OK except in the corner case of the guest crashing while
9620 * holding a mutex that is shared with another process via
9621 * shared memory).
9622 */
9623 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009624#endif
9625
Peter Maydell1acae9f2013-07-02 14:04:12 +01009626#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009627 case TARGET_NR_utimensat:
9628 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009629 struct timespec *tsp, ts[2];
9630 if (!arg3) {
9631 tsp = NULL;
9632 } else {
9633 target_to_host_timespec(ts, arg3);
9634 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9635 tsp = ts;
9636 }
ths9007f0e2007-09-25 17:50:37 +00009637 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009638 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009639 else {
bellard579a97f2007-11-11 14:26:47 +00009640 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009641 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009642 goto fail;
9643 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009644 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009645 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009646 }
9647 }
9648 break;
9649#endif
pbrookbd0c5662008-05-29 14:34:11 +00009650 case TARGET_NR_futex:
9651 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9652 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009653#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009654 case TARGET_NR_inotify_init:
9655 ret = get_errno(sys_inotify_init());
9656 break;
9657#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009658#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009659#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9660 case TARGET_NR_inotify_init1:
9661 ret = get_errno(sys_inotify_init1(arg1));
9662 break;
9663#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009664#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009665#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009666 case TARGET_NR_inotify_add_watch:
9667 p = lock_user_string(arg2);
9668 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9669 unlock_user(p, arg2, 0);
9670 break;
9671#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009672#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009673 case TARGET_NR_inotify_rm_watch:
9674 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9675 break;
9676#endif
ths9007f0e2007-09-25 17:50:37 +00009677
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009678#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009679 case TARGET_NR_mq_open:
9680 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009681 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009682
9683 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009684 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009685 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009686 attrp = &posix_mq_attr;
9687 } else {
9688 attrp = 0;
9689 }
9690 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009691 unlock_user (p, arg1, 0);
9692 }
9693 break;
9694
9695 case TARGET_NR_mq_unlink:
9696 p = lock_user_string(arg1 - 1);
9697 ret = get_errno(mq_unlink(p));
9698 unlock_user (p, arg1, 0);
9699 break;
9700
9701 case TARGET_NR_mq_timedsend:
9702 {
9703 struct timespec ts;
9704
9705 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9706 if (arg5 != 0) {
9707 target_to_host_timespec(&ts, arg5);
9708 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9709 host_to_target_timespec(arg5, &ts);
9710 }
9711 else
9712 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9713 unlock_user (p, arg2, arg3);
9714 }
9715 break;
9716
9717 case TARGET_NR_mq_timedreceive:
9718 {
9719 struct timespec ts;
9720 unsigned int prio;
9721
9722 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9723 if (arg5 != 0) {
9724 target_to_host_timespec(&ts, arg5);
9725 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9726 host_to_target_timespec(arg5, &ts);
9727 }
9728 else
9729 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9730 unlock_user (p, arg2, arg3);
9731 if (arg4 != 0)
9732 put_user_u32(prio, arg4);
9733 }
9734 break;
9735
9736 /* Not implemented for now... */
9737/* case TARGET_NR_mq_notify: */
9738/* break; */
9739
9740 case TARGET_NR_mq_getsetattr:
9741 {
9742 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9743 ret = 0;
9744 if (arg3 != 0) {
9745 ret = mq_getattr(arg1, &posix_mq_attr_out);
9746 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9747 }
9748 if (arg2 != 0) {
9749 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9750 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9751 }
9752
9753 }
9754 break;
9755#endif
9756
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309757#ifdef CONFIG_SPLICE
9758#ifdef TARGET_NR_tee
9759 case TARGET_NR_tee:
9760 {
9761 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9762 }
9763 break;
9764#endif
9765#ifdef TARGET_NR_splice
9766 case TARGET_NR_splice:
9767 {
9768 loff_t loff_in, loff_out;
9769 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +01009770 if (arg2) {
9771 if (get_user_u64(loff_in, arg2)) {
9772 goto efault;
9773 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309774 ploff_in = &loff_in;
9775 }
Andreas Schwab17644b32015-03-10 17:11:35 +01009776 if (arg4) {
9777 if (get_user_u64(loff_out, arg4)) {
9778 goto efault;
9779 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309780 ploff_out = &loff_out;
9781 }
9782 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +01009783 if (arg2) {
9784 if (put_user_u64(loff_in, arg2)) {
9785 goto efault;
9786 }
9787 }
9788 if (arg4) {
9789 if (put_user_u64(loff_out, arg4)) {
9790 goto efault;
9791 }
9792 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309793 }
9794 break;
9795#endif
9796#ifdef TARGET_NR_vmsplice
9797 case TARGET_NR_vmsplice:
9798 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009799 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9800 if (vec != NULL) {
9801 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9802 unlock_iovec(vec, arg2, arg3, 0);
9803 } else {
9804 ret = -host_to_target_errno(errno);
9805 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309806 }
9807 break;
9808#endif
9809#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009810#ifdef CONFIG_EVENTFD
9811#if defined(TARGET_NR_eventfd)
9812 case TARGET_NR_eventfd:
9813 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +02009814 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009815 break;
9816#endif
9817#if defined(TARGET_NR_eventfd2)
9818 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009819 {
9820 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9821 if (arg2 & TARGET_O_NONBLOCK) {
9822 host_flags |= O_NONBLOCK;
9823 }
9824 if (arg2 & TARGET_O_CLOEXEC) {
9825 host_flags |= O_CLOEXEC;
9826 }
9827 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +02009828 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +03009829 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009830 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009831#endif
9832#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009833#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9834 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009835#if TARGET_ABI_BITS == 32
9836 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9837 target_offset64(arg5, arg6)));
9838#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009839 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009840#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009841 break;
9842#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009843#if defined(CONFIG_SYNC_FILE_RANGE)
9844#if defined(TARGET_NR_sync_file_range)
9845 case TARGET_NR_sync_file_range:
9846#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009847#if defined(TARGET_MIPS)
9848 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9849 target_offset64(arg5, arg6), arg7));
9850#else
Peter Maydellc727f472011-01-06 11:05:10 +00009851 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9852 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009853#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009854#else
9855 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9856#endif
9857 break;
9858#endif
9859#if defined(TARGET_NR_sync_file_range2)
9860 case TARGET_NR_sync_file_range2:
9861 /* This is like sync_file_range but the arguments are reordered */
9862#if TARGET_ABI_BITS == 32
9863 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9864 target_offset64(arg5, arg6), arg2));
9865#else
9866 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9867#endif
9868 break;
9869#endif
9870#endif
Laurent Viviere36800c2015-10-02 14:48:09 +02009871#if defined(TARGET_NR_signalfd4)
9872 case TARGET_NR_signalfd4:
9873 ret = do_signalfd4(arg1, arg2, arg4);
9874 break;
9875#endif
9876#if defined(TARGET_NR_signalfd)
9877 case TARGET_NR_signalfd:
9878 ret = do_signalfd4(arg1, arg2, 0);
9879 break;
9880#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009881#if defined(CONFIG_EPOLL)
9882#if defined(TARGET_NR_epoll_create)
9883 case TARGET_NR_epoll_create:
9884 ret = get_errno(epoll_create(arg1));
9885 break;
9886#endif
9887#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9888 case TARGET_NR_epoll_create1:
9889 ret = get_errno(epoll_create1(arg1));
9890 break;
9891#endif
9892#if defined(TARGET_NR_epoll_ctl)
9893 case TARGET_NR_epoll_ctl:
9894 {
9895 struct epoll_event ep;
9896 struct epoll_event *epp = 0;
9897 if (arg4) {
9898 struct target_epoll_event *target_ep;
9899 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9900 goto efault;
9901 }
9902 ep.events = tswap32(target_ep->events);
9903 /* The epoll_data_t union is just opaque data to the kernel,
9904 * so we transfer all 64 bits across and need not worry what
9905 * actual data type it is.
9906 */
9907 ep.data.u64 = tswap64(target_ep->data.u64);
9908 unlock_user_struct(target_ep, arg4, 0);
9909 epp = &ep;
9910 }
9911 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9912 break;
9913 }
9914#endif
9915
9916#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9917#define IMPLEMENT_EPOLL_PWAIT
9918#endif
9919#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9920#if defined(TARGET_NR_epoll_wait)
9921 case TARGET_NR_epoll_wait:
9922#endif
9923#if defined(IMPLEMENT_EPOLL_PWAIT)
9924 case TARGET_NR_epoll_pwait:
9925#endif
9926 {
9927 struct target_epoll_event *target_ep;
9928 struct epoll_event *ep;
9929 int epfd = arg1;
9930 int maxevents = arg3;
9931 int timeout = arg4;
9932
9933 target_ep = lock_user(VERIFY_WRITE, arg2,
9934 maxevents * sizeof(struct target_epoll_event), 1);
9935 if (!target_ep) {
9936 goto efault;
9937 }
9938
9939 ep = alloca(maxevents * sizeof(struct epoll_event));
9940
9941 switch (num) {
9942#if defined(IMPLEMENT_EPOLL_PWAIT)
9943 case TARGET_NR_epoll_pwait:
9944 {
9945 target_sigset_t *target_set;
9946 sigset_t _set, *set = &_set;
9947
9948 if (arg5) {
9949 target_set = lock_user(VERIFY_READ, arg5,
9950 sizeof(target_sigset_t), 1);
9951 if (!target_set) {
9952 unlock_user(target_ep, arg2, 0);
9953 goto efault;
9954 }
9955 target_to_host_sigset(set, target_set);
9956 unlock_user(target_set, arg5, 0);
9957 } else {
9958 set = NULL;
9959 }
9960
9961 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9962 break;
9963 }
9964#endif
9965#if defined(TARGET_NR_epoll_wait)
9966 case TARGET_NR_epoll_wait:
9967 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9968 break;
9969#endif
9970 default:
9971 ret = -TARGET_ENOSYS;
9972 }
9973 if (!is_error(ret)) {
9974 int i;
9975 for (i = 0; i < ret; i++) {
9976 target_ep[i].events = tswap32(ep[i].events);
9977 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9978 }
9979 }
9980 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9981 break;
9982 }
9983#endif
9984#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009985#ifdef TARGET_NR_prlimit64
9986 case TARGET_NR_prlimit64:
9987 {
9988 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9989 struct target_rlimit64 *target_rnew, *target_rold;
9990 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +01009991 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +01009992 if (arg3) {
9993 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9994 goto efault;
9995 }
9996 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9997 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9998 unlock_user_struct(target_rnew, arg3, 0);
9999 rnewp = &rnew;
10000 }
10001
Felix Janda95018012014-12-02 22:11:17 +010010002 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010003 if (!is_error(ret) && arg4) {
10004 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10005 goto efault;
10006 }
10007 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10008 target_rold->rlim_max = tswap64(rold.rlim_max);
10009 unlock_user_struct(target_rold, arg4, 1);
10010 }
10011 break;
10012 }
10013#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010014#ifdef TARGET_NR_gethostname
10015 case TARGET_NR_gethostname:
10016 {
10017 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10018 if (name) {
10019 ret = get_errno(gethostname(name, arg2));
10020 unlock_user(name, arg1, arg2);
10021 } else {
10022 ret = -TARGET_EFAULT;
10023 }
10024 break;
10025 }
10026#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010027#ifdef TARGET_NR_atomic_cmpxchg_32
10028 case TARGET_NR_atomic_cmpxchg_32:
10029 {
10030 /* should use start_exclusive from main.c */
10031 abi_ulong mem_value;
10032 if (get_user_u32(mem_value, arg6)) {
10033 target_siginfo_t info;
10034 info.si_signo = SIGSEGV;
10035 info.si_errno = 0;
10036 info.si_code = TARGET_SEGV_MAPERR;
10037 info._sifields._sigfault._addr = arg6;
10038 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10039 ret = 0xdeadbeef;
10040
10041 }
10042 if (mem_value == arg2)
10043 put_user_u32(arg1, arg6);
10044 ret = mem_value;
10045 break;
10046 }
10047#endif
10048#ifdef TARGET_NR_atomic_barrier
10049 case TARGET_NR_atomic_barrier:
10050 {
10051 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010052 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010053 break;
10054 }
10055#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010056
10057#ifdef TARGET_NR_timer_create
10058 case TARGET_NR_timer_create:
10059 {
10060 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10061
10062 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010063
10064 int clkid = arg1;
10065 int timer_index = next_free_host_timer();
10066
10067 if (timer_index < 0) {
10068 ret = -TARGET_EAGAIN;
10069 } else {
10070 timer_t *phtimer = g_posix_timers + timer_index;
10071
10072 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010073 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010074 ret = target_to_host_sigevent(phost_sevp, arg2);
10075 if (ret != 0) {
10076 break;
10077 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010078 }
10079
10080 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10081 if (ret) {
10082 phtimer = NULL;
10083 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010084 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010085 goto efault;
10086 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010087 }
10088 }
10089 break;
10090 }
10091#endif
10092
10093#ifdef TARGET_NR_timer_settime
10094 case TARGET_NR_timer_settime:
10095 {
10096 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
10097 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010098 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010099
Alexander Grafaecc8862014-11-10 21:33:03 +010010100 if (timerid < 0) {
10101 ret = timerid;
10102 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010103 ret = -TARGET_EINVAL;
10104 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010105 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010106 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
10107
10108 target_to_host_itimerspec(&hspec_new, arg3);
10109 ret = get_errno(
10110 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
10111 host_to_target_itimerspec(arg2, &hspec_old);
10112 }
10113 break;
10114 }
10115#endif
10116
10117#ifdef TARGET_NR_timer_gettime
10118 case TARGET_NR_timer_gettime:
10119 {
10120 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010010121 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010122
Alexander Grafaecc8862014-11-10 21:33:03 +010010123 if (timerid < 0) {
10124 ret = timerid;
10125 } else if (!arg2) {
10126 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010127 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010128 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010129 struct itimerspec hspec;
10130 ret = get_errno(timer_gettime(htimer, &hspec));
10131
10132 if (host_to_target_itimerspec(arg2, &hspec)) {
10133 ret = -TARGET_EFAULT;
10134 }
10135 }
10136 break;
10137 }
10138#endif
10139
10140#ifdef TARGET_NR_timer_getoverrun
10141 case TARGET_NR_timer_getoverrun:
10142 {
10143 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010144 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010145
Alexander Grafaecc8862014-11-10 21:33:03 +010010146 if (timerid < 0) {
10147 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010148 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010149 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010150 ret = get_errno(timer_getoverrun(htimer));
10151 }
Laurent Viviere36800c2015-10-02 14:48:09 +020010152 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010153 break;
10154 }
10155#endif
10156
10157#ifdef TARGET_NR_timer_delete
10158 case TARGET_NR_timer_delete:
10159 {
10160 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010010161 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020010162
Alexander Grafaecc8862014-11-10 21:33:03 +010010163 if (timerid < 0) {
10164 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010165 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020010166 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010167 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020010168 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010169 }
10170 break;
10171 }
10172#endif
10173
Riku Voipio51834342014-06-22 11:25:42 +010010174#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
10175 case TARGET_NR_timerfd_create:
10176 ret = get_errno(timerfd_create(arg1,
10177 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
10178 break;
10179#endif
10180
10181#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
10182 case TARGET_NR_timerfd_gettime:
10183 {
10184 struct itimerspec its_curr;
10185
10186 ret = get_errno(timerfd_gettime(arg1, &its_curr));
10187
10188 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
10189 goto efault;
10190 }
10191 }
10192 break;
10193#endif
10194
10195#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
10196 case TARGET_NR_timerfd_settime:
10197 {
10198 struct itimerspec its_new, its_old, *p_new;
10199
10200 if (arg3) {
10201 if (target_to_host_itimerspec(&its_new, arg3)) {
10202 goto efault;
10203 }
10204 p_new = &its_new;
10205 } else {
10206 p_new = NULL;
10207 }
10208
10209 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
10210
10211 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
10212 goto efault;
10213 }
10214 }
10215 break;
10216#endif
10217
Paul Burtonab31cda2014-06-22 11:25:43 +010010218#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
10219 case TARGET_NR_ioprio_get:
10220 ret = get_errno(ioprio_get(arg1, arg2));
10221 break;
10222#endif
10223
10224#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
10225 case TARGET_NR_ioprio_set:
10226 ret = get_errno(ioprio_set(arg1, arg2, arg3));
10227 break;
10228#endif
10229
Riku Voipio9af5c902014-08-12 15:58:57 +030010230#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
10231 case TARGET_NR_setns:
10232 ret = get_errno(setns(arg1, arg2));
10233 break;
10234#endif
10235#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
10236 case TARGET_NR_unshare:
10237 ret = get_errno(unshare(arg1));
10238 break;
10239#endif
10240
bellard31e31b82003-02-18 22:55:36 +000010241 default:
10242 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000010243 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000010244#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 +000010245 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000010246#endif
ths0da46a62007-10-20 20:23:07 +000010247 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000010248 break;
10249 }
bellard579a97f2007-11-11 14:26:47 +000010250fail:
bellardc573ff62004-01-04 15:51:36 +000010251#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000010252 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000010253#endif
thsb92c47c2007-11-01 00:07:38 +000010254 if(do_strace)
10255 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000010256 return ret;
bellard579a97f2007-11-11 14:26:47 +000010257efault:
10258 ret = -TARGET_EFAULT;
10259 goto fail;
bellard31e31b82003-02-18 22:55:36 +000010260}