blob: a931919816f4f9bbed9f7f858ce8779e9d07bbe7 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
Peter Maydelld39594e2016-01-26 18:17:02 +000020#include "qemu/osdep.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020021#include "qemu/cutils.h"
22#include "qemu/path.h"
bellard31e31b82003-02-18 22:55:36 +000023#include <elf.h>
24#include <endian.h>
John Spencerc56dc772012-12-10 07:59:46 +010025#include <grp.h>
thsd08d3bb2007-03-19 13:09:22 +000026#include <sys/ipc.h>
27#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/wait.h>
bellard31e31b82003-02-18 22:55:36 +000029#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010030#include <sys/file.h>
31#include <sys/fsuid.h>
32#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000033#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000034#include <sys/resource.h>
35#include <sys/mman.h>
36#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000037#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000038#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020039#ifdef __ia64__
40int __clone2(int (*fn)(void *), void *child_stack_base,
41 size_t stack_size, int flags, void *arg, ...);
42#endif
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000044#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000045#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000046#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000047#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000048#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000049#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000050#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000051#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000052#include <sys/sysinfo.h>
Laurent Viviere36800c2015-10-02 14:48:09 +020053#include <sys/signalfd.h>
bellard72f03902003-02-18 23:33:18 +000054//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000055#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000056#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020057#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000058#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020059#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030060#ifdef CONFIG_TIMERFD
61#include <sys/timerfd.h>
62#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020063#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000064#include <sys/gmon.h>
65#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030066#ifdef CONFIG_EVENTFD
67#include <sys/eventfd.h>
68#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000069#ifdef CONFIG_EPOLL
70#include <sys/epoll.h>
71#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070072#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010073#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070074#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000075#ifdef CONFIG_SENDFILE
76#include <sys/sendfile.h>
77#endif
bellard31e31b82003-02-18 22:55:36 +000078
79#define termios host_termios
80#define winsize host_winsize
81#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000082#define sgttyb host_sgttyb /* same as target */
83#define tchars host_tchars /* same as target */
84#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000085
86#include <linux/termios.h>
87#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000088#include <linux/cdrom.h>
89#include <linux/hdreg.h>
90#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000091#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000092#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030093#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000094#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +000095#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +000096#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +020097#include <linux/fb.h>
98#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +010099#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000100#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100101#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200102#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100103#include <linux/blkpg.h>
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200104#include <linux/netlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200105#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200106#include <linux/rtnetlink.h>
Laurent Vivier575b22b2016-06-02 22:14:15 +0200107#endif
Laurent Vivier5ce9bb52016-05-22 18:56:21 +0200108#include <linux/audit.h>
pbrookd7e40362008-05-23 16:06:43 +0000109#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200110#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000111
bellard3ef693a2003-03-23 20:17:16 +0000112#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000113
pbrookd865bab2008-06-07 22:12:17 +0000114#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
115 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000116
bellard72f03902003-02-18 23:33:18 +0000117//#define DEBUG
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +0100118/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
119 * once. This exercises the codepaths for restart.
120 */
121//#define DEBUG_ERESTARTSYS
bellard31e31b82003-02-18 22:55:36 +0000122
bellard1a9353d2003-03-16 20:28:50 +0000123//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000124#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
125#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000126
Peter Maydellb28a1f32016-05-27 15:51:47 +0100127/* This is the size of the host kernel's sigset_t, needed where we make
128 * direct system calls that take a sigset_t pointer and a size.
129 */
130#define SIGSET_T_SIZE (_NSIG / 8)
bellard70a194b2003-08-11 22:20:16 +0000131
bellard70a194b2003-08-11 22:20:16 +0000132#undef _syscall0
133#undef _syscall1
134#undef _syscall2
135#undef _syscall3
136#undef _syscall4
137#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000138#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000162}
163
bellard83fcb512006-06-14 13:37:16 +0000164#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000165static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000168}
169
bellard83fcb512006-06-14 13:37:16 +0000170#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
171 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000172static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000173{ \
174 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000175}
bellard83fcb512006-06-14 13:37:16 +0000176
177
178#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
179 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000180static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
181 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000182{ \
183 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
184}
185
bellard70a194b2003-08-11 22:20:16 +0000186
bellard31e31b82003-02-18 22:55:36 +0000187#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000188#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000189#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000190#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000191#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000192#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000193#define __NR_sys_syslog __NR_syslog
pbrookbd0c5662008-05-29 14:34:11 +0000194#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000195#define __NR_sys_inotify_init __NR_inotify_init
196#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
197#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000198
Alexander Graf42a39fb2011-04-15 17:32:45 +0200199#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
200 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000201#define __NR__llseek __NR_lseek
202#endif
203
James Hogana29e5ba2014-03-25 21:51:08 +0000204/* Newer kernel ports have llseek() instead of _llseek() */
205#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
206#define TARGET_NR__llseek TARGET_NR_llseek
207#endif
208
bellard72f03902003-02-18 23:33:18 +0000209#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000210_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000211#else
ths0da46a62007-10-20 20:23:07 +0000212/* This is a replacement for the host gettid() and must return a host
213 errno. */
bellard72f03902003-02-18 23:33:18 +0000214static int gettid(void) {
215 return -ENOSYS;
216}
217#endif
Chen Gang704eff62015-08-21 05:37:33 +0800218#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
aurel323b3f24a2009-04-15 16:12:13 +0000219_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100220#endif
221#if !defined(__NR_getdents) || \
222 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000223_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
224#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700225#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000226_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
227 loff_t *, res, uint, wh);
228#endif
229_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
230_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
aurel323b3f24a2009-04-15 16:12:13 +0000231#ifdef __NR_exit_group
232_syscall1(int,exit_group,int,error_code)
233#endif
234#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
235_syscall1(int,set_tid_address,int *,tidptr)
236#endif
aurel323b3f24a2009-04-15 16:12:13 +0000237#if defined(TARGET_NR_futex) && defined(__NR_futex)
238_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
239 const struct timespec *,timeout,int *,uaddr2,int,val3)
240#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500241#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
242_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
243 unsigned long *, user_mask_ptr);
244#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
245_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
246 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200247_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
248 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000249_syscall2(int, capget, struct __user_cap_header_struct *, header,
250 struct __user_cap_data_struct *, data);
251_syscall2(int, capset, struct __user_cap_header_struct *, header,
252 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100253#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
254_syscall2(int, ioprio_get, int, which, int, who)
255#endif
256#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
257_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
258#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +0100259#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
260_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
261#endif
aurel323b3f24a2009-04-15 16:12:13 +0000262
263static bitmask_transtbl fcntl_flags_tbl[] = {
264 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
265 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
266 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
267 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
268 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
269 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
270 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
271 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700272 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000273 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
274 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
275 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
276 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000277#if defined(O_DIRECT)
278 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
279#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700280#if defined(O_NOATIME)
281 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
282#endif
283#if defined(O_CLOEXEC)
284 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
285#endif
286#if defined(O_PATH)
287 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
288#endif
289 /* Don't terminate the list prematurely on 64-bit host+guest. */
290#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
291 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
292#endif
aurel323b3f24a2009-04-15 16:12:13 +0000293 { 0, 0, 0, 0 }
294};
295
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100296typedef abi_long (*TargetFdDataFunc)(void *, size_t);
Laurent Vivier7b36f782015-10-28 21:40:44 +0100297typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
Laurent Viviere36800c2015-10-02 14:48:09 +0200298typedef struct TargetFdTrans {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100299 TargetFdDataFunc host_to_target_data;
300 TargetFdDataFunc target_to_host_data;
Laurent Vivier7b36f782015-10-28 21:40:44 +0100301 TargetFdAddrFunc target_to_host_addr;
Laurent Viviere36800c2015-10-02 14:48:09 +0200302} TargetFdTrans;
303
304static TargetFdTrans **target_fd_trans;
305
306static unsigned int target_fd_max;
307
Laurent Vivier6c5b5642016-05-22 18:56:19 +0200308static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
309{
310 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
311 return target_fd_trans[fd]->target_to_host_data;
312 }
313 return NULL;
314}
315
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100316static TargetFdDataFunc fd_trans_host_to_target_data(int fd)
Laurent Viviere36800c2015-10-02 14:48:09 +0200317{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100318 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier5d4d3662015-10-28 21:40:43 +0100319 return target_fd_trans[fd]->host_to_target_data;
Laurent Viviere36800c2015-10-02 14:48:09 +0200320 }
321 return NULL;
322}
323
Laurent Vivier7b36f782015-10-28 21:40:44 +0100324static TargetFdAddrFunc fd_trans_target_to_host_addr(int fd)
325{
Laurent Vivier861d72c2015-10-28 21:40:46 +0100326 if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
Laurent Vivier7b36f782015-10-28 21:40:44 +0100327 return target_fd_trans[fd]->target_to_host_addr;
328 }
329 return NULL;
330}
331
Laurent Viviere36800c2015-10-02 14:48:09 +0200332static void fd_trans_register(int fd, TargetFdTrans *trans)
333{
334 unsigned int oldmax;
335
336 if (fd >= target_fd_max) {
337 oldmax = target_fd_max;
338 target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
Laurent Vivier5089c7c2016-01-18 23:50:45 +0100339 target_fd_trans = g_renew(TargetFdTrans *,
340 target_fd_trans, target_fd_max);
Laurent Viviere36800c2015-10-02 14:48:09 +0200341 memset((void *)(target_fd_trans + oldmax), 0,
342 (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
343 }
344 target_fd_trans[fd] = trans;
345}
346
347static void fd_trans_unregister(int fd)
348{
349 if (fd >= 0 && fd < target_fd_max) {
350 target_fd_trans[fd] = NULL;
351 }
352}
353
354static void fd_trans_dup(int oldfd, int newfd)
355{
356 fd_trans_unregister(newfd);
357 if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
358 fd_trans_register(newfd, target_fd_trans[oldfd]);
359 }
360}
361
aurel323b3f24a2009-04-15 16:12:13 +0000362static int sys_getcwd1(char *buf, size_t size)
363{
364 if (getcwd(buf, size) == NULL) {
365 /* getcwd() sets errno */
366 return (-1);
367 }
aurel32aaf4ad32009-04-16 14:17:14 +0000368 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000369}
370
Peter Maydell1acae9f2013-07-02 14:04:12 +0100371#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300372#ifdef CONFIG_UTIMENSAT
373static int sys_utimensat(int dirfd, const char *pathname,
374 const struct timespec times[2], int flags)
375{
376 if (pathname == NULL)
377 return futimens(dirfd, times);
378 else
379 return utimensat(dirfd, pathname, times, flags);
380}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100381#elif defined(__NR_utimensat)
382#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000383_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
384 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100385#else
386static int sys_utimensat(int dirfd, const char *pathname,
387 const struct timespec times[2], int flags)
388{
389 errno = ENOSYS;
390 return -1;
391}
ths9007f0e2007-09-25 17:50:37 +0000392#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100393#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000394
395#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000396#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000397
aurel3239b59762008-10-01 21:46:50 +0000398#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000399static int sys_inotify_init(void)
400{
401 return (inotify_init());
402}
aurel3239b59762008-10-01 21:46:50 +0000403#endif
404#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000405static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
406{
407 return (inotify_add_watch(fd, pathname, mask));
408}
aurel3239b59762008-10-01 21:46:50 +0000409#endif
410#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000411static int sys_inotify_rm_watch(int fd, int32_t wd)
412{
aurel328690e422009-04-17 13:50:32 +0000413 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000414}
aurel3239b59762008-10-01 21:46:50 +0000415#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000416#ifdef CONFIG_INOTIFY1
417#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
418static int sys_inotify_init1(int flags)
419{
420 return (inotify_init1(flags));
421}
422#endif
423#endif
aurel323b3f24a2009-04-15 16:12:13 +0000424#else
425/* Userspace can usually survive runtime without inotify */
426#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000427#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000428#undef TARGET_NR_inotify_add_watch
429#undef TARGET_NR_inotify_rm_watch
430#endif /* CONFIG_INOTIFY */
431
Mike Frysingerd8035d42011-02-07 01:05:51 -0500432#if defined(TARGET_NR_ppoll)
433#ifndef __NR_ppoll
434# define __NR_ppoll -1
435#endif
436#define __NR_sys_ppoll __NR_ppoll
437_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200438 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500439 size_t, sigsetsize)
440#endif
bellard66fb9762003-03-23 01:06:05 +0000441
Peter Maydell163a05a2011-06-27 17:44:52 +0100442#if defined(TARGET_NR_prlimit64)
443#ifndef __NR_prlimit64
444# define __NR_prlimit64 -1
445#endif
446#define __NR_sys_prlimit64 __NR_prlimit64
447/* The glibc rlimit structure may not be that used by the underlying syscall */
448struct host_rlimit64 {
449 uint64_t rlim_cur;
450 uint64_t rlim_max;
451};
452_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
453 const struct host_rlimit64 *, new_limit,
454 struct host_rlimit64 *, old_limit)
455#endif
456
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100457
458#if defined(TARGET_NR_timer_create)
459/* Maxiumum of 32 active POSIX timers allowed at any one time. */
460static timer_t g_posix_timers[32] = { 0, } ;
461
462static inline int next_free_host_timer(void)
463{
464 int k ;
465 /* FIXME: Does finding the next free slot require a lock? */
466 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
467 if (g_posix_timers[k] == 0) {
468 g_posix_timers[k] = (timer_t) 1;
469 return k;
470 }
471 }
472 return -1;
473}
474#endif
475
Riku Voipio48e515d2011-07-12 15:40:51 +0300476/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000477#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300478static inline int regpairs_aligned(void *cpu_env) {
479 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
480}
481#elif defined(TARGET_MIPS)
482static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000483#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
484/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
485 * of registers which translates to the same as ARM/MIPS, because we start with
486 * r3 as arg1 */
487static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300488#else
489static inline int regpairs_aligned(void *cpu_env) { return 0; }
490#endif
491
thsb92c47c2007-11-01 00:07:38 +0000492#define ERRNO_TABLE_SIZE 1200
493
494/* target_to_host_errno_table[] is initialized from
495 * host_to_target_errno_table[] in syscall_init(). */
496static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
497};
498
ths637947f2007-06-01 12:09:19 +0000499/*
thsfe8f0962007-07-12 10:59:21 +0000500 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000501 * minus the errnos that are not actually generic to all archs.
502 */
thsb92c47c2007-11-01 00:07:38 +0000503static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
Chen Gang08703b92015-09-07 10:35:06 +0800504 [EAGAIN] = TARGET_EAGAIN,
ths637947f2007-06-01 12:09:19 +0000505 [EIDRM] = TARGET_EIDRM,
506 [ECHRNG] = TARGET_ECHRNG,
507 [EL2NSYNC] = TARGET_EL2NSYNC,
508 [EL3HLT] = TARGET_EL3HLT,
509 [EL3RST] = TARGET_EL3RST,
510 [ELNRNG] = TARGET_ELNRNG,
511 [EUNATCH] = TARGET_EUNATCH,
512 [ENOCSI] = TARGET_ENOCSI,
513 [EL2HLT] = TARGET_EL2HLT,
514 [EDEADLK] = TARGET_EDEADLK,
515 [ENOLCK] = TARGET_ENOLCK,
516 [EBADE] = TARGET_EBADE,
517 [EBADR] = TARGET_EBADR,
518 [EXFULL] = TARGET_EXFULL,
519 [ENOANO] = TARGET_ENOANO,
520 [EBADRQC] = TARGET_EBADRQC,
521 [EBADSLT] = TARGET_EBADSLT,
522 [EBFONT] = TARGET_EBFONT,
523 [ENOSTR] = TARGET_ENOSTR,
524 [ENODATA] = TARGET_ENODATA,
525 [ETIME] = TARGET_ETIME,
526 [ENOSR] = TARGET_ENOSR,
527 [ENONET] = TARGET_ENONET,
528 [ENOPKG] = TARGET_ENOPKG,
529 [EREMOTE] = TARGET_EREMOTE,
530 [ENOLINK] = TARGET_ENOLINK,
531 [EADV] = TARGET_EADV,
532 [ESRMNT] = TARGET_ESRMNT,
533 [ECOMM] = TARGET_ECOMM,
534 [EPROTO] = TARGET_EPROTO,
535 [EDOTDOT] = TARGET_EDOTDOT,
536 [EMULTIHOP] = TARGET_EMULTIHOP,
537 [EBADMSG] = TARGET_EBADMSG,
538 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
539 [EOVERFLOW] = TARGET_EOVERFLOW,
540 [ENOTUNIQ] = TARGET_ENOTUNIQ,
541 [EBADFD] = TARGET_EBADFD,
542 [EREMCHG] = TARGET_EREMCHG,
543 [ELIBACC] = TARGET_ELIBACC,
544 [ELIBBAD] = TARGET_ELIBBAD,
545 [ELIBSCN] = TARGET_ELIBSCN,
546 [ELIBMAX] = TARGET_ELIBMAX,
547 [ELIBEXEC] = TARGET_ELIBEXEC,
548 [EILSEQ] = TARGET_EILSEQ,
549 [ENOSYS] = TARGET_ENOSYS,
550 [ELOOP] = TARGET_ELOOP,
551 [ERESTART] = TARGET_ERESTART,
552 [ESTRPIPE] = TARGET_ESTRPIPE,
553 [ENOTEMPTY] = TARGET_ENOTEMPTY,
554 [EUSERS] = TARGET_EUSERS,
555 [ENOTSOCK] = TARGET_ENOTSOCK,
556 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
557 [EMSGSIZE] = TARGET_EMSGSIZE,
558 [EPROTOTYPE] = TARGET_EPROTOTYPE,
559 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
560 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
561 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
562 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
563 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
564 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
565 [EADDRINUSE] = TARGET_EADDRINUSE,
566 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
567 [ENETDOWN] = TARGET_ENETDOWN,
568 [ENETUNREACH] = TARGET_ENETUNREACH,
569 [ENETRESET] = TARGET_ENETRESET,
570 [ECONNABORTED] = TARGET_ECONNABORTED,
571 [ECONNRESET] = TARGET_ECONNRESET,
572 [ENOBUFS] = TARGET_ENOBUFS,
573 [EISCONN] = TARGET_EISCONN,
574 [ENOTCONN] = TARGET_ENOTCONN,
575 [EUCLEAN] = TARGET_EUCLEAN,
576 [ENOTNAM] = TARGET_ENOTNAM,
577 [ENAVAIL] = TARGET_ENAVAIL,
578 [EISNAM] = TARGET_EISNAM,
579 [EREMOTEIO] = TARGET_EREMOTEIO,
580 [ESHUTDOWN] = TARGET_ESHUTDOWN,
581 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
582 [ETIMEDOUT] = TARGET_ETIMEDOUT,
583 [ECONNREFUSED] = TARGET_ECONNREFUSED,
584 [EHOSTDOWN] = TARGET_EHOSTDOWN,
585 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
586 [EALREADY] = TARGET_EALREADY,
587 [EINPROGRESS] = TARGET_EINPROGRESS,
588 [ESTALE] = TARGET_ESTALE,
589 [ECANCELED] = TARGET_ECANCELED,
590 [ENOMEDIUM] = TARGET_ENOMEDIUM,
591 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000592#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000593 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000594#endif
595#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000596 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000597#endif
598#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000599 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000600#endif
601#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000602 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000603#endif
604#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000605 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000606#endif
607#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000608 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000609#endif
thsb92c47c2007-11-01 00:07:38 +0000610};
ths637947f2007-06-01 12:09:19 +0000611
612static inline int host_to_target_errno(int err)
613{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100614 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
615 host_to_target_errno_table[err]) {
ths637947f2007-06-01 12:09:19 +0000616 return host_to_target_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100617 }
ths637947f2007-06-01 12:09:19 +0000618 return err;
619}
620
thsb92c47c2007-11-01 00:07:38 +0000621static inline int target_to_host_errno(int err)
622{
Timothy E Baldwin24661192016-05-12 18:47:25 +0100623 if (err >= 0 && err < ERRNO_TABLE_SIZE &&
624 target_to_host_errno_table[err]) {
thsb92c47c2007-11-01 00:07:38 +0000625 return target_to_host_errno_table[err];
Timothy E Baldwin24661192016-05-12 18:47:25 +0100626 }
thsb92c47c2007-11-01 00:07:38 +0000627 return err;
628}
629
blueswir1992f48a2007-10-14 16:27:31 +0000630static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000631{
632 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000633 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000634 else
635 return ret;
636}
637
blueswir1992f48a2007-10-14 16:27:31 +0000638static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000639{
blueswir1992f48a2007-10-14 16:27:31 +0000640 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000641}
642
thsb92c47c2007-11-01 00:07:38 +0000643char *target_strerror(int err)
644{
Alexander Graf962b2892011-11-21 12:04:07 +0100645 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
646 return NULL;
647 }
thsb92c47c2007-11-01 00:07:38 +0000648 return strerror(target_to_host_errno(err));
649}
650
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100651#define safe_syscall0(type, name) \
652static type safe_##name(void) \
653{ \
654 return safe_syscall(__NR_##name); \
655}
656
657#define safe_syscall1(type, name, type1, arg1) \
658static type safe_##name(type1 arg1) \
659{ \
660 return safe_syscall(__NR_##name, arg1); \
661}
662
663#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
664static type safe_##name(type1 arg1, type2 arg2) \
665{ \
666 return safe_syscall(__NR_##name, arg1, arg2); \
667}
668
669#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
670static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
671{ \
672 return safe_syscall(__NR_##name, arg1, arg2, arg3); \
673}
674
675#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
676 type4, arg4) \
677static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
678{ \
679 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
680}
681
682#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
683 type4, arg4, type5, arg5) \
684static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
685 type5 arg5) \
686{ \
687 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
688}
689
690#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
691 type4, arg4, type5, arg5, type6, arg6) \
692static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
693 type5 arg5, type6 arg6) \
694{ \
695 return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
696}
697
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100698safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
699safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
Timothy E Baldwinc10a0732016-05-12 18:47:48 +0100700safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
701 int, flags, mode_t, mode)
Timothy E Baldwin4af80a32016-05-12 18:47:49 +0100702safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
703 struct rusage *, rusage)
704safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
705 int, options, struct rusage *, rusage)
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +0100706safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
Peter Maydell6df9d382016-05-12 18:47:51 +0100707safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
708 fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
Peter Maydelld509eeb2016-05-12 18:47:52 +0100709safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
710 const struct timespec *,timeout,int *,uaddr2,int,val3)
Peter Maydell2fe4fba2016-05-27 15:51:48 +0100711safe_syscall2(int, rt_sigsuspend, sigset_t *, newset, size_t, sigsetsize)
Peter Maydellbef653d2016-05-27 15:51:57 +0100712safe_syscall2(int, kill, pid_t, pid, int, sig)
713safe_syscall2(int, tkill, int, tid, int, sig)
714safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig)
Peter Maydell918c03e2016-06-06 19:58:02 +0100715safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt)
716safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt)
Peter Maydell2a3c7612016-06-06 19:58:03 +0100717safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
718 socklen_t, addrlen)
Peter Maydell66687532016-06-06 19:58:04 +0100719safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
720 int, flags, const struct sockaddr *, addr, socklen_t, addrlen)
721safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len,
722 int, flags, struct sockaddr *, addr, socklen_t *, addrlen)
723safe_syscall3(ssize_t, sendmsg, int, fd, const struct msghdr *, msg, int, flags)
724safe_syscall3(ssize_t, recvmsg, int, fd, struct msghdr *, msg, int, flags)
Peter Maydell2a845982016-06-06 19:58:07 +0100725safe_syscall2(int, flock, int, fd, int, operation)
Peter Maydellb3f82332016-06-06 19:58:08 +0100726safe_syscall4(int, rt_sigtimedwait, const sigset_t *, these, siginfo_t *, uinfo,
727 const struct timespec *, uts, size_t, sigsetsize)
Peter Maydell9e518222016-06-06 19:58:09 +0100728safe_syscall2(int, nanosleep, const struct timespec *, req,
729 struct timespec *, rem)
730#ifdef TARGET_NR_clock_nanosleep
731safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
732 const struct timespec *, req, struct timespec *, rem)
733#endif
Peter Maydell89f9fe42016-06-06 19:58:05 +0100734#ifdef __NR_msgsnd
735safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
736 int, flags)
737safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
738 long, msgtype, int, flags)
739#else
740/* This host kernel architecture uses a single ipc syscall; fake up
741 * wrappers for the sub-operations to hide this implementation detail.
742 * Annoyingly we can't include linux/ipc.h to get the constant definitions
743 * for the call parameter because some structs in there conflict with the
744 * sys/ipc.h ones. So we just define them here, and rely on them being
745 * the same for all host architectures.
746 */
747#define Q_MSGSND 11
748#define Q_MSGRCV 12
749#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
750
751safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
752 void *, ptr, long, fifth)
753static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
754{
755 return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
756}
757static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
758{
759 return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
760}
761#endif
Peter Maydelld40ecd62016-06-06 19:58:06 +0100762#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
763safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
764 size_t, len, unsigned, prio, const struct timespec *, timeout)
765safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
766 size_t, len, unsigned *, prio, const struct timespec *, timeout)
767#endif
Timothy E Baldwin50afd022016-05-12 18:47:47 +0100768
Paul Burton8289d112014-06-22 11:25:33 +0100769static inline int host_to_target_sock_type(int host_type)
770{
771 int target_type;
772
773 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
774 case SOCK_DGRAM:
775 target_type = TARGET_SOCK_DGRAM;
776 break;
777 case SOCK_STREAM:
778 target_type = TARGET_SOCK_STREAM;
779 break;
780 default:
781 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
782 break;
783 }
784
785#if defined(SOCK_CLOEXEC)
786 if (host_type & SOCK_CLOEXEC) {
787 target_type |= TARGET_SOCK_CLOEXEC;
788 }
789#endif
790
791#if defined(SOCK_NONBLOCK)
792 if (host_type & SOCK_NONBLOCK) {
793 target_type |= TARGET_SOCK_NONBLOCK;
794 }
795#endif
796
797 return target_type;
798}
799
blueswir1992f48a2007-10-14 16:27:31 +0000800static abi_ulong target_brk;
801static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000802static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000803
blueswir1992f48a2007-10-14 16:27:31 +0000804void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000805{
blueswir14c1de732007-07-07 20:45:44 +0000806 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000807 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000808}
809
vincent4d1de872011-06-14 21:56:33 +0000810//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
811#define DEBUGF_BRK(message, args...)
812
ths0da46a62007-10-20 20:23:07 +0000813/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000814abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000815{
blueswir1992f48a2007-10-14 16:27:31 +0000816 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000817 int new_alloc_size;
818
Paul Brook3a0c6c42012-02-09 19:04:27 +0000819 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000820
vincent4d1de872011-06-14 21:56:33 +0000821 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000822 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000823 return target_brk;
824 }
825 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000826 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
827 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000828 return target_brk;
829 }
bellard31e31b82003-02-18 22:55:36 +0000830
vincent4d1de872011-06-14 21:56:33 +0000831 /* If the new brk is less than the highest page reserved to the
832 * target heap allocation, set it and we're almost done... */
833 if (new_brk <= brk_page) {
834 /* Heap contents are initialized to zero, as for anonymous
835 * mapped pages. */
836 if (new_brk > target_brk) {
837 memset(g2h(target_brk), 0, new_brk - target_brk);
838 }
bellard31e31b82003-02-18 22:55:36 +0000839 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000840 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000841 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000842 }
843
Peter Maydell00faf082011-04-18 16:34:24 +0100844 /* We need to allocate more memory after the brk... Note that
845 * we don't use MAP_FIXED because that will map over the top of
846 * any existing mapping (like the one with the host libc or qemu
847 * itself); instead we treat "mapped but at wrong address" as
848 * a failure and unmap again.
849 */
vincent4d1de872011-06-14 21:56:33 +0000850 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000851 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000852 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100853 MAP_ANON|MAP_PRIVATE, 0, 0));
854
855 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200856 /* Heap contents are initialized to zero, as for anonymous
857 * mapped pages. Technically the new pages are already
858 * initialized to zero since they *are* anonymous mapped
859 * pages, however we have to take care with the contents that
860 * come from the remaining part of the previous page: it may
861 * contains garbage data due to a previous heap usage (grown
862 * then shrunken). */
863 memset(g2h(target_brk), 0, brk_page - target_brk);
864
Peter Maydell00faf082011-04-18 16:34:24 +0100865 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000866 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000867 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
868 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100869 return target_brk;
870 } else if (mapped_addr != -1) {
871 /* Mapped but at wrong address, meaning there wasn't actually
872 * enough space for this brk.
873 */
874 target_munmap(mapped_addr, new_alloc_size);
875 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000876 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000877 }
878 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000879 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100880 }
balrog7ab240a2008-04-26 12:17:34 +0000881
Richard Henderson7dd46c02010-05-03 10:07:49 -0700882#if defined(TARGET_ALPHA)
883 /* We (partially) emulate OSF/1 on Alpha, which requires we
884 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100885 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700886#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100887 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000888 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000889}
890
ths26edcf42007-12-09 02:25:24 +0000891static inline abi_long copy_from_user_fdset(fd_set *fds,
892 abi_ulong target_fds_addr,
893 int n)
bellard31e31b82003-02-18 22:55:36 +0000894{
ths26edcf42007-12-09 02:25:24 +0000895 int i, nw, j, k;
896 abi_ulong b, *target_fds;
897
898 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
899 if (!(target_fds = lock_user(VERIFY_READ,
900 target_fds_addr,
901 sizeof(abi_ulong) * nw,
902 1)))
903 return -TARGET_EFAULT;
904
905 FD_ZERO(fds);
906 k = 0;
907 for (i = 0; i < nw; i++) {
908 /* grab the abi_ulong */
909 __get_user(b, &target_fds[i]);
910 for (j = 0; j < TARGET_ABI_BITS; j++) {
911 /* check the bit inside the abi_ulong */
912 if ((b >> j) & 1)
913 FD_SET(k, fds);
914 k++;
bellard31e31b82003-02-18 22:55:36 +0000915 }
bellard31e31b82003-02-18 22:55:36 +0000916 }
ths26edcf42007-12-09 02:25:24 +0000917
918 unlock_user(target_fds, target_fds_addr, 0);
919
920 return 0;
bellard31e31b82003-02-18 22:55:36 +0000921}
922
Mike Frysinger055e0902011-06-03 17:01:49 -0400923static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
924 abi_ulong target_fds_addr,
925 int n)
926{
927 if (target_fds_addr) {
928 if (copy_from_user_fdset(fds, target_fds_addr, n))
929 return -TARGET_EFAULT;
930 *fds_ptr = fds;
931 } else {
932 *fds_ptr = NULL;
933 }
934 return 0;
935}
936
ths26edcf42007-12-09 02:25:24 +0000937static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
938 const fd_set *fds,
939 int n)
bellard31e31b82003-02-18 22:55:36 +0000940{
bellard31e31b82003-02-18 22:55:36 +0000941 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000942 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000943 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000944
ths26edcf42007-12-09 02:25:24 +0000945 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
946 if (!(target_fds = lock_user(VERIFY_WRITE,
947 target_fds_addr,
948 sizeof(abi_ulong) * nw,
949 0)))
950 return -TARGET_EFAULT;
951
952 k = 0;
953 for (i = 0; i < nw; i++) {
954 v = 0;
955 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000956 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000957 k++;
bellard31e31b82003-02-18 22:55:36 +0000958 }
ths26edcf42007-12-09 02:25:24 +0000959 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000960 }
ths26edcf42007-12-09 02:25:24 +0000961
962 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
963
964 return 0;
bellard31e31b82003-02-18 22:55:36 +0000965}
966
bellardc596ed12003-07-13 17:32:31 +0000967#if defined(__alpha__)
968#define HOST_HZ 1024
969#else
970#define HOST_HZ 100
971#endif
972
blueswir1992f48a2007-10-14 16:27:31 +0000973static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000974{
975#if HOST_HZ == TARGET_HZ
976 return ticks;
977#else
978 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
979#endif
980}
981
bellard579a97f2007-11-11 14:26:47 +0000982static inline abi_long host_to_target_rusage(abi_ulong target_addr,
983 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000984{
pbrook53a59602006-03-25 19:31:22 +0000985 struct target_rusage *target_rusage;
986
bellard579a97f2007-11-11 14:26:47 +0000987 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
988 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200989 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
990 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
991 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
992 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
993 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
994 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
995 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
996 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
997 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
998 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
999 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
1000 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
1001 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
1002 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
1003 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
1004 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
1005 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
1006 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +00001007 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001008
1009 return 0;
bellardb4091862003-05-16 15:39:34 +00001010}
1011
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001012static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001013{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001014 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001015 rlim_t result;
1016
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001017 target_rlim_swap = tswapal(target_rlim);
1018 if (target_rlim_swap == TARGET_RLIM_INFINITY)
1019 return RLIM_INFINITY;
1020
1021 result = target_rlim_swap;
1022 if (target_rlim_swap != (rlim_t)result)
1023 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001024
1025 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001026}
1027
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001028static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001029{
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001030 abi_ulong target_rlim_swap;
1031 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001032
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001033 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001034 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001035 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001036 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001037 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +03001038
1039 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09001040}
1041
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03001042static inline int target_to_host_resource(int code)
1043{
1044 switch (code) {
1045 case TARGET_RLIMIT_AS:
1046 return RLIMIT_AS;
1047 case TARGET_RLIMIT_CORE:
1048 return RLIMIT_CORE;
1049 case TARGET_RLIMIT_CPU:
1050 return RLIMIT_CPU;
1051 case TARGET_RLIMIT_DATA:
1052 return RLIMIT_DATA;
1053 case TARGET_RLIMIT_FSIZE:
1054 return RLIMIT_FSIZE;
1055 case TARGET_RLIMIT_LOCKS:
1056 return RLIMIT_LOCKS;
1057 case TARGET_RLIMIT_MEMLOCK:
1058 return RLIMIT_MEMLOCK;
1059 case TARGET_RLIMIT_MSGQUEUE:
1060 return RLIMIT_MSGQUEUE;
1061 case TARGET_RLIMIT_NICE:
1062 return RLIMIT_NICE;
1063 case TARGET_RLIMIT_NOFILE:
1064 return RLIMIT_NOFILE;
1065 case TARGET_RLIMIT_NPROC:
1066 return RLIMIT_NPROC;
1067 case TARGET_RLIMIT_RSS:
1068 return RLIMIT_RSS;
1069 case TARGET_RLIMIT_RTPRIO:
1070 return RLIMIT_RTPRIO;
1071 case TARGET_RLIMIT_SIGPENDING:
1072 return RLIMIT_SIGPENDING;
1073 case TARGET_RLIMIT_STACK:
1074 return RLIMIT_STACK;
1075 default:
1076 return code;
1077 }
1078}
1079
ths788f5ec2007-12-09 02:37:05 +00001080static inline abi_long copy_from_user_timeval(struct timeval *tv,
1081 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001082{
pbrook53a59602006-03-25 19:31:22 +00001083 struct target_timeval *target_tv;
1084
ths788f5ec2007-12-09 02:37:05 +00001085 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +00001086 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001087
1088 __get_user(tv->tv_sec, &target_tv->tv_sec);
1089 __get_user(tv->tv_usec, &target_tv->tv_usec);
1090
1091 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001092
1093 return 0;
bellard31e31b82003-02-18 22:55:36 +00001094}
1095
ths788f5ec2007-12-09 02:37:05 +00001096static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
1097 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +00001098{
pbrook53a59602006-03-25 19:31:22 +00001099 struct target_timeval *target_tv;
1100
ths788f5ec2007-12-09 02:37:05 +00001101 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +00001102 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +00001103
1104 __put_user(tv->tv_sec, &target_tv->tv_sec);
1105 __put_user(tv->tv_usec, &target_tv->tv_usec);
1106
1107 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001108
1109 return 0;
bellard31e31b82003-02-18 22:55:36 +00001110}
1111
Paul Burtonef4467e2014-06-22 11:25:40 +01001112static inline abi_long copy_from_user_timezone(struct timezone *tz,
1113 abi_ulong target_tz_addr)
1114{
1115 struct target_timezone *target_tz;
1116
1117 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
1118 return -TARGET_EFAULT;
1119 }
1120
1121 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
1122 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
1123
1124 unlock_user_struct(target_tz, target_tz_addr, 0);
1125
1126 return 0;
1127}
1128
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001129#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
1130#include <mqueue.h>
1131
aurel3224e10032009-04-15 16:11:43 +00001132static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
1133 abi_ulong target_mq_attr_addr)
1134{
1135 struct target_mq_attr *target_mq_attr;
1136
1137 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
1138 target_mq_attr_addr, 1))
1139 return -TARGET_EFAULT;
1140
1141 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
1142 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1143 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1144 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1145
1146 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
1147
1148 return 0;
1149}
1150
1151static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
1152 const struct mq_attr *attr)
1153{
1154 struct target_mq_attr *target_mq_attr;
1155
1156 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
1157 target_mq_attr_addr, 0))
1158 return -TARGET_EFAULT;
1159
1160 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
1161 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
1162 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
1163 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
1164
1165 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
1166
1167 return 0;
1168}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001169#endif
bellard31e31b82003-02-18 22:55:36 +00001170
Mike Frysinger055e0902011-06-03 17:01:49 -04001171#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001172/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001173static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001174 abi_ulong rfd_addr, abi_ulong wfd_addr,
1175 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001176{
1177 fd_set rfds, wfds, efds;
1178 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
Peter Maydell6df9d382016-05-12 18:47:51 +01001179 struct timeval tv;
1180 struct timespec ts, *ts_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001181 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001182
Mike Frysinger055e0902011-06-03 17:01:49 -04001183 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1184 if (ret) {
1185 return ret;
pbrook53a59602006-03-25 19:31:22 +00001186 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001187 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1188 if (ret) {
1189 return ret;
pbrook53a59602006-03-25 19:31:22 +00001190 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001191 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1192 if (ret) {
1193 return ret;
pbrook53a59602006-03-25 19:31:22 +00001194 }
ths3b46e622007-09-17 08:09:54 +00001195
ths26edcf42007-12-09 02:25:24 +00001196 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001197 if (copy_from_user_timeval(&tv, target_tv_addr))
1198 return -TARGET_EFAULT;
Peter Maydell6df9d382016-05-12 18:47:51 +01001199 ts.tv_sec = tv.tv_sec;
1200 ts.tv_nsec = tv.tv_usec * 1000;
1201 ts_ptr = &ts;
bellard31e31b82003-02-18 22:55:36 +00001202 } else {
Peter Maydell6df9d382016-05-12 18:47:51 +01001203 ts_ptr = NULL;
bellard31e31b82003-02-18 22:55:36 +00001204 }
ths26edcf42007-12-09 02:25:24 +00001205
Peter Maydell6df9d382016-05-12 18:47:51 +01001206 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
1207 ts_ptr, NULL));
pbrook53a59602006-03-25 19:31:22 +00001208
ths26edcf42007-12-09 02:25:24 +00001209 if (!is_error(ret)) {
1210 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1211 return -TARGET_EFAULT;
1212 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1213 return -TARGET_EFAULT;
1214 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1215 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001216
Peter Maydell6df9d382016-05-12 18:47:51 +01001217 if (target_tv_addr) {
1218 tv.tv_sec = ts.tv_sec;
1219 tv.tv_usec = ts.tv_nsec / 1000;
1220 if (copy_to_user_timeval(target_tv_addr, &tv)) {
1221 return -TARGET_EFAULT;
1222 }
1223 }
bellard31e31b82003-02-18 22:55:36 +00001224 }
bellard579a97f2007-11-11 14:26:47 +00001225
bellard31e31b82003-02-18 22:55:36 +00001226 return ret;
1227}
Mike Frysinger055e0902011-06-03 17:01:49 -04001228#endif
bellard31e31b82003-02-18 22:55:36 +00001229
Riku Voipio099d6b02009-05-05 12:10:04 +03001230static abi_long do_pipe2(int host_pipe[], int flags)
1231{
1232#ifdef CONFIG_PIPE2
1233 return pipe2(host_pipe, flags);
1234#else
1235 return -ENOSYS;
1236#endif
1237}
1238
Richard Hendersonfb41a662010-05-03 10:07:52 -07001239static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1240 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001241{
1242 int host_pipe[2];
1243 abi_long ret;
1244 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1245
1246 if (is_error(ret))
1247 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001248
1249 /* Several targets have special calling conventions for the original
1250 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1251 if (!is_pipe2) {
1252#if defined(TARGET_ALPHA)
1253 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1254 return host_pipe[0];
1255#elif defined(TARGET_MIPS)
1256 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1257 return host_pipe[0];
1258#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001259 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001260 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001261#elif defined(TARGET_SPARC)
1262 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1263 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001264#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001265 }
1266
Riku Voipio099d6b02009-05-05 12:10:04 +03001267 if (put_user_s32(host_pipe[0], pipedes)
1268 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1269 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001270 return get_errno(ret);
1271}
1272
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001273static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1274 abi_ulong target_addr,
1275 socklen_t len)
1276{
1277 struct target_ip_mreqn *target_smreqn;
1278
1279 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1280 if (!target_smreqn)
1281 return -TARGET_EFAULT;
1282 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1283 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1284 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001285 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001286 unlock_user(target_smreqn, target_addr, 0);
1287
1288 return 0;
1289}
1290
Laurent Vivier7b36f782015-10-28 21:40:44 +01001291static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
bellard579a97f2007-11-11 14:26:47 +00001292 abi_ulong target_addr,
1293 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001294{
aurel32607175e2009-04-15 16:11:59 +00001295 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1296 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001297 struct target_sockaddr *target_saddr;
1298
Laurent Vivier7b36f782015-10-28 21:40:44 +01001299 if (fd_trans_target_to_host_addr(fd)) {
1300 return fd_trans_target_to_host_addr(fd)(addr, target_addr, len);
1301 }
1302
bellard579a97f2007-11-11 14:26:47 +00001303 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1304 if (!target_saddr)
1305 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001306
1307 sa_family = tswap16(target_saddr->sa_family);
1308
1309 /* Oops. The caller might send a incomplete sun_path; sun_path
1310 * must be terminated by \0 (see the manual page), but
1311 * unfortunately it is quite common to specify sockaddr_un
1312 * length as "strlen(x->sun_path)" while it should be
1313 * "strlen(...) + 1". We'll fix that here if needed.
1314 * Linux kernel has a similar feature.
1315 */
1316
1317 if (sa_family == AF_UNIX) {
1318 if (len < unix_maxlen && len > 0) {
1319 char *cp = (char*)target_saddr;
1320
1321 if ( cp[len-1] && !cp[len] )
1322 len++;
1323 }
1324 if (len > unix_maxlen)
1325 len = unix_maxlen;
1326 }
1327
pbrook53a59602006-03-25 19:31:22 +00001328 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001329 addr->sa_family = sa_family;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001330 if (sa_family == AF_NETLINK) {
1331 struct sockaddr_nl *nladdr;
1332
1333 nladdr = (struct sockaddr_nl *)addr;
1334 nladdr->nl_pid = tswap32(nladdr->nl_pid);
1335 nladdr->nl_groups = tswap32(nladdr->nl_groups);
1336 } else if (sa_family == AF_PACKET) {
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001337 struct target_sockaddr_ll *lladdr;
1338
1339 lladdr = (struct target_sockaddr_ll *)addr;
1340 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1341 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1342 }
pbrook53a59602006-03-25 19:31:22 +00001343 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001344
1345 return 0;
bellard7854b052003-03-29 17:22:23 +00001346}
1347
bellard579a97f2007-11-11 14:26:47 +00001348static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1349 struct sockaddr *addr,
1350 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001351{
pbrook53a59602006-03-25 19:31:22 +00001352 struct target_sockaddr *target_saddr;
1353
bellard579a97f2007-11-11 14:26:47 +00001354 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1355 if (!target_saddr)
1356 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001357 memcpy(target_saddr, addr, len);
1358 target_saddr->sa_family = tswap16(addr->sa_family);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001359 if (addr->sa_family == AF_NETLINK) {
1360 struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
1361 target_nl->nl_pid = tswap32(target_nl->nl_pid);
1362 target_nl->nl_groups = tswap32(target_nl->nl_groups);
1363 }
pbrook53a59602006-03-25 19:31:22 +00001364 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001365
1366 return 0;
bellard7854b052003-03-29 17:22:23 +00001367}
1368
bellard5a4a8982007-11-11 17:39:18 +00001369static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1370 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001371{
1372 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001373 abi_long msg_controllen;
1374 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001375 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001376 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001377
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001378 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001379 if (msg_controllen < sizeof (struct target_cmsghdr))
1380 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001381 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001382 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001383 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001384 if (!target_cmsg)
1385 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001386
1387 while (cmsg && target_cmsg) {
1388 void *data = CMSG_DATA(cmsg);
1389 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1390
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001391 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001392 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1393
1394 space += CMSG_SPACE(len);
1395 if (space > msgh->msg_controllen) {
1396 space -= CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001397 /* This is a QEMU bug, since we allocated the payload
1398 * area ourselves (unlike overflow in host-to-target
1399 * conversion, which is just the guest giving us a buffer
1400 * that's too small). It can't happen for the payload types
1401 * we currently support; if it becomes an issue in future
1402 * we would need to improve our allocation strategy to
1403 * something more intelligent than "twice the size of the
1404 * target buffer we're reading from".
1405 */
bellard31febb72005-12-18 20:03:27 +00001406 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001407 break;
1408 }
1409
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001410 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1411 cmsg->cmsg_level = SOL_SOCKET;
1412 } else {
1413 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1414 }
bellard7854b052003-03-29 17:22:23 +00001415 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1416 cmsg->cmsg_len = CMSG_LEN(len);
1417
Alex Suykov30b8b682014-12-23 07:52:58 +02001418 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001419 int *fd = (int *)data;
1420 int *target_fd = (int *)target_data;
1421 int i, numfds = len / sizeof(int);
1422
Peter Maydell876e23c2015-05-26 19:46:32 +01001423 for (i = 0; i < numfds; i++) {
1424 __get_user(fd[i], target_fd + i);
1425 }
Alex Suykov30b8b682014-12-23 07:52:58 +02001426 } else if (cmsg->cmsg_level == SOL_SOCKET
1427 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1428 struct ucred *cred = (struct ucred *)data;
1429 struct target_ucred *target_cred =
1430 (struct target_ucred *)target_data;
1431
Peter Maydell876e23c2015-05-26 19:46:32 +01001432 __get_user(cred->pid, &target_cred->pid);
1433 __get_user(cred->uid, &target_cred->uid);
1434 __get_user(cred->gid, &target_cred->gid);
Alex Suykov30b8b682014-12-23 07:52:58 +02001435 } else {
1436 gemu_log("Unsupported ancillary data: %d/%d\n",
1437 cmsg->cmsg_level, cmsg->cmsg_type);
1438 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001439 }
1440
1441 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001442 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1443 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001444 }
bellard5a4a8982007-11-11 17:39:18 +00001445 unlock_user(target_cmsg, target_cmsg_addr, 0);
1446 the_end:
bellard7854b052003-03-29 17:22:23 +00001447 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001448 return 0;
bellard7854b052003-03-29 17:22:23 +00001449}
1450
bellard5a4a8982007-11-11 17:39:18 +00001451static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1452 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001453{
1454 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001455 abi_long msg_controllen;
1456 abi_ulong target_cmsg_addr;
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001457 struct target_cmsghdr *target_cmsg, *target_cmsg_start;
bellard7854b052003-03-29 17:22:23 +00001458 socklen_t space = 0;
1459
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001460 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001461 if (msg_controllen < sizeof (struct target_cmsghdr))
1462 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001463 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001464 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001465 target_cmsg_start = target_cmsg;
bellard5a4a8982007-11-11 17:39:18 +00001466 if (!target_cmsg)
1467 return -TARGET_EFAULT;
1468
bellard7854b052003-03-29 17:22:23 +00001469 while (cmsg && target_cmsg) {
1470 void *data = CMSG_DATA(cmsg);
1471 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1472
1473 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
Peter Maydellc2aeb252015-05-26 19:46:31 +01001474 int tgt_len, tgt_space;
bellard7854b052003-03-29 17:22:23 +00001475
Peter Maydellc2aeb252015-05-26 19:46:31 +01001476 /* We never copy a half-header but may copy half-data;
1477 * this is Linux's behaviour in put_cmsg(). Note that
1478 * truncation here is a guest problem (which we report
1479 * to the guest via the CTRUNC bit), unlike truncation
1480 * in target_to_host_cmsg, which is a QEMU bug.
1481 */
1482 if (msg_controllen < sizeof(struct cmsghdr)) {
1483 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
bellard7854b052003-03-29 17:22:23 +00001484 break;
1485 }
1486
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001487 if (cmsg->cmsg_level == SOL_SOCKET) {
1488 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1489 } else {
1490 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1491 }
bellard7854b052003-03-29 17:22:23 +00001492 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
bellard7854b052003-03-29 17:22:23 +00001493
Peter Maydellc2aeb252015-05-26 19:46:31 +01001494 tgt_len = TARGET_CMSG_LEN(len);
1495
1496 /* Payload types which need a different size of payload on
1497 * the target must adjust tgt_len here.
1498 */
1499 switch (cmsg->cmsg_level) {
1500 case SOL_SOCKET:
1501 switch (cmsg->cmsg_type) {
1502 case SO_TIMESTAMP:
1503 tgt_len = sizeof(struct target_timeval);
1504 break;
1505 default:
1506 break;
1507 }
1508 default:
1509 break;
1510 }
1511
1512 if (msg_controllen < tgt_len) {
1513 target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
1514 tgt_len = msg_controllen;
1515 }
1516
1517 /* We must now copy-and-convert len bytes of payload
1518 * into tgt_len bytes of destination space. Bear in mind
1519 * that in both source and destination we may be dealing
1520 * with a truncated value!
1521 */
Huw Davies52b65492014-04-17 14:02:47 +01001522 switch (cmsg->cmsg_level) {
1523 case SOL_SOCKET:
1524 switch (cmsg->cmsg_type) {
1525 case SCM_RIGHTS:
1526 {
1527 int *fd = (int *)data;
1528 int *target_fd = (int *)target_data;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001529 int i, numfds = tgt_len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001530
Peter Maydell876e23c2015-05-26 19:46:32 +01001531 for (i = 0; i < numfds; i++) {
1532 __put_user(fd[i], target_fd + i);
1533 }
Huw Davies52b65492014-04-17 14:02:47 +01001534 break;
1535 }
1536 case SO_TIMESTAMP:
1537 {
1538 struct timeval *tv = (struct timeval *)data;
1539 struct target_timeval *target_tv =
1540 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001541
Peter Maydellc2aeb252015-05-26 19:46:31 +01001542 if (len != sizeof(struct timeval) ||
1543 tgt_len != sizeof(struct target_timeval)) {
Huw Davies52b65492014-04-17 14:02:47 +01001544 goto unimplemented;
Peter Maydellc2aeb252015-05-26 19:46:31 +01001545 }
Huw Davies52b65492014-04-17 14:02:47 +01001546
1547 /* copy struct timeval to target */
Peter Maydell876e23c2015-05-26 19:46:32 +01001548 __put_user(tv->tv_sec, &target_tv->tv_sec);
1549 __put_user(tv->tv_usec, &target_tv->tv_usec);
Huw Davies52b65492014-04-17 14:02:47 +01001550 break;
1551 }
Huw Davies4bc29752014-04-17 14:02:48 +01001552 case SCM_CREDENTIALS:
1553 {
1554 struct ucred *cred = (struct ucred *)data;
1555 struct target_ucred *target_cred =
1556 (struct target_ucred *)target_data;
1557
1558 __put_user(cred->pid, &target_cred->pid);
1559 __put_user(cred->uid, &target_cred->uid);
1560 __put_user(cred->gid, &target_cred->gid);
1561 break;
1562 }
Huw Davies52b65492014-04-17 14:02:47 +01001563 default:
1564 goto unimplemented;
1565 }
1566 break;
1567
1568 default:
1569 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001570 gemu_log("Unsupported ancillary data: %d/%d\n",
1571 cmsg->cmsg_level, cmsg->cmsg_type);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001572 memcpy(target_data, data, MIN(len, tgt_len));
1573 if (tgt_len > len) {
1574 memset(target_data + len, 0, tgt_len - len);
1575 }
bellard7854b052003-03-29 17:22:23 +00001576 }
1577
Peter Maydellc2aeb252015-05-26 19:46:31 +01001578 target_cmsg->cmsg_len = tswapal(tgt_len);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001579 tgt_space = TARGET_CMSG_SPACE(len);
Peter Maydellc2aeb252015-05-26 19:46:31 +01001580 if (msg_controllen < tgt_space) {
1581 tgt_space = msg_controllen;
1582 }
1583 msg_controllen -= tgt_space;
1584 space += tgt_space;
bellard7854b052003-03-29 17:22:23 +00001585 cmsg = CMSG_NXTHDR(msgh, cmsg);
Jonathan Neuschäferee104582015-09-03 07:27:26 +02001586 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
1587 target_cmsg_start);
bellard7854b052003-03-29 17:22:23 +00001588 }
bellard5a4a8982007-11-11 17:39:18 +00001589 unlock_user(target_cmsg, target_cmsg_addr, space);
1590 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001591 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001592 return 0;
bellard7854b052003-03-29 17:22:23 +00001593}
1594
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001595static void tswap_nlmsghdr(struct nlmsghdr *nlh)
1596{
1597 nlh->nlmsg_len = tswap32(nlh->nlmsg_len);
1598 nlh->nlmsg_type = tswap16(nlh->nlmsg_type);
1599 nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags);
1600 nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq);
1601 nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid);
1602}
1603
1604static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh,
1605 size_t len,
1606 abi_long (*host_to_target_nlmsg)
1607 (struct nlmsghdr *))
1608{
1609 uint32_t nlmsg_len;
1610 abi_long ret;
1611
1612 while (len > sizeof(struct nlmsghdr)) {
1613
1614 nlmsg_len = nlh->nlmsg_len;
1615 if (nlmsg_len < sizeof(struct nlmsghdr) ||
1616 nlmsg_len > len) {
1617 break;
1618 }
1619
1620 switch (nlh->nlmsg_type) {
1621 case NLMSG_DONE:
1622 tswap_nlmsghdr(nlh);
1623 return 0;
1624 case NLMSG_NOOP:
1625 break;
1626 case NLMSG_ERROR:
1627 {
1628 struct nlmsgerr *e = NLMSG_DATA(nlh);
1629 e->error = tswap32(e->error);
1630 tswap_nlmsghdr(&e->msg);
1631 tswap_nlmsghdr(nlh);
1632 return 0;
1633 }
1634 default:
1635 ret = host_to_target_nlmsg(nlh);
1636 if (ret < 0) {
1637 tswap_nlmsghdr(nlh);
1638 return ret;
1639 }
1640 break;
1641 }
1642 tswap_nlmsghdr(nlh);
1643 len -= NLMSG_ALIGN(nlmsg_len);
1644 nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len));
1645 }
1646 return 0;
1647}
1648
1649static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
1650 size_t len,
1651 abi_long (*target_to_host_nlmsg)
1652 (struct nlmsghdr *))
1653{
1654 int ret;
1655
1656 while (len > sizeof(struct nlmsghdr)) {
1657 if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) ||
1658 tswap32(nlh->nlmsg_len) > len) {
1659 break;
1660 }
1661 tswap_nlmsghdr(nlh);
1662 switch (nlh->nlmsg_type) {
1663 case NLMSG_DONE:
1664 return 0;
1665 case NLMSG_NOOP:
1666 break;
1667 case NLMSG_ERROR:
1668 {
1669 struct nlmsgerr *e = NLMSG_DATA(nlh);
1670 e->error = tswap32(e->error);
1671 tswap_nlmsghdr(&e->msg);
1672 }
1673 default:
1674 ret = target_to_host_nlmsg(nlh);
1675 if (ret < 0) {
1676 return ret;
1677 }
1678 }
1679 len -= NLMSG_ALIGN(nlh->nlmsg_len);
1680 nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1681 }
1682 return 0;
1683}
1684
Laurent Vivier575b22b2016-06-02 22:14:15 +02001685#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02001686static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr,
1687 size_t len,
1688 abi_long (*host_to_target_rtattr)
1689 (struct rtattr *))
1690{
1691 unsigned short rta_len;
1692 abi_long ret;
1693
1694 while (len > sizeof(struct rtattr)) {
1695 rta_len = rtattr->rta_len;
1696 if (rta_len < sizeof(struct rtattr) ||
1697 rta_len > len) {
1698 break;
1699 }
1700 ret = host_to_target_rtattr(rtattr);
1701 rtattr->rta_len = tswap16(rtattr->rta_len);
1702 rtattr->rta_type = tswap16(rtattr->rta_type);
1703 if (ret < 0) {
1704 return ret;
1705 }
1706 len -= RTA_ALIGN(rta_len);
1707 rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len));
1708 }
1709 return 0;
1710}
1711
1712static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
1713{
1714 uint32_t *u32;
1715 struct rtnl_link_stats *st;
1716 struct rtnl_link_stats64 *st64;
1717 struct rtnl_link_ifmap *map;
1718
1719 switch (rtattr->rta_type) {
1720 /* binary stream */
1721 case IFLA_ADDRESS:
1722 case IFLA_BROADCAST:
1723 /* string */
1724 case IFLA_IFNAME:
1725 case IFLA_QDISC:
1726 break;
1727 /* uin8_t */
1728 case IFLA_OPERSTATE:
1729 case IFLA_LINKMODE:
1730 case IFLA_CARRIER:
1731 case IFLA_PROTO_DOWN:
1732 break;
1733 /* uint32_t */
1734 case IFLA_MTU:
1735 case IFLA_LINK:
1736 case IFLA_WEIGHT:
1737 case IFLA_TXQLEN:
1738 case IFLA_CARRIER_CHANGES:
1739 case IFLA_NUM_RX_QUEUES:
1740 case IFLA_NUM_TX_QUEUES:
1741 case IFLA_PROMISCUITY:
1742 case IFLA_EXT_MASK:
1743 case IFLA_LINK_NETNSID:
1744 case IFLA_GROUP:
1745 case IFLA_MASTER:
1746 case IFLA_NUM_VF:
1747 u32 = RTA_DATA(rtattr);
1748 *u32 = tswap32(*u32);
1749 break;
1750 /* struct rtnl_link_stats */
1751 case IFLA_STATS:
1752 st = RTA_DATA(rtattr);
1753 st->rx_packets = tswap32(st->rx_packets);
1754 st->tx_packets = tswap32(st->tx_packets);
1755 st->rx_bytes = tswap32(st->rx_bytes);
1756 st->tx_bytes = tswap32(st->tx_bytes);
1757 st->rx_errors = tswap32(st->rx_errors);
1758 st->tx_errors = tswap32(st->tx_errors);
1759 st->rx_dropped = tswap32(st->rx_dropped);
1760 st->tx_dropped = tswap32(st->tx_dropped);
1761 st->multicast = tswap32(st->multicast);
1762 st->collisions = tswap32(st->collisions);
1763
1764 /* detailed rx_errors: */
1765 st->rx_length_errors = tswap32(st->rx_length_errors);
1766 st->rx_over_errors = tswap32(st->rx_over_errors);
1767 st->rx_crc_errors = tswap32(st->rx_crc_errors);
1768 st->rx_frame_errors = tswap32(st->rx_frame_errors);
1769 st->rx_fifo_errors = tswap32(st->rx_fifo_errors);
1770 st->rx_missed_errors = tswap32(st->rx_missed_errors);
1771
1772 /* detailed tx_errors */
1773 st->tx_aborted_errors = tswap32(st->tx_aborted_errors);
1774 st->tx_carrier_errors = tswap32(st->tx_carrier_errors);
1775 st->tx_fifo_errors = tswap32(st->tx_fifo_errors);
1776 st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors);
1777 st->tx_window_errors = tswap32(st->tx_window_errors);
1778
1779 /* for cslip etc */
1780 st->rx_compressed = tswap32(st->rx_compressed);
1781 st->tx_compressed = tswap32(st->tx_compressed);
1782 break;
1783 /* struct rtnl_link_stats64 */
1784 case IFLA_STATS64:
1785 st64 = RTA_DATA(rtattr);
1786 st64->rx_packets = tswap64(st64->rx_packets);
1787 st64->tx_packets = tswap64(st64->tx_packets);
1788 st64->rx_bytes = tswap64(st64->rx_bytes);
1789 st64->tx_bytes = tswap64(st64->tx_bytes);
1790 st64->rx_errors = tswap64(st64->rx_errors);
1791 st64->tx_errors = tswap64(st64->tx_errors);
1792 st64->rx_dropped = tswap64(st64->rx_dropped);
1793 st64->tx_dropped = tswap64(st64->tx_dropped);
1794 st64->multicast = tswap64(st64->multicast);
1795 st64->collisions = tswap64(st64->collisions);
1796
1797 /* detailed rx_errors: */
1798 st64->rx_length_errors = tswap64(st64->rx_length_errors);
1799 st64->rx_over_errors = tswap64(st64->rx_over_errors);
1800 st64->rx_crc_errors = tswap64(st64->rx_crc_errors);
1801 st64->rx_frame_errors = tswap64(st64->rx_frame_errors);
1802 st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors);
1803 st64->rx_missed_errors = tswap64(st64->rx_missed_errors);
1804
1805 /* detailed tx_errors */
1806 st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors);
1807 st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors);
1808 st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors);
1809 st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors);
1810 st64->tx_window_errors = tswap64(st64->tx_window_errors);
1811
1812 /* for cslip etc */
1813 st64->rx_compressed = tswap64(st64->rx_compressed);
1814 st64->tx_compressed = tswap64(st64->tx_compressed);
1815 break;
1816 /* struct rtnl_link_ifmap */
1817 case IFLA_MAP:
1818 map = RTA_DATA(rtattr);
1819 map->mem_start = tswap64(map->mem_start);
1820 map->mem_end = tswap64(map->mem_end);
1821 map->base_addr = tswap64(map->base_addr);
1822 map->irq = tswap16(map->irq);
1823 break;
1824 /* nested */
1825 case IFLA_AF_SPEC:
1826 case IFLA_LINKINFO:
1827 /* FIXME: implement nested type */
1828 gemu_log("Unimplemented nested type %d\n", rtattr->rta_type);
1829 break;
1830 default:
1831 gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type);
1832 break;
1833 }
1834 return 0;
1835}
1836
1837static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
1838{
1839 uint32_t *u32;
1840 struct ifa_cacheinfo *ci;
1841
1842 switch (rtattr->rta_type) {
1843 /* binary: depends on family type */
1844 case IFA_ADDRESS:
1845 case IFA_LOCAL:
1846 break;
1847 /* string */
1848 case IFA_LABEL:
1849 break;
1850 /* u32 */
1851 case IFA_FLAGS:
1852 case IFA_BROADCAST:
1853 u32 = RTA_DATA(rtattr);
1854 *u32 = tswap32(*u32);
1855 break;
1856 /* struct ifa_cacheinfo */
1857 case IFA_CACHEINFO:
1858 ci = RTA_DATA(rtattr);
1859 ci->ifa_prefered = tswap32(ci->ifa_prefered);
1860 ci->ifa_valid = tswap32(ci->ifa_valid);
1861 ci->cstamp = tswap32(ci->cstamp);
1862 ci->tstamp = tswap32(ci->tstamp);
1863 break;
1864 default:
1865 gemu_log("Unknown host IFA type: %d\n", rtattr->rta_type);
1866 break;
1867 }
1868 return 0;
1869}
1870
1871static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
1872{
1873 uint32_t *u32;
1874 switch (rtattr->rta_type) {
1875 /* binary: depends on family type */
1876 case RTA_GATEWAY:
1877 case RTA_DST:
1878 case RTA_PREFSRC:
1879 break;
1880 /* u32 */
1881 case RTA_PRIORITY:
1882 case RTA_TABLE:
1883 case RTA_OIF:
1884 u32 = RTA_DATA(rtattr);
1885 *u32 = tswap32(*u32);
1886 break;
1887 default:
1888 gemu_log("Unknown host RTA type: %d\n", rtattr->rta_type);
1889 break;
1890 }
1891 return 0;
1892}
1893
1894static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
1895 uint32_t rtattr_len)
1896{
1897 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1898 host_to_target_data_link_rtattr);
1899}
1900
1901static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr,
1902 uint32_t rtattr_len)
1903{
1904 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1905 host_to_target_data_addr_rtattr);
1906}
1907
1908static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
1909 uint32_t rtattr_len)
1910{
1911 return host_to_target_for_each_rtattr(rtattr, rtattr_len,
1912 host_to_target_data_route_rtattr);
1913}
1914
1915static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
1916{
1917 uint32_t nlmsg_len;
1918 struct ifinfomsg *ifi;
1919 struct ifaddrmsg *ifa;
1920 struct rtmsg *rtm;
1921
1922 nlmsg_len = nlh->nlmsg_len;
1923 switch (nlh->nlmsg_type) {
1924 case RTM_NEWLINK:
1925 case RTM_DELLINK:
1926 case RTM_GETLINK:
1927 ifi = NLMSG_DATA(nlh);
1928 ifi->ifi_type = tswap16(ifi->ifi_type);
1929 ifi->ifi_index = tswap32(ifi->ifi_index);
1930 ifi->ifi_flags = tswap32(ifi->ifi_flags);
1931 ifi->ifi_change = tswap32(ifi->ifi_change);
1932 host_to_target_link_rtattr(IFLA_RTA(ifi),
1933 nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
1934 break;
1935 case RTM_NEWADDR:
1936 case RTM_DELADDR:
1937 case RTM_GETADDR:
1938 ifa = NLMSG_DATA(nlh);
1939 ifa->ifa_index = tswap32(ifa->ifa_index);
1940 host_to_target_addr_rtattr(IFA_RTA(ifa),
1941 nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
1942 break;
1943 case RTM_NEWROUTE:
1944 case RTM_DELROUTE:
1945 case RTM_GETROUTE:
1946 rtm = NLMSG_DATA(nlh);
1947 rtm->rtm_flags = tswap32(rtm->rtm_flags);
1948 host_to_target_route_rtattr(RTM_RTA(rtm),
1949 nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
1950 break;
1951 default:
1952 return -TARGET_EINVAL;
1953 }
1954 return 0;
1955}
1956
1957static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh,
1958 size_t len)
1959{
1960 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route);
1961}
1962
1963static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr,
1964 size_t len,
1965 abi_long (*target_to_host_rtattr)
1966 (struct rtattr *))
1967{
1968 abi_long ret;
1969
1970 while (len >= sizeof(struct rtattr)) {
1971 if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) ||
1972 tswap16(rtattr->rta_len) > len) {
1973 break;
1974 }
1975 rtattr->rta_len = tswap16(rtattr->rta_len);
1976 rtattr->rta_type = tswap16(rtattr->rta_type);
1977 ret = target_to_host_rtattr(rtattr);
1978 if (ret < 0) {
1979 return ret;
1980 }
1981 len -= RTA_ALIGN(rtattr->rta_len);
1982 rtattr = (struct rtattr *)(((char *)rtattr) +
1983 RTA_ALIGN(rtattr->rta_len));
1984 }
1985 return 0;
1986}
1987
1988static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr)
1989{
1990 switch (rtattr->rta_type) {
1991 default:
1992 gemu_log("Unknown target IFLA type: %d\n", rtattr->rta_type);
1993 break;
1994 }
1995 return 0;
1996}
1997
1998static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
1999{
2000 switch (rtattr->rta_type) {
2001 /* binary: depends on family type */
2002 case IFA_LOCAL:
2003 case IFA_ADDRESS:
2004 break;
2005 default:
2006 gemu_log("Unknown target IFA type: %d\n", rtattr->rta_type);
2007 break;
2008 }
2009 return 0;
2010}
2011
2012static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
2013{
2014 uint32_t *u32;
2015 switch (rtattr->rta_type) {
2016 /* binary: depends on family type */
2017 case RTA_DST:
2018 case RTA_SRC:
2019 case RTA_GATEWAY:
2020 break;
2021 /* u32 */
2022 case RTA_OIF:
2023 u32 = RTA_DATA(rtattr);
2024 *u32 = tswap32(*u32);
2025 break;
2026 default:
2027 gemu_log("Unknown target RTA type: %d\n", rtattr->rta_type);
2028 break;
2029 }
2030 return 0;
2031}
2032
2033static void target_to_host_link_rtattr(struct rtattr *rtattr,
2034 uint32_t rtattr_len)
2035{
2036 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2037 target_to_host_data_link_rtattr);
2038}
2039
2040static void target_to_host_addr_rtattr(struct rtattr *rtattr,
2041 uint32_t rtattr_len)
2042{
2043 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2044 target_to_host_data_addr_rtattr);
2045}
2046
2047static void target_to_host_route_rtattr(struct rtattr *rtattr,
2048 uint32_t rtattr_len)
2049{
2050 target_to_host_for_each_rtattr(rtattr, rtattr_len,
2051 target_to_host_data_route_rtattr);
2052}
2053
2054static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
2055{
2056 struct ifinfomsg *ifi;
2057 struct ifaddrmsg *ifa;
2058 struct rtmsg *rtm;
2059
2060 switch (nlh->nlmsg_type) {
2061 case RTM_GETLINK:
2062 break;
2063 case RTM_NEWLINK:
2064 case RTM_DELLINK:
2065 ifi = NLMSG_DATA(nlh);
2066 ifi->ifi_type = tswap16(ifi->ifi_type);
2067 ifi->ifi_index = tswap32(ifi->ifi_index);
2068 ifi->ifi_flags = tswap32(ifi->ifi_flags);
2069 ifi->ifi_change = tswap32(ifi->ifi_change);
2070 target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
2071 NLMSG_LENGTH(sizeof(*ifi)));
2072 break;
2073 case RTM_GETADDR:
2074 case RTM_NEWADDR:
2075 case RTM_DELADDR:
2076 ifa = NLMSG_DATA(nlh);
2077 ifa->ifa_index = tswap32(ifa->ifa_index);
2078 target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
2079 NLMSG_LENGTH(sizeof(*ifa)));
2080 break;
2081 case RTM_GETROUTE:
2082 break;
2083 case RTM_NEWROUTE:
2084 case RTM_DELROUTE:
2085 rtm = NLMSG_DATA(nlh);
2086 rtm->rtm_flags = tswap32(rtm->rtm_flags);
2087 target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
2088 NLMSG_LENGTH(sizeof(*rtm)));
2089 break;
2090 default:
2091 return -TARGET_EOPNOTSUPP;
2092 }
2093 return 0;
2094}
2095
2096static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len)
2097{
2098 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route);
2099}
Laurent Vivier575b22b2016-06-02 22:14:15 +02002100#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002101
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002102static abi_long host_to_target_data_audit(struct nlmsghdr *nlh)
2103{
2104 switch (nlh->nlmsg_type) {
2105 default:
2106 gemu_log("Unknown host audit message type %d\n",
2107 nlh->nlmsg_type);
2108 return -TARGET_EINVAL;
2109 }
2110 return 0;
2111}
2112
2113static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh,
2114 size_t len)
2115{
2116 return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit);
2117}
2118
2119static abi_long target_to_host_data_audit(struct nlmsghdr *nlh)
2120{
2121 switch (nlh->nlmsg_type) {
2122 case AUDIT_USER:
2123 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
2124 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
2125 break;
2126 default:
2127 gemu_log("Unknown target audit message type %d\n",
2128 nlh->nlmsg_type);
2129 return -TARGET_EINVAL;
2130 }
2131
2132 return 0;
2133}
2134
2135static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len)
2136{
2137 return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit);
2138}
2139
ths0da46a62007-10-20 20:23:07 +00002140/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002141static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002142 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00002143{
blueswir1992f48a2007-10-14 16:27:31 +00002144 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00002145 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002146 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002147 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00002148
bellard8853f862004-02-22 14:57:26 +00002149 switch(level) {
2150 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00002151 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00002152 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00002153 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00002154
bellard2f619692007-11-16 10:46:05 +00002155 if (get_user_u32(val, optval_addr))
2156 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002157 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2158 break;
2159 case SOL_IP:
2160 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00002161 case IP_TOS:
2162 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00002163 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00002164 case IP_ROUTER_ALERT:
2165 case IP_RECVOPTS:
2166 case IP_RETOPTS:
2167 case IP_PKTINFO:
2168 case IP_MTU_DISCOVER:
2169 case IP_RECVERR:
2170 case IP_RECVTOS:
2171#ifdef IP_FREEBIND
2172 case IP_FREEBIND:
2173#endif
2174 case IP_MULTICAST_TTL:
2175 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00002176 val = 0;
2177 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00002178 if (get_user_u32(val, optval_addr))
2179 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002180 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00002181 if (get_user_u8(val, optval_addr))
2182 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002183 }
2184 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
2185 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02002186 case IP_ADD_MEMBERSHIP:
2187 case IP_DROP_MEMBERSHIP:
2188 if (optlen < sizeof (struct target_ip_mreq) ||
2189 optlen > sizeof (struct target_ip_mreqn))
2190 return -TARGET_EINVAL;
2191
2192 ip_mreq = (struct ip_mreqn *) alloca(optlen);
2193 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
2194 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
2195 break;
2196
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02002197 case IP_BLOCK_SOURCE:
2198 case IP_UNBLOCK_SOURCE:
2199 case IP_ADD_SOURCE_MEMBERSHIP:
2200 case IP_DROP_SOURCE_MEMBERSHIP:
2201 if (optlen != sizeof (struct target_ip_mreq_source))
2202 return -TARGET_EINVAL;
2203
2204 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2205 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
2206 unlock_user (ip_mreq_source, optval_addr, 0);
2207 break;
2208
bellard8853f862004-02-22 14:57:26 +00002209 default:
2210 goto unimplemented;
2211 }
2212 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02002213 case SOL_IPV6:
2214 switch (optname) {
2215 case IPV6_MTU_DISCOVER:
2216 case IPV6_MTU:
2217 case IPV6_V6ONLY:
2218 case IPV6_RECVPKTINFO:
2219 val = 0;
2220 if (optlen < sizeof(uint32_t)) {
2221 return -TARGET_EINVAL;
2222 }
2223 if (get_user_u32(val, optval_addr)) {
2224 return -TARGET_EFAULT;
2225 }
2226 ret = get_errno(setsockopt(sockfd, level, optname,
2227 &val, sizeof(val)));
2228 break;
2229 default:
2230 goto unimplemented;
2231 }
2232 break;
Jing Huang920394d2012-07-24 13:59:23 +00002233 case SOL_RAW:
2234 switch (optname) {
2235 case ICMP_FILTER:
2236 /* struct icmp_filter takes an u32 value */
2237 if (optlen < sizeof(uint32_t)) {
2238 return -TARGET_EINVAL;
2239 }
2240
2241 if (get_user_u32(val, optval_addr)) {
2242 return -TARGET_EFAULT;
2243 }
2244 ret = get_errno(setsockopt(sockfd, level, optname,
2245 &val, sizeof(val)));
2246 break;
2247
2248 default:
2249 goto unimplemented;
2250 }
2251 break;
bellard3532fa72006-06-24 15:06:03 +00002252 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00002253 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00002254 case TARGET_SO_RCVTIMEO:
2255 {
2256 struct timeval tv;
2257
2258 optname = SO_RCVTIMEO;
2259
2260set_timeout:
2261 if (optlen != sizeof(struct target_timeval)) {
2262 return -TARGET_EINVAL;
2263 }
2264
2265 if (copy_from_user_timeval(&tv, optval_addr)) {
2266 return -TARGET_EFAULT;
2267 }
2268
2269 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2270 &tv, sizeof(tv)));
2271 return ret;
2272 }
2273 case TARGET_SO_SNDTIMEO:
2274 optname = SO_SNDTIMEO;
2275 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02002276 case TARGET_SO_ATTACH_FILTER:
2277 {
2278 struct target_sock_fprog *tfprog;
2279 struct target_sock_filter *tfilter;
2280 struct sock_fprog fprog;
2281 struct sock_filter *filter;
2282 int i;
2283
2284 if (optlen != sizeof(*tfprog)) {
2285 return -TARGET_EINVAL;
2286 }
2287 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
2288 return -TARGET_EFAULT;
2289 }
2290 if (!lock_user_struct(VERIFY_READ, tfilter,
2291 tswapal(tfprog->filter), 0)) {
2292 unlock_user_struct(tfprog, optval_addr, 1);
2293 return -TARGET_EFAULT;
2294 }
2295
2296 fprog.len = tswap16(tfprog->len);
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302297 filter = g_try_new(struct sock_filter, fprog.len);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002298 if (filter == NULL) {
2299 unlock_user_struct(tfilter, tfprog->filter, 1);
2300 unlock_user_struct(tfprog, optval_addr, 1);
2301 return -TARGET_ENOMEM;
2302 }
2303 for (i = 0; i < fprog.len; i++) {
2304 filter[i].code = tswap16(tfilter[i].code);
2305 filter[i].jt = tfilter[i].jt;
2306 filter[i].jf = tfilter[i].jf;
2307 filter[i].k = tswap32(tfilter[i].k);
2308 }
2309 fprog.filter = filter;
2310
2311 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
2312 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302313 g_free(filter);
Laurent Vivierf57d4192013-08-30 01:46:41 +02002314
2315 unlock_user_struct(tfilter, tfprog->filter, 1);
2316 unlock_user_struct(tfprog, optval_addr, 1);
2317 return ret;
2318 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002319 case TARGET_SO_BINDTODEVICE:
2320 {
2321 char *dev_ifname, *addr_ifname;
2322
2323 if (optlen > IFNAMSIZ - 1) {
2324 optlen = IFNAMSIZ - 1;
2325 }
2326 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
2327 if (!dev_ifname) {
2328 return -TARGET_EFAULT;
2329 }
2330 optname = SO_BINDTODEVICE;
2331 addr_ifname = alloca(IFNAMSIZ);
2332 memcpy(addr_ifname, dev_ifname, optlen);
2333 addr_ifname[optlen] = 0;
Chen Gangfad6c582016-01-11 13:58:50 +08002334 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
2335 addr_ifname, optlen));
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02002336 unlock_user (dev_ifname, optval_addr, 0);
2337 return ret;
2338 }
bellard8853f862004-02-22 14:57:26 +00002339 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00002340 case TARGET_SO_DEBUG:
2341 optname = SO_DEBUG;
2342 break;
2343 case TARGET_SO_REUSEADDR:
2344 optname = SO_REUSEADDR;
2345 break;
2346 case TARGET_SO_TYPE:
2347 optname = SO_TYPE;
2348 break;
2349 case TARGET_SO_ERROR:
2350 optname = SO_ERROR;
2351 break;
2352 case TARGET_SO_DONTROUTE:
2353 optname = SO_DONTROUTE;
2354 break;
2355 case TARGET_SO_BROADCAST:
2356 optname = SO_BROADCAST;
2357 break;
2358 case TARGET_SO_SNDBUF:
2359 optname = SO_SNDBUF;
2360 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002361 case TARGET_SO_SNDBUFFORCE:
2362 optname = SO_SNDBUFFORCE;
2363 break;
bellard3532fa72006-06-24 15:06:03 +00002364 case TARGET_SO_RCVBUF:
2365 optname = SO_RCVBUF;
2366 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01002367 case TARGET_SO_RCVBUFFORCE:
2368 optname = SO_RCVBUFFORCE;
2369 break;
bellard3532fa72006-06-24 15:06:03 +00002370 case TARGET_SO_KEEPALIVE:
2371 optname = SO_KEEPALIVE;
2372 break;
2373 case TARGET_SO_OOBINLINE:
2374 optname = SO_OOBINLINE;
2375 break;
2376 case TARGET_SO_NO_CHECK:
2377 optname = SO_NO_CHECK;
2378 break;
2379 case TARGET_SO_PRIORITY:
2380 optname = SO_PRIORITY;
2381 break;
bellard5e83e8e2005-03-01 22:32:06 +00002382#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00002383 case TARGET_SO_BSDCOMPAT:
2384 optname = SO_BSDCOMPAT;
2385 break;
bellard5e83e8e2005-03-01 22:32:06 +00002386#endif
bellard3532fa72006-06-24 15:06:03 +00002387 case TARGET_SO_PASSCRED:
2388 optname = SO_PASSCRED;
2389 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01002390 case TARGET_SO_PASSSEC:
2391 optname = SO_PASSSEC;
2392 break;
bellard3532fa72006-06-24 15:06:03 +00002393 case TARGET_SO_TIMESTAMP:
2394 optname = SO_TIMESTAMP;
2395 break;
2396 case TARGET_SO_RCVLOWAT:
2397 optname = SO_RCVLOWAT;
2398 break;
bellard8853f862004-02-22 14:57:26 +00002399 break;
2400 default:
2401 goto unimplemented;
2402 }
bellard3532fa72006-06-24 15:06:03 +00002403 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00002404 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00002405
bellard2f619692007-11-16 10:46:05 +00002406 if (get_user_u32(val, optval_addr))
2407 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00002408 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00002409 break;
bellard7854b052003-03-29 17:22:23 +00002410 default:
bellard8853f862004-02-22 14:57:26 +00002411 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02002412 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00002413 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00002414 }
bellard8853f862004-02-22 14:57:26 +00002415 return ret;
bellard7854b052003-03-29 17:22:23 +00002416}
2417
ths0da46a62007-10-20 20:23:07 +00002418/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002419static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00002420 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00002421{
blueswir1992f48a2007-10-14 16:27:31 +00002422 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00002423 int len, val;
2424 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00002425
2426 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00002427 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002428 level = SOL_SOCKET;
2429 switch (optname) {
2430 /* These don't just return a single integer */
2431 case TARGET_SO_LINGER:
2432 case TARGET_SO_RCVTIMEO:
2433 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002434 case TARGET_SO_PEERNAME:
2435 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02002436 case TARGET_SO_PEERCRED: {
2437 struct ucred cr;
2438 socklen_t crlen;
2439 struct target_ucred *tcr;
2440
2441 if (get_user_u32(len, optlen)) {
2442 return -TARGET_EFAULT;
2443 }
2444 if (len < 0) {
2445 return -TARGET_EINVAL;
2446 }
2447
2448 crlen = sizeof(cr);
2449 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
2450 &cr, &crlen));
2451 if (ret < 0) {
2452 return ret;
2453 }
2454 if (len > crlen) {
2455 len = crlen;
2456 }
2457 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
2458 return -TARGET_EFAULT;
2459 }
2460 __put_user(cr.pid, &tcr->pid);
2461 __put_user(cr.uid, &tcr->uid);
2462 __put_user(cr.gid, &tcr->gid);
2463 unlock_user_struct(tcr, optval_addr, 1);
2464 if (put_user_u32(len, optlen)) {
2465 return -TARGET_EFAULT;
2466 }
2467 break;
2468 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002469 /* Options with 'int' argument. */
2470 case TARGET_SO_DEBUG:
2471 optname = SO_DEBUG;
2472 goto int_case;
2473 case TARGET_SO_REUSEADDR:
2474 optname = SO_REUSEADDR;
2475 goto int_case;
2476 case TARGET_SO_TYPE:
2477 optname = SO_TYPE;
2478 goto int_case;
2479 case TARGET_SO_ERROR:
2480 optname = SO_ERROR;
2481 goto int_case;
2482 case TARGET_SO_DONTROUTE:
2483 optname = SO_DONTROUTE;
2484 goto int_case;
2485 case TARGET_SO_BROADCAST:
2486 optname = SO_BROADCAST;
2487 goto int_case;
2488 case TARGET_SO_SNDBUF:
2489 optname = SO_SNDBUF;
2490 goto int_case;
2491 case TARGET_SO_RCVBUF:
2492 optname = SO_RCVBUF;
2493 goto int_case;
2494 case TARGET_SO_KEEPALIVE:
2495 optname = SO_KEEPALIVE;
2496 goto int_case;
2497 case TARGET_SO_OOBINLINE:
2498 optname = SO_OOBINLINE;
2499 goto int_case;
2500 case TARGET_SO_NO_CHECK:
2501 optname = SO_NO_CHECK;
2502 goto int_case;
2503 case TARGET_SO_PRIORITY:
2504 optname = SO_PRIORITY;
2505 goto int_case;
2506#ifdef SO_BSDCOMPAT
2507 case TARGET_SO_BSDCOMPAT:
2508 optname = SO_BSDCOMPAT;
2509 goto int_case;
2510#endif
2511 case TARGET_SO_PASSCRED:
2512 optname = SO_PASSCRED;
2513 goto int_case;
2514 case TARGET_SO_TIMESTAMP:
2515 optname = SO_TIMESTAMP;
2516 goto int_case;
2517 case TARGET_SO_RCVLOWAT:
2518 optname = SO_RCVLOWAT;
2519 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01002520 case TARGET_SO_ACCEPTCONN:
2521 optname = SO_ACCEPTCONN;
2522 goto int_case;
bellard8853f862004-02-22 14:57:26 +00002523 default:
bellard2efbe912005-07-23 15:10:20 +00002524 goto int_case;
2525 }
2526 break;
2527 case SOL_TCP:
2528 /* TCP options all take an 'int' value. */
2529 int_case:
bellard2f619692007-11-16 10:46:05 +00002530 if (get_user_u32(len, optlen))
2531 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002532 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002533 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002534 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00002535 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2536 if (ret < 0)
2537 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01002538 if (optname == SO_TYPE) {
2539 val = host_to_target_sock_type(val);
2540 }
bellard2efbe912005-07-23 15:10:20 +00002541 if (len > lv)
2542 len = lv;
bellard2f619692007-11-16 10:46:05 +00002543 if (len == 4) {
2544 if (put_user_u32(val, optval_addr))
2545 return -TARGET_EFAULT;
2546 } else {
2547 if (put_user_u8(val, optval_addr))
2548 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02002549 }
bellard2f619692007-11-16 10:46:05 +00002550 if (put_user_u32(len, optlen))
2551 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002552 break;
2553 case SOL_IP:
2554 switch(optname) {
2555 case IP_TOS:
2556 case IP_TTL:
2557 case IP_HDRINCL:
2558 case IP_ROUTER_ALERT:
2559 case IP_RECVOPTS:
2560 case IP_RETOPTS:
2561 case IP_PKTINFO:
2562 case IP_MTU_DISCOVER:
2563 case IP_RECVERR:
2564 case IP_RECVTOS:
2565#ifdef IP_FREEBIND
2566 case IP_FREEBIND:
2567#endif
2568 case IP_MULTICAST_TTL:
2569 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00002570 if (get_user_u32(len, optlen))
2571 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00002572 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00002573 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05002574 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00002575 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
2576 if (ret < 0)
2577 return ret;
bellard2efbe912005-07-23 15:10:20 +00002578 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00002579 len = 1;
bellard2f619692007-11-16 10:46:05 +00002580 if (put_user_u32(len, optlen)
2581 || put_user_u8(val, optval_addr))
2582 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002583 } else {
bellard2efbe912005-07-23 15:10:20 +00002584 if (len > sizeof(int))
2585 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00002586 if (put_user_u32(len, optlen)
2587 || put_user_u32(val, optval_addr))
2588 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00002589 }
bellard8853f862004-02-22 14:57:26 +00002590 break;
bellard2efbe912005-07-23 15:10:20 +00002591 default:
thsc02f4992007-12-18 02:39:59 +00002592 ret = -TARGET_ENOPROTOOPT;
2593 break;
bellard8853f862004-02-22 14:57:26 +00002594 }
2595 break;
2596 default:
2597 unimplemented:
2598 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
2599 level, optname);
thsc02f4992007-12-18 02:39:59 +00002600 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00002601 break;
2602 }
2603 return ret;
bellard7854b052003-03-29 17:22:23 +00002604}
2605
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002606static struct iovec *lock_iovec(int type, abi_ulong target_addr,
2607 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002608{
2609 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002610 struct iovec *vec;
2611 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00002612 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00002613 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05002614 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00002615
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002616 if (count == 0) {
2617 errno = 0;
2618 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002619 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00002620 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002621 errno = EINVAL;
2622 return NULL;
2623 }
2624
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302625 vec = g_try_new0(struct iovec, count);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002626 if (vec == NULL) {
2627 errno = ENOMEM;
2628 return NULL;
2629 }
2630
2631 target_vec = lock_user(VERIFY_READ, target_addr,
2632 count * sizeof(struct target_iovec), 1);
2633 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002634 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002635 goto fail2;
2636 }
2637
2638 /* ??? If host page size > target page size, this will result in a
2639 value larger than what we can actually support. */
2640 max_len = 0x7fffffff & TARGET_PAGE_MASK;
2641 total_len = 0;
2642
2643 for (i = 0; i < count; i++) {
2644 abi_ulong base = tswapal(target_vec[i].iov_base);
2645 abi_long len = tswapal(target_vec[i].iov_len);
2646
2647 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00002648 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002649 goto fail;
2650 } else if (len == 0) {
2651 /* Zero length pointer is ignored. */
2652 vec[i].iov_base = 0;
2653 } else {
2654 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05002655 /* If the first buffer pointer is bad, this is a fault. But
2656 * subsequent bad buffers will result in a partial write; this
2657 * is realized by filling the vector with null pointers and
2658 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002659 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05002660 if (i == 0) {
2661 err = EFAULT;
2662 goto fail;
2663 } else {
2664 bad_address = true;
2665 }
2666 }
2667 if (bad_address) {
2668 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002669 }
2670 if (len > max_len - total_len) {
2671 len = max_len - total_len;
2672 }
2673 }
2674 vec[i].iov_len = len;
2675 total_len += len;
2676 }
2677
2678 unlock_user(target_vec, target_addr, 0);
2679 return vec;
2680
2681 fail:
Chen Gang S7eff5182015-01-23 18:01:09 +08002682 while (--i >= 0) {
2683 if (tswapal(target_vec[i].iov_len) > 0) {
2684 unlock_user(vec[i].iov_base, tswapal(target_vec[i].iov_base), 0);
2685 }
2686 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002687 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002688 fail2:
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302689 g_free(vec);
Peter Maydell501bb4b2014-02-17 18:55:33 +00002690 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002691 return NULL;
pbrook53a59602006-03-25 19:31:22 +00002692}
2693
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002694static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
2695 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00002696{
2697 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00002698 int i;
2699
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002700 target_vec = lock_user(VERIFY_READ, target_addr,
2701 count * sizeof(struct target_iovec), 1);
2702 if (target_vec) {
2703 for (i = 0; i < count; i++) {
2704 abi_ulong base = tswapal(target_vec[i].iov_base);
Chen Gang S71ec7ce2015-01-23 18:07:50 +08002705 abi_long len = tswapal(target_vec[i].iov_len);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002706 if (len < 0) {
2707 break;
2708 }
balrogd732dcb2008-10-28 10:21:03 +00002709 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
2710 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002711 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00002712 }
bellard579a97f2007-11-11 14:26:47 +00002713
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05302714 g_free(vec);
pbrook53a59602006-03-25 19:31:22 +00002715}
2716
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002717static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002718{
2719 int host_type = 0;
2720 int target_type = *type;
2721
2722 switch (target_type & TARGET_SOCK_TYPE_MASK) {
2723 case TARGET_SOCK_DGRAM:
2724 host_type = SOCK_DGRAM;
2725 break;
2726 case TARGET_SOCK_STREAM:
2727 host_type = SOCK_STREAM;
2728 break;
2729 default:
2730 host_type = target_type & TARGET_SOCK_TYPE_MASK;
2731 break;
2732 }
2733 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002734#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002735 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002736#else
2737 return -TARGET_EINVAL;
2738#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002739 }
2740 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002741#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002742 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002743#elif !defined(O_NONBLOCK)
2744 return -TARGET_EINVAL;
2745#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002746 }
2747 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002748 return 0;
2749}
2750
2751/* Try to emulate socket type flags after socket creation. */
2752static int sock_flags_fixup(int fd, int target_type)
2753{
2754#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
2755 if (target_type & TARGET_SOCK_NONBLOCK) {
2756 int flags = fcntl(fd, F_GETFL);
2757 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
2758 close(fd);
2759 return -TARGET_EINVAL;
2760 }
2761 }
2762#endif
2763 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002764}
2765
Laurent Vivier0cf22722015-10-28 21:40:45 +01002766static abi_long packet_target_to_host_sockaddr(void *host_addr,
2767 abi_ulong target_addr,
2768 socklen_t len)
2769{
2770 struct sockaddr *addr = host_addr;
2771 struct target_sockaddr *target_saddr;
2772
2773 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
2774 if (!target_saddr) {
2775 return -TARGET_EFAULT;
2776 }
2777
2778 memcpy(addr, target_saddr, len);
2779 addr->sa_family = tswap16(target_saddr->sa_family);
2780 /* spkt_protocol is big-endian */
2781
2782 unlock_user(target_saddr, target_addr, 0);
2783 return 0;
2784}
2785
2786static TargetFdTrans target_packet_trans = {
2787 .target_to_host_addr = packet_target_to_host_sockaddr,
2788};
2789
Laurent Vivier575b22b2016-06-02 22:14:15 +02002790#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002791static abi_long netlink_route_target_to_host(void *buf, size_t len)
2792{
2793 return target_to_host_nlmsg_route(buf, len);
2794}
2795
2796static abi_long netlink_route_host_to_target(void *buf, size_t len)
2797{
2798 return host_to_target_nlmsg_route(buf, len);
2799}
2800
2801static TargetFdTrans target_netlink_route_trans = {
2802 .target_to_host_data = netlink_route_target_to_host,
2803 .host_to_target_data = netlink_route_host_to_target,
2804};
Laurent Vivier575b22b2016-06-02 22:14:15 +02002805#endif /* CONFIG_RTNETLINK */
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002806
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002807static abi_long netlink_audit_target_to_host(void *buf, size_t len)
2808{
2809 return target_to_host_nlmsg_audit(buf, len);
2810}
2811
2812static abi_long netlink_audit_host_to_target(void *buf, size_t len)
2813{
2814 return host_to_target_nlmsg_audit(buf, len);
2815}
2816
2817static TargetFdTrans target_netlink_audit_trans = {
2818 .target_to_host_data = netlink_audit_target_to_host,
2819 .host_to_target_data = netlink_audit_host_to_target,
2820};
2821
ths0da46a62007-10-20 20:23:07 +00002822/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002823static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00002824{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002825 int target_type = type;
2826 int ret;
2827
2828 ret = target_to_host_sock_type(&type);
2829 if (ret) {
2830 return ret;
2831 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002832
Laurent Vivier575b22b2016-06-02 22:14:15 +02002833 if (domain == PF_NETLINK && !(
2834#ifdef CONFIG_RTNETLINK
2835 protocol == NETLINK_ROUTE ||
2836#endif
2837 protocol == NETLINK_KOBJECT_UEVENT ||
2838 protocol == NETLINK_AUDIT)) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002839 return -EPFNOSUPPORT;
2840 }
Laurent Vivierff626f22015-10-28 21:40:42 +01002841
2842 if (domain == AF_PACKET ||
2843 (domain == AF_INET && type == SOCK_PACKET)) {
2844 protocol = tswap16(protocol);
2845 }
2846
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002847 ret = get_errno(socket(domain, type, protocol));
2848 if (ret >= 0) {
2849 ret = sock_flags_fixup(ret, target_type);
Laurent Vivier0cf22722015-10-28 21:40:45 +01002850 if (type == SOCK_PACKET) {
2851 /* Manage an obsolete case :
2852 * if socket type is SOCK_PACKET, bind by name
2853 */
2854 fd_trans_register(ret, &target_packet_trans);
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002855 } else if (domain == PF_NETLINK) {
2856 switch (protocol) {
Laurent Vivier575b22b2016-06-02 22:14:15 +02002857#ifdef CONFIG_RTNETLINK
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002858 case NETLINK_ROUTE:
2859 fd_trans_register(ret, &target_netlink_route_trans);
2860 break;
Laurent Vivier575b22b2016-06-02 22:14:15 +02002861#endif
Laurent Vivierb2656202016-05-22 18:56:20 +02002862 case NETLINK_KOBJECT_UEVENT:
2863 /* nothing to do: messages are strings */
2864 break;
Laurent Vivier5ce9bb52016-05-22 18:56:21 +02002865 case NETLINK_AUDIT:
2866 fd_trans_register(ret, &target_netlink_audit_trans);
2867 break;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002868 default:
2869 g_assert_not_reached();
2870 }
Laurent Vivier0cf22722015-10-28 21:40:45 +01002871 }
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02002872 }
2873 return ret;
bellard3532fa72006-06-24 15:06:03 +00002874}
2875
ths0da46a62007-10-20 20:23:07 +00002876/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002877static abi_long do_bind(int sockfd, abi_ulong target_addr,
2878 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002879{
aurel328f7aeaf2009-01-30 19:47:57 +00002880 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002881 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002882
Blue Swirl38724252010-09-18 05:53:14 +00002883 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002884 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002885 }
aurel328f7aeaf2009-01-30 19:47:57 +00002886
aurel32607175e2009-04-15 16:11:59 +00002887 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002888
Laurent Vivier7b36f782015-10-28 21:40:44 +01002889 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002890 if (ret)
2891 return ret;
2892
bellard3532fa72006-06-24 15:06:03 +00002893 return get_errno(bind(sockfd, addr, addrlen));
2894}
2895
ths0da46a62007-10-20 20:23:07 +00002896/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002897static abi_long do_connect(int sockfd, abi_ulong target_addr,
2898 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002899{
aurel328f7aeaf2009-01-30 19:47:57 +00002900 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002901 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002902
Blue Swirl38724252010-09-18 05:53:14 +00002903 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002904 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002905 }
aurel328f7aeaf2009-01-30 19:47:57 +00002906
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002907 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002908
Laurent Vivier7b36f782015-10-28 21:40:44 +01002909 ret = target_to_host_sockaddr(sockfd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002910 if (ret)
2911 return ret;
2912
Peter Maydell2a3c7612016-06-06 19:58:03 +01002913 return get_errno(safe_connect(sockfd, addr, addrlen));
bellard3532fa72006-06-24 15:06:03 +00002914}
2915
Alexander Graff19e00d2014-03-02 19:36:42 +00002916/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2917static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2918 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002919{
balrog6de645c2008-10-28 10:26:29 +00002920 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002921 struct msghdr msg;
2922 int count;
2923 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002924 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002925
bellard3532fa72006-06-24 15:06:03 +00002926 if (msgp->msg_name) {
2927 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002928 msg.msg_name = alloca(msg.msg_namelen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01002929 ret = target_to_host_sockaddr(fd, msg.msg_name,
2930 tswapal(msgp->msg_name),
2931 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002932 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002933 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002934 }
bellard3532fa72006-06-24 15:06:03 +00002935 } else {
2936 msg.msg_name = NULL;
2937 msg.msg_namelen = 0;
2938 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002939 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002940 msg.msg_control = alloca(msg.msg_controllen);
2941 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002942
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002943 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002944 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002945 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2946 target_vec, count, send);
2947 if (vec == NULL) {
2948 ret = -host_to_target_errno(errno);
2949 goto out2;
2950 }
bellard3532fa72006-06-24 15:06:03 +00002951 msg.msg_iovlen = count;
2952 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002953
bellard3532fa72006-06-24 15:06:03 +00002954 if (send) {
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002955 if (fd_trans_target_to_host_data(fd)) {
2956 ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base,
2957 msg.msg_iov->iov_len);
2958 } else {
2959 ret = target_to_host_cmsg(&msg, msgp);
2960 }
2961 if (ret == 0) {
Peter Maydell66687532016-06-06 19:58:04 +01002962 ret = get_errno(safe_sendmsg(fd, &msg, flags));
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002963 }
bellard3532fa72006-06-24 15:06:03 +00002964 } else {
Peter Maydell66687532016-06-06 19:58:04 +01002965 ret = get_errno(safe_recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002966 if (!is_error(ret)) {
2967 len = ret;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02002968 if (fd_trans_host_to_target_data(fd)) {
2969 ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
2970 msg.msg_iov->iov_len);
2971 } else {
2972 ret = host_to_target_cmsg(msgp, &msg);
2973 }
Jing Huangca619062012-07-24 13:58:02 +00002974 if (!is_error(ret)) {
2975 msgp->msg_namelen = tswap32(msg.msg_namelen);
2976 if (msg.msg_name != NULL) {
2977 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2978 msg.msg_name, msg.msg_namelen);
2979 if (ret) {
2980 goto out;
2981 }
2982 }
2983
balrog6de645c2008-10-28 10:26:29 +00002984 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002985 }
balrog6de645c2008-10-28 10:26:29 +00002986 }
bellard3532fa72006-06-24 15:06:03 +00002987 }
Jing Huangca619062012-07-24 13:58:02 +00002988
2989out:
bellard3532fa72006-06-24 15:06:03 +00002990 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002991out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002992 return ret;
2993}
2994
2995static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2996 int flags, int send)
2997{
2998 abi_long ret;
2999 struct target_msghdr *msgp;
3000
3001 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
3002 msgp,
3003 target_msg,
3004 send ? 1 : 0)) {
3005 return -TARGET_EFAULT;
3006 }
3007 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00003008 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00003009 return ret;
3010}
3011
Alexander Graff19e00d2014-03-02 19:36:42 +00003012/* We don't rely on the C library to have sendmmsg/recvmmsg support,
3013 * so it might not have this *mmsg-specific flag either.
3014 */
3015#ifndef MSG_WAITFORONE
3016#define MSG_WAITFORONE 0x10000
3017#endif
3018
3019static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
3020 unsigned int vlen, unsigned int flags,
3021 int send)
3022{
3023 struct target_mmsghdr *mmsgp;
3024 abi_long ret = 0;
3025 int i;
3026
3027 if (vlen > UIO_MAXIOV) {
3028 vlen = UIO_MAXIOV;
3029 }
3030
3031 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
3032 if (!mmsgp) {
3033 return -TARGET_EFAULT;
3034 }
3035
3036 for (i = 0; i < vlen; i++) {
3037 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
3038 if (is_error(ret)) {
3039 break;
3040 }
3041 mmsgp[i].msg_len = tswap32(ret);
3042 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
3043 if (flags & MSG_WAITFORONE) {
3044 flags |= MSG_DONTWAIT;
3045 }
3046 }
3047
3048 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
3049
3050 /* Return number of datagrams sent if we sent any at all;
3051 * otherwise return the error.
3052 */
3053 if (i) {
3054 return i;
3055 }
3056 return ret;
3057}
Alexander Graff19e00d2014-03-02 19:36:42 +00003058
Peter Maydella94b4982013-02-08 04:35:04 +00003059/* If we don't have a system accept4() then just call accept.
3060 * The callsites to do_accept4() will ensure that they don't
3061 * pass a non-zero flags argument in this config.
3062 */
3063#ifndef CONFIG_ACCEPT4
3064static inline int accept4(int sockfd, struct sockaddr *addr,
3065 socklen_t *addrlen, int flags)
3066{
3067 assert(flags == 0);
3068 return accept(sockfd, addr, addrlen);
3069}
3070#endif
3071
3072/* do_accept4() Must return target values and target errnos. */
3073static abi_long do_accept4(int fd, abi_ulong target_addr,
3074 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00003075{
bellard2f619692007-11-16 10:46:05 +00003076 socklen_t addrlen;
3077 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003078 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003079 int host_flags;
3080
3081 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00003082
Peter Maydella94b4982013-02-08 04:35:04 +00003083 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003084 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00003085 }
Arnaud Patard917507b2009-06-19 10:44:45 +03003086
3087 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00003088 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03003089 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00003090
Blue Swirl38724252010-09-18 05:53:14 +00003091 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003092 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003093 }
aurel328f7aeaf2009-01-30 19:47:57 +00003094
Arnaud Patard917507b2009-06-19 10:44:45 +03003095 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3096 return -TARGET_EINVAL;
3097
bellard2f619692007-11-16 10:46:05 +00003098 addr = alloca(addrlen);
3099
Petar Jovanovicd25295d2014-03-31 17:41:23 +02003100 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00003101 if (!is_error(ret)) {
3102 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003103 if (put_user_u32(addrlen, target_addrlen_addr))
3104 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003105 }
3106 return ret;
3107}
3108
ths0da46a62007-10-20 20:23:07 +00003109/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003110static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003111 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003112{
bellard2f619692007-11-16 10:46:05 +00003113 socklen_t addrlen;
3114 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003115 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003116
bellard2f619692007-11-16 10:46:05 +00003117 if (get_user_u32(addrlen, target_addrlen_addr))
3118 return -TARGET_EFAULT;
3119
Blue Swirl38724252010-09-18 05:53:14 +00003120 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003121 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003122 }
aurel328f7aeaf2009-01-30 19:47:57 +00003123
Arnaud Patard917507b2009-06-19 10:44:45 +03003124 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3125 return -TARGET_EFAULT;
3126
bellard2f619692007-11-16 10:46:05 +00003127 addr = alloca(addrlen);
3128
pbrook1be9e1d2006-11-19 15:26:04 +00003129 ret = get_errno(getpeername(fd, addr, &addrlen));
3130 if (!is_error(ret)) {
3131 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003132 if (put_user_u32(addrlen, target_addrlen_addr))
3133 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003134 }
3135 return ret;
3136}
3137
ths0da46a62007-10-20 20:23:07 +00003138/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003139static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00003140 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003141{
bellard2f619692007-11-16 10:46:05 +00003142 socklen_t addrlen;
3143 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00003144 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003145
bellard2f619692007-11-16 10:46:05 +00003146 if (get_user_u32(addrlen, target_addrlen_addr))
3147 return -TARGET_EFAULT;
3148
Blue Swirl38724252010-09-18 05:53:14 +00003149 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003150 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003151 }
aurel328f7aeaf2009-01-30 19:47:57 +00003152
Arnaud Patard917507b2009-06-19 10:44:45 +03003153 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
3154 return -TARGET_EFAULT;
3155
bellard2f619692007-11-16 10:46:05 +00003156 addr = alloca(addrlen);
3157
pbrook1be9e1d2006-11-19 15:26:04 +00003158 ret = get_errno(getsockname(fd, addr, &addrlen));
3159 if (!is_error(ret)) {
3160 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003161 if (put_user_u32(addrlen, target_addrlen_addr))
3162 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003163 }
3164 return ret;
3165}
3166
ths0da46a62007-10-20 20:23:07 +00003167/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003168static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00003169 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00003170{
3171 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00003172 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003173
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02003174 target_to_host_sock_type(&type);
3175
pbrook1be9e1d2006-11-19 15:26:04 +00003176 ret = get_errno(socketpair(domain, type, protocol, tab));
3177 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00003178 if (put_user_s32(tab[0], target_tab_addr)
3179 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
3180 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003181 }
3182 return ret;
3183}
3184
ths0da46a62007-10-20 20:23:07 +00003185/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003186static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
3187 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003188{
3189 void *addr;
3190 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003191 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003192
Blue Swirl38724252010-09-18 05:53:14 +00003193 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003194 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00003195 }
aurel328f7aeaf2009-01-30 19:47:57 +00003196
bellard579a97f2007-11-11 14:26:47 +00003197 host_msg = lock_user(VERIFY_READ, msg, len, 1);
3198 if (!host_msg)
3199 return -TARGET_EFAULT;
Laurent Vivier6c5b5642016-05-22 18:56:19 +02003200 if (fd_trans_target_to_host_data(fd)) {
3201 ret = fd_trans_target_to_host_data(fd)(host_msg, len);
3202 if (ret < 0) {
3203 unlock_user(host_msg, msg, 0);
3204 return ret;
3205 }
3206 }
pbrook1be9e1d2006-11-19 15:26:04 +00003207 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02003208 addr = alloca(addrlen+1);
Laurent Vivier7b36f782015-10-28 21:40:44 +01003209 ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03003210 if (ret) {
3211 unlock_user(host_msg, msg, 0);
3212 return ret;
3213 }
Peter Maydell66687532016-06-06 19:58:04 +01003214 ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003215 } else {
Peter Maydell66687532016-06-06 19:58:04 +01003216 ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003217 }
3218 unlock_user(host_msg, msg, 0);
3219 return ret;
3220}
3221
ths0da46a62007-10-20 20:23:07 +00003222/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003223static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
3224 abi_ulong target_addr,
3225 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00003226{
3227 socklen_t addrlen;
3228 void *addr;
3229 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00003230 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00003231
bellard579a97f2007-11-11 14:26:47 +00003232 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
3233 if (!host_msg)
3234 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00003235 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00003236 if (get_user_u32(addrlen, target_addrlen)) {
3237 ret = -TARGET_EFAULT;
3238 goto fail;
3239 }
Blue Swirl38724252010-09-18 05:53:14 +00003240 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00003241 ret = -TARGET_EINVAL;
3242 goto fail;
3243 }
pbrook1be9e1d2006-11-19 15:26:04 +00003244 addr = alloca(addrlen);
Peter Maydell66687532016-06-06 19:58:04 +01003245 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
3246 addr, &addrlen));
pbrook1be9e1d2006-11-19 15:26:04 +00003247 } else {
3248 addr = NULL; /* To keep compiler quiet. */
Peter Maydell66687532016-06-06 19:58:04 +01003249 ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
pbrook1be9e1d2006-11-19 15:26:04 +00003250 }
3251 if (!is_error(ret)) {
3252 if (target_addr) {
3253 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00003254 if (put_user_u32(addrlen, target_addrlen)) {
3255 ret = -TARGET_EFAULT;
3256 goto fail;
3257 }
pbrook1be9e1d2006-11-19 15:26:04 +00003258 }
3259 unlock_user(host_msg, msg, len);
3260 } else {
bellard2f619692007-11-16 10:46:05 +00003261fail:
pbrook1be9e1d2006-11-19 15:26:04 +00003262 unlock_user(host_msg, msg, 0);
3263 }
3264 return ret;
3265}
3266
j_mayer32407102007-09-26 23:01:49 +00003267#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00003268/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003269static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00003270{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003271 static const unsigned ac[] = { /* number of arguments per call */
3272 [SOCKOP_socket] = 3, /* domain, type, protocol */
3273 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
3274 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
3275 [SOCKOP_listen] = 2, /* sockfd, backlog */
3276 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
3277 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
3278 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
3279 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
3280 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
3281 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
3282 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
3283 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3284 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
3285 [SOCKOP_shutdown] = 2, /* sockfd, how */
3286 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
3287 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003288 [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
3289 [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003290 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3291 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
3292 };
3293 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00003294
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003295 /* first, collect the arguments in a[] according to ac[] */
3296 if (num >= 0 && num < ARRAY_SIZE(ac)) {
3297 unsigned i;
3298 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
3299 for (i = 0; i < ac[num]; ++i) {
3300 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01003301 return -TARGET_EFAULT;
3302 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01003303 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003304 }
bellard2f619692007-11-16 10:46:05 +00003305
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003306 /* now when we have the args, actually handle the call */
3307 switch (num) {
3308 case SOCKOP_socket: /* domain, type, protocol */
3309 return do_socket(a[0], a[1], a[2]);
3310 case SOCKOP_bind: /* sockfd, addr, addrlen */
3311 return do_bind(a[0], a[1], a[2]);
3312 case SOCKOP_connect: /* sockfd, addr, addrlen */
3313 return do_connect(a[0], a[1], a[2]);
3314 case SOCKOP_listen: /* sockfd, backlog */
3315 return get_errno(listen(a[0], a[1]));
3316 case SOCKOP_accept: /* sockfd, addr, addrlen */
3317 return do_accept4(a[0], a[1], a[2], 0);
3318 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
3319 return do_accept4(a[0], a[1], a[2], a[3]);
3320 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
3321 return do_getsockname(a[0], a[1], a[2]);
3322 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
3323 return do_getpeername(a[0], a[1], a[2]);
3324 case SOCKOP_socketpair: /* domain, type, protocol, tab */
3325 return do_socketpair(a[0], a[1], a[2], a[3]);
3326 case SOCKOP_send: /* sockfd, msg, len, flags */
3327 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
3328 case SOCKOP_recv: /* sockfd, msg, len, flags */
3329 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
3330 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
3331 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
3332 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
3333 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
3334 case SOCKOP_shutdown: /* sockfd, how */
3335 return get_errno(shutdown(a[0], a[1]));
3336 case SOCKOP_sendmsg: /* sockfd, msg, flags */
3337 return do_sendrecvmsg(a[0], a[1], a[2], 1);
3338 case SOCKOP_recvmsg: /* sockfd, msg, flags */
3339 return do_sendrecvmsg(a[0], a[1], a[2], 0);
John Paul Adrian Glaubitz5a53dc52015-12-24 19:59:59 +01003340 case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
3341 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
3342 case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
3343 return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003344 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
3345 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
3346 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
3347 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00003348 default:
3349 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04003350 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003351 }
bellard31e31b82003-02-18 22:55:36 +00003352}
j_mayer32407102007-09-26 23:01:49 +00003353#endif
bellard31e31b82003-02-18 22:55:36 +00003354
bellard8853f862004-02-22 14:57:26 +00003355#define N_SHM_REGIONS 32
3356
3357static struct shm_region {
Peter Maydellb6e17872016-02-09 15:57:11 +00003358 abi_ulong start;
3359 abi_ulong size;
3360 bool in_use;
bellard8853f862004-02-22 14:57:26 +00003361} shm_regions[N_SHM_REGIONS];
3362
ths3eb6b042007-06-03 14:26:27 +00003363struct target_semid_ds
3364{
3365 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00003366 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05003367#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003368 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05003369#endif
blueswir1992f48a2007-10-14 16:27:31 +00003370 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05003371#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00003372 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05003373#endif
blueswir1992f48a2007-10-14 16:27:31 +00003374 abi_ulong sem_nsems;
3375 abi_ulong __unused3;
3376 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00003377};
3378
bellard579a97f2007-11-11 14:26:47 +00003379static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
3380 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003381{
3382 struct target_ipc_perm *target_ip;
3383 struct target_semid_ds *target_sd;
3384
bellard579a97f2007-11-11 14:26:47 +00003385 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3386 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00003387 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003388 host_ip->__key = tswap32(target_ip->__key);
3389 host_ip->uid = tswap32(target_ip->uid);
3390 host_ip->gid = tswap32(target_ip->gid);
3391 host_ip->cuid = tswap32(target_ip->cuid);
3392 host_ip->cgid = tswap32(target_ip->cgid);
3393#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3394 host_ip->mode = tswap32(target_ip->mode);
3395#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003396 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003397#endif
3398#if defined(TARGET_PPC)
3399 host_ip->__seq = tswap32(target_ip->__seq);
3400#else
3401 host_ip->__seq = tswap16(target_ip->__seq);
3402#endif
ths3eb6b042007-06-03 14:26:27 +00003403 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003404 return 0;
ths3eb6b042007-06-03 14:26:27 +00003405}
3406
bellard579a97f2007-11-11 14:26:47 +00003407static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
3408 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00003409{
3410 struct target_ipc_perm *target_ip;
3411 struct target_semid_ds *target_sd;
3412
bellard579a97f2007-11-11 14:26:47 +00003413 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3414 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00003415 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003416 target_ip->__key = tswap32(host_ip->__key);
3417 target_ip->uid = tswap32(host_ip->uid);
3418 target_ip->gid = tswap32(host_ip->gid);
3419 target_ip->cuid = tswap32(host_ip->cuid);
3420 target_ip->cgid = tswap32(host_ip->cgid);
3421#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
3422 target_ip->mode = tswap32(host_ip->mode);
3423#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003424 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01003425#endif
3426#if defined(TARGET_PPC)
3427 target_ip->__seq = tswap32(host_ip->__seq);
3428#else
3429 target_ip->__seq = tswap16(host_ip->__seq);
3430#endif
ths3eb6b042007-06-03 14:26:27 +00003431 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003432 return 0;
ths3eb6b042007-06-03 14:26:27 +00003433}
3434
bellard579a97f2007-11-11 14:26:47 +00003435static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
3436 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003437{
3438 struct target_semid_ds *target_sd;
3439
bellard579a97f2007-11-11 14:26:47 +00003440 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3441 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003442 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
3443 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003444 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
3445 host_sd->sem_otime = tswapal(target_sd->sem_otime);
3446 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003447 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003448 return 0;
ths3eb6b042007-06-03 14:26:27 +00003449}
3450
bellard579a97f2007-11-11 14:26:47 +00003451static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
3452 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00003453{
3454 struct target_semid_ds *target_sd;
3455
bellard579a97f2007-11-11 14:26:47 +00003456 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3457 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00003458 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08003459 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003460 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
3461 target_sd->sem_otime = tswapal(host_sd->sem_otime);
3462 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00003463 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003464 return 0;
ths3eb6b042007-06-03 14:26:27 +00003465}
3466
aurel32e5289082009-04-18 16:16:12 +00003467struct target_seminfo {
3468 int semmap;
3469 int semmni;
3470 int semmns;
3471 int semmnu;
3472 int semmsl;
3473 int semopm;
3474 int semume;
3475 int semusz;
3476 int semvmx;
3477 int semaem;
3478};
3479
3480static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
3481 struct seminfo *host_seminfo)
3482{
3483 struct target_seminfo *target_seminfo;
3484 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
3485 return -TARGET_EFAULT;
3486 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
3487 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
3488 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
3489 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
3490 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
3491 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
3492 __put_user(host_seminfo->semume, &target_seminfo->semume);
3493 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
3494 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
3495 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
3496 unlock_user_struct(target_seminfo, target_addr, 1);
3497 return 0;
3498}
3499
thsfa294812007-02-02 22:05:00 +00003500union semun {
3501 int val;
ths3eb6b042007-06-03 14:26:27 +00003502 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00003503 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00003504 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00003505};
3506
ths3eb6b042007-06-03 14:26:27 +00003507union target_semun {
3508 int val;
aurel32e5289082009-04-18 16:16:12 +00003509 abi_ulong buf;
3510 abi_ulong array;
3511 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00003512};
3513
aurel32e5289082009-04-18 16:16:12 +00003514static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
3515 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00003516{
aurel32e5289082009-04-18 16:16:12 +00003517 int nsems;
3518 unsigned short *array;
3519 union semun semun;
3520 struct semid_ds semid_ds;
3521 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003522
aurel32e5289082009-04-18 16:16:12 +00003523 semun.buf = &semid_ds;
3524
3525 ret = semctl(semid, 0, IPC_STAT, semun);
3526 if (ret == -1)
3527 return get_errno(ret);
3528
3529 nsems = semid_ds.sem_nsems;
3530
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303531 *host_array = g_try_new(unsigned short, nsems);
Peter Maydell69d4c702014-02-17 18:55:34 +00003532 if (!*host_array) {
3533 return -TARGET_ENOMEM;
3534 }
aurel32e5289082009-04-18 16:16:12 +00003535 array = lock_user(VERIFY_READ, target_addr,
3536 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00003537 if (!array) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303538 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003539 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00003540 }
aurel32e5289082009-04-18 16:16:12 +00003541
3542 for(i=0; i<nsems; i++) {
3543 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003544 }
aurel32e5289082009-04-18 16:16:12 +00003545 unlock_user(array, target_addr, 0);
3546
bellard579a97f2007-11-11 14:26:47 +00003547 return 0;
ths3eb6b042007-06-03 14:26:27 +00003548}
3549
aurel32e5289082009-04-18 16:16:12 +00003550static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
3551 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00003552{
aurel32e5289082009-04-18 16:16:12 +00003553 int nsems;
3554 unsigned short *array;
3555 union semun semun;
3556 struct semid_ds semid_ds;
3557 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00003558
aurel32e5289082009-04-18 16:16:12 +00003559 semun.buf = &semid_ds;
3560
3561 ret = semctl(semid, 0, IPC_STAT, semun);
3562 if (ret == -1)
3563 return get_errno(ret);
3564
3565 nsems = semid_ds.sem_nsems;
3566
3567 array = lock_user(VERIFY_WRITE, target_addr,
3568 nsems*sizeof(unsigned short), 0);
3569 if (!array)
3570 return -TARGET_EFAULT;
3571
3572 for(i=0; i<nsems; i++) {
3573 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00003574 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303575 g_free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00003576 unlock_user(array, target_addr, 1);
3577
bellard579a97f2007-11-11 14:26:47 +00003578 return 0;
ths3eb6b042007-06-03 14:26:27 +00003579}
3580
aurel32e5289082009-04-18 16:16:12 +00003581static inline abi_long do_semctl(int semid, int semnum, int cmd,
Stefan Weild1c002b2015-02-08 15:40:58 +01003582 abi_ulong target_arg)
ths3eb6b042007-06-03 14:26:27 +00003583{
Stefan Weild1c002b2015-02-08 15:40:58 +01003584 union target_semun target_su = { .buf = target_arg };
ths3eb6b042007-06-03 14:26:27 +00003585 union semun arg;
3586 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05303587 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00003588 struct seminfo seminfo;
3589 abi_long ret = -TARGET_EINVAL;
3590 abi_long err;
3591 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00003592
3593 switch( cmd ) {
3594 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00003595 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05003596 /* In 64 bit cross-endian situations, we will erroneously pick up
3597 * the wrong half of the union for the "val" element. To rectify
3598 * this, the entire 8-byte structure is byteswapped, followed by
3599 * a swap of the 4 byte val field. In other cases, the data is
3600 * already in proper host byte order. */
3601 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
3602 target_su.buf = tswapal(target_su.buf);
3603 arg.val = tswap32(target_su.val);
3604 } else {
3605 arg.val = target_su.val;
3606 }
aurel32e5289082009-04-18 16:16:12 +00003607 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00003608 break;
3609 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00003610 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00003611 err = target_to_host_semarray(semid, &array, target_su.array);
3612 if (err)
3613 return err;
3614 arg.array = array;
3615 ret = get_errno(semctl(semid, semnum, cmd, arg));
3616 err = host_to_target_semarray(semid, target_su.array, &array);
3617 if (err)
3618 return err;
ths3eb6b042007-06-03 14:26:27 +00003619 break;
3620 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00003621 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00003622 case SEM_STAT:
3623 err = target_to_host_semid_ds(&dsarg, target_su.buf);
3624 if (err)
3625 return err;
3626 arg.buf = &dsarg;
3627 ret = get_errno(semctl(semid, semnum, cmd, arg));
3628 err = host_to_target_semid_ds(target_su.buf, &dsarg);
3629 if (err)
3630 return err;
ths3eb6b042007-06-03 14:26:27 +00003631 break;
aurel32e5289082009-04-18 16:16:12 +00003632 case IPC_INFO:
3633 case SEM_INFO:
3634 arg.__buf = &seminfo;
3635 ret = get_errno(semctl(semid, semnum, cmd, arg));
3636 err = host_to_target_seminfo(target_su.__buf, &seminfo);
3637 if (err)
3638 return err;
3639 break;
3640 case IPC_RMID:
3641 case GETPID:
3642 case GETNCNT:
3643 case GETZCNT:
3644 ret = get_errno(semctl(semid, semnum, cmd, NULL));
3645 break;
ths3eb6b042007-06-03 14:26:27 +00003646 }
3647
3648 return ret;
3649}
3650
aurel32e5289082009-04-18 16:16:12 +00003651struct target_sembuf {
3652 unsigned short sem_num;
3653 short sem_op;
3654 short sem_flg;
3655};
3656
3657static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
3658 abi_ulong target_addr,
3659 unsigned nsops)
3660{
3661 struct target_sembuf *target_sembuf;
3662 int i;
3663
3664 target_sembuf = lock_user(VERIFY_READ, target_addr,
3665 nsops*sizeof(struct target_sembuf), 1);
3666 if (!target_sembuf)
3667 return -TARGET_EFAULT;
3668
3669 for(i=0; i<nsops; i++) {
3670 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
3671 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
3672 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
3673 }
3674
3675 unlock_user(target_sembuf, target_addr, 0);
3676
3677 return 0;
3678}
3679
3680static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
3681{
3682 struct sembuf sops[nsops];
3683
3684 if (target_to_host_sembuf(sops, ptr, nsops))
3685 return -TARGET_EFAULT;
3686
Petar Jovanovicc7128c92013-03-21 07:57:36 +00003687 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00003688}
3689
ths1bc012f2007-06-03 14:27:49 +00003690struct target_msqid_ds
3691{
aurel321c54ff92008-10-13 21:08:44 +00003692 struct target_ipc_perm msg_perm;
3693 abi_ulong msg_stime;
3694#if TARGET_ABI_BITS == 32
3695 abi_ulong __unused1;
3696#endif
3697 abi_ulong msg_rtime;
3698#if TARGET_ABI_BITS == 32
3699 abi_ulong __unused2;
3700#endif
3701 abi_ulong msg_ctime;
3702#if TARGET_ABI_BITS == 32
3703 abi_ulong __unused3;
3704#endif
3705 abi_ulong __msg_cbytes;
3706 abi_ulong msg_qnum;
3707 abi_ulong msg_qbytes;
3708 abi_ulong msg_lspid;
3709 abi_ulong msg_lrpid;
3710 abi_ulong __unused4;
3711 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00003712};
3713
bellard579a97f2007-11-11 14:26:47 +00003714static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
3715 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00003716{
3717 struct target_msqid_ds *target_md;
3718
bellard579a97f2007-11-11 14:26:47 +00003719 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
3720 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003721 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
3722 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003723 host_md->msg_stime = tswapal(target_md->msg_stime);
3724 host_md->msg_rtime = tswapal(target_md->msg_rtime);
3725 host_md->msg_ctime = tswapal(target_md->msg_ctime);
3726 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
3727 host_md->msg_qnum = tswapal(target_md->msg_qnum);
3728 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
3729 host_md->msg_lspid = tswapal(target_md->msg_lspid);
3730 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003731 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00003732 return 0;
ths1bc012f2007-06-03 14:27:49 +00003733}
3734
bellard579a97f2007-11-11 14:26:47 +00003735static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
3736 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00003737{
3738 struct target_msqid_ds *target_md;
3739
bellard579a97f2007-11-11 14:26:47 +00003740 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
3741 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003742 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
3743 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003744 target_md->msg_stime = tswapal(host_md->msg_stime);
3745 target_md->msg_rtime = tswapal(host_md->msg_rtime);
3746 target_md->msg_ctime = tswapal(host_md->msg_ctime);
3747 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
3748 target_md->msg_qnum = tswapal(host_md->msg_qnum);
3749 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
3750 target_md->msg_lspid = tswapal(host_md->msg_lspid);
3751 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00003752 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00003753 return 0;
ths1bc012f2007-06-03 14:27:49 +00003754}
3755
aurel321c54ff92008-10-13 21:08:44 +00003756struct target_msginfo {
3757 int msgpool;
3758 int msgmap;
3759 int msgmax;
3760 int msgmnb;
3761 int msgmni;
3762 int msgssz;
3763 int msgtql;
3764 unsigned short int msgseg;
3765};
3766
3767static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
3768 struct msginfo *host_msginfo)
3769{
3770 struct target_msginfo *target_msginfo;
3771 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
3772 return -TARGET_EFAULT;
3773 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
3774 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
3775 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
3776 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
3777 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
3778 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
3779 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
3780 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
3781 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00003782 return 0;
aurel321c54ff92008-10-13 21:08:44 +00003783}
3784
3785static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00003786{
3787 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00003788 struct msginfo msginfo;
3789 abi_long ret = -TARGET_EINVAL;
3790
3791 cmd &= 0xff;
3792
3793 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00003794 case IPC_STAT:
3795 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00003796 case MSG_STAT:
3797 if (target_to_host_msqid_ds(&dsarg,ptr))
3798 return -TARGET_EFAULT;
3799 ret = get_errno(msgctl(msgid, cmd, &dsarg));
3800 if (host_to_target_msqid_ds(ptr,&dsarg))
3801 return -TARGET_EFAULT;
3802 break;
3803 case IPC_RMID:
3804 ret = get_errno(msgctl(msgid, cmd, NULL));
3805 break;
3806 case IPC_INFO:
3807 case MSG_INFO:
3808 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
3809 if (host_to_target_msginfo(ptr, &msginfo))
3810 return -TARGET_EFAULT;
3811 break;
ths1bc012f2007-06-03 14:27:49 +00003812 }
aurel321c54ff92008-10-13 21:08:44 +00003813
ths1bc012f2007-06-03 14:27:49 +00003814 return ret;
3815}
3816
3817struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00003818 abi_long mtype;
3819 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00003820};
3821
blueswir1992f48a2007-10-14 16:27:31 +00003822static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05003823 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003824{
3825 struct target_msgbuf *target_mb;
3826 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003827 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003828
Tom Mustaedcc5f92014-08-12 13:53:37 -05003829 if (msgsz < 0) {
3830 return -TARGET_EINVAL;
3831 }
3832
bellard579a97f2007-11-11 14:26:47 +00003833 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
3834 return -TARGET_EFAULT;
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303835 host_mb = g_try_malloc(msgsz + sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08003836 if (!host_mb) {
3837 unlock_user_struct(target_mb, msgp, 0);
3838 return -TARGET_ENOMEM;
3839 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003840 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00003841 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
Peter Maydell89f9fe42016-06-06 19:58:05 +01003842 ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05303843 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003844 unlock_user_struct(target_mb, msgp, 0);
3845
3846 return ret;
3847}
3848
blueswir1992f48a2007-10-14 16:27:31 +00003849static inline abi_long do_msgrcv(int msqid, abi_long msgp,
Peter Maydell99874f62016-05-20 19:00:56 +01003850 ssize_t msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00003851 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00003852{
3853 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00003854 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00003855 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00003856 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00003857
Peter Maydell99874f62016-05-20 19:00:56 +01003858 if (msgsz < 0) {
3859 return -TARGET_EINVAL;
3860 }
3861
bellard579a97f2007-11-11 14:26:47 +00003862 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
3863 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00003864
Peter Maydell415d8472016-05-20 19:00:57 +01003865 host_mb = g_try_malloc(msgsz + sizeof(long));
3866 if (!host_mb) {
3867 ret = -TARGET_ENOMEM;
3868 goto end;
3869 }
Peter Maydell89f9fe42016-06-06 19:58:05 +01003870 ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00003871
bellard579a97f2007-11-11 14:26:47 +00003872 if (ret > 0) {
3873 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
3874 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
3875 if (!target_mtext) {
3876 ret = -TARGET_EFAULT;
3877 goto end;
3878 }
aurel321c54ff92008-10-13 21:08:44 +00003879 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00003880 unlock_user(target_mtext, target_mtext_addr, ret);
3881 }
aurel321c54ff92008-10-13 21:08:44 +00003882
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003883 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00003884
bellard579a97f2007-11-11 14:26:47 +00003885end:
3886 if (target_mb)
3887 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02003888 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00003889 return ret;
3890}
3891
Riku Voipio88a8c982009-04-03 10:42:00 +03003892static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
3893 abi_ulong target_addr)
3894{
3895 struct target_shmid_ds *target_sd;
3896
3897 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
3898 return -TARGET_EFAULT;
3899 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
3900 return -TARGET_EFAULT;
3901 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3902 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
3903 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3904 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3905 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3906 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3907 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3908 unlock_user_struct(target_sd, target_addr, 0);
3909 return 0;
3910}
3911
3912static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
3913 struct shmid_ds *host_sd)
3914{
3915 struct target_shmid_ds *target_sd;
3916
3917 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
3918 return -TARGET_EFAULT;
3919 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
3920 return -TARGET_EFAULT;
3921 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
3922 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
3923 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
3924 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3925 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3926 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3927 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3928 unlock_user_struct(target_sd, target_addr, 1);
3929 return 0;
3930}
3931
3932struct target_shminfo {
3933 abi_ulong shmmax;
3934 abi_ulong shmmin;
3935 abi_ulong shmmni;
3936 abi_ulong shmseg;
3937 abi_ulong shmall;
3938};
3939
3940static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3941 struct shminfo *host_shminfo)
3942{
3943 struct target_shminfo *target_shminfo;
3944 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3945 return -TARGET_EFAULT;
3946 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3947 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3948 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3949 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3950 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3951 unlock_user_struct(target_shminfo, target_addr, 1);
3952 return 0;
3953}
3954
3955struct target_shm_info {
3956 int used_ids;
3957 abi_ulong shm_tot;
3958 abi_ulong shm_rss;
3959 abi_ulong shm_swp;
3960 abi_ulong swap_attempts;
3961 abi_ulong swap_successes;
3962};
3963
3964static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3965 struct shm_info *host_shm_info)
3966{
3967 struct target_shm_info *target_shm_info;
3968 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3969 return -TARGET_EFAULT;
3970 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3971 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3972 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3973 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3974 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3975 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3976 unlock_user_struct(target_shm_info, target_addr, 1);
3977 return 0;
3978}
3979
3980static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3981{
3982 struct shmid_ds dsarg;
3983 struct shminfo shminfo;
3984 struct shm_info shm_info;
3985 abi_long ret = -TARGET_EINVAL;
3986
3987 cmd &= 0xff;
3988
3989 switch(cmd) {
3990 case IPC_STAT:
3991 case IPC_SET:
3992 case SHM_STAT:
3993 if (target_to_host_shmid_ds(&dsarg, buf))
3994 return -TARGET_EFAULT;
3995 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3996 if (host_to_target_shmid_ds(buf, &dsarg))
3997 return -TARGET_EFAULT;
3998 break;
3999 case IPC_INFO:
4000 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
4001 if (host_to_target_shminfo(buf, &shminfo))
4002 return -TARGET_EFAULT;
4003 break;
4004 case SHM_INFO:
4005 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
4006 if (host_to_target_shm_info(buf, &shm_info))
4007 return -TARGET_EFAULT;
4008 break;
4009 case IPC_RMID:
4010 case SHM_LOCK:
4011 case SHM_UNLOCK:
4012 ret = get_errno(shmctl(shmid, cmd, NULL));
4013 break;
4014 }
4015
4016 return ret;
4017}
4018
4019static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
4020{
4021 abi_long raddr;
4022 void *host_raddr;
4023 struct shmid_ds shm_info;
4024 int i,ret;
4025
4026 /* find out the length of the shared memory segment */
4027 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
4028 if (is_error(ret)) {
4029 /* can't get length, bail out */
4030 return ret;
4031 }
4032
4033 mmap_lock();
4034
4035 if (shmaddr)
4036 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
4037 else {
4038 abi_ulong mmap_start;
4039
4040 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
4041
4042 if (mmap_start == -1) {
4043 errno = ENOMEM;
4044 host_raddr = (void *)-1;
4045 } else
4046 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
4047 }
4048
4049 if (host_raddr == (void *)-1) {
4050 mmap_unlock();
4051 return get_errno((long)host_raddr);
4052 }
4053 raddr=h2g((unsigned long)host_raddr);
4054
4055 page_set_flags(raddr, raddr + shm_info.shm_segsz,
4056 PAGE_VALID | PAGE_READ |
4057 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
4058
4059 for (i = 0; i < N_SHM_REGIONS; i++) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004060 if (!shm_regions[i].in_use) {
4061 shm_regions[i].in_use = true;
Riku Voipio88a8c982009-04-03 10:42:00 +03004062 shm_regions[i].start = raddr;
4063 shm_regions[i].size = shm_info.shm_segsz;
4064 break;
4065 }
4066 }
4067
4068 mmap_unlock();
4069 return raddr;
4070
4071}
4072
4073static inline abi_long do_shmdt(abi_ulong shmaddr)
4074{
4075 int i;
4076
4077 for (i = 0; i < N_SHM_REGIONS; ++i) {
Peter Maydellb6e17872016-02-09 15:57:11 +00004078 if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
4079 shm_regions[i].in_use = false;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09004080 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03004081 break;
4082 }
4083 }
4084
4085 return get_errno(shmdt(g2h(shmaddr)));
4086}
4087
aurel321c54ff92008-10-13 21:08:44 +00004088#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00004089/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00004090/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05004091static abi_long do_ipc(unsigned int call, abi_long first,
4092 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00004093 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00004094{
4095 int version;
blueswir1992f48a2007-10-14 16:27:31 +00004096 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00004097
4098 version = call >> 16;
4099 call &= 0xffff;
4100
4101 switch (call) {
thsfa294812007-02-02 22:05:00 +00004102 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00004103 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00004104 break;
4105
4106 case IPCOP_semget:
4107 ret = get_errno(semget(first, second, third));
4108 break;
4109
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004110 case IPCOP_semctl: {
4111 /* The semun argument to semctl is passed by value, so dereference the
4112 * ptr argument. */
4113 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05004114 get_user_ual(atptr, ptr);
Stefan Weild1c002b2015-02-08 15:40:58 +01004115 ret = do_semctl(first, second, third, atptr);
thsfa294812007-02-02 22:05:00 +00004116 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05004117 }
thsd96372e2007-02-02 22:05:44 +00004118
aurel321c54ff92008-10-13 21:08:44 +00004119 case IPCOP_msgget:
4120 ret = get_errno(msgget(first, second));
4121 break;
thsd96372e2007-02-02 22:05:44 +00004122
aurel321c54ff92008-10-13 21:08:44 +00004123 case IPCOP_msgsnd:
4124 ret = do_msgsnd(first, ptr, second, third);
4125 break;
thsd96372e2007-02-02 22:05:44 +00004126
aurel321c54ff92008-10-13 21:08:44 +00004127 case IPCOP_msgctl:
4128 ret = do_msgctl(first, second, ptr);
4129 break;
thsd96372e2007-02-02 22:05:44 +00004130
aurel321c54ff92008-10-13 21:08:44 +00004131 case IPCOP_msgrcv:
4132 switch (version) {
4133 case 0:
4134 {
4135 struct target_ipc_kludge {
4136 abi_long msgp;
4137 abi_long msgtyp;
4138 } *tmp;
thsd96372e2007-02-02 22:05:44 +00004139
aurel321c54ff92008-10-13 21:08:44 +00004140 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
4141 ret = -TARGET_EFAULT;
4142 break;
ths1bc012f2007-06-03 14:27:49 +00004143 }
aurel321c54ff92008-10-13 21:08:44 +00004144
Laurent Vivier79dd77d2012-12-20 11:00:11 +00004145 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00004146
4147 unlock_user_struct(tmp, ptr, 0);
4148 break;
4149 }
4150 default:
4151 ret = do_msgrcv(first, ptr, second, fifth, third);
4152 }
4153 break;
thsd96372e2007-02-02 22:05:44 +00004154
bellard8853f862004-02-22 14:57:26 +00004155 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03004156 switch (version) {
4157 default:
bellard5a4a8982007-11-11 17:39:18 +00004158 {
4159 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03004160 raddr = do_shmat(first, ptr, second);
4161 if (is_error(raddr))
4162 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00004163 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00004164 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03004165 break;
4166 }
4167 case 1:
4168 ret = -TARGET_EINVAL;
4169 break;
bellard5a4a8982007-11-11 17:39:18 +00004170 }
bellard8853f862004-02-22 14:57:26 +00004171 break;
4172 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03004173 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00004174 break;
4175
4176 case IPCOP_shmget:
4177 /* IPC_* flag values are the same on all linux platforms */
4178 ret = get_errno(shmget(first, second, third));
4179 break;
4180
4181 /* IPC_* and SHM_* command values are the same on all linux platforms */
4182 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01004183 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00004184 break;
4185 default:
j_mayer32407102007-09-26 23:01:49 +00004186 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00004187 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00004188 break;
4189 }
4190 return ret;
4191}
j_mayer32407102007-09-26 23:01:49 +00004192#endif
bellard8853f862004-02-22 14:57:26 +00004193
bellard31e31b82003-02-18 22:55:36 +00004194/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00004195
Blue Swirl001faf32009-05-13 17:53:17 +00004196#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00004197#define STRUCT_SPECIAL(name) STRUCT_ ## name,
4198enum {
4199#include "syscall_types.h"
Alexander Graf8be656b2015-05-06 23:47:32 +02004200STRUCT_MAX
bellard31e31b82003-02-18 22:55:36 +00004201};
4202#undef STRUCT
4203#undef STRUCT_SPECIAL
4204
Blue Swirl001faf32009-05-13 17:53:17 +00004205#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00004206#define STRUCT_SPECIAL(name)
4207#include "syscall_types.h"
4208#undef STRUCT
4209#undef STRUCT_SPECIAL
4210
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004211typedef struct IOCTLEntry IOCTLEntry;
4212
4213typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004214 int fd, int cmd, abi_long arg);
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004215
4216struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08004217 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00004218 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00004219 const char *name;
4220 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004221 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00004222 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004223};
bellard31e31b82003-02-18 22:55:36 +00004224
4225#define IOC_R 0x0001
4226#define IOC_W 0x0002
4227#define IOC_RW (IOC_R | IOC_W)
4228
4229#define MAX_STRUCT_SIZE 4096
4230
Peter Maydelldace20d2011-01-10 13:11:24 +00004231#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00004232/* So fiemap access checks don't overflow on 32 bit systems.
4233 * This is very slightly smaller than the limit imposed by
4234 * the underlying kernel.
4235 */
4236#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
4237 / sizeof(struct fiemap_extent))
4238
4239static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004240 int fd, int cmd, abi_long arg)
Peter Maydell285da2b2011-01-06 15:04:18 +00004241{
4242 /* The parameter for this ioctl is a struct fiemap followed
4243 * by an array of struct fiemap_extent whose size is set
4244 * in fiemap->fm_extent_count. The array is filled in by the
4245 * ioctl.
4246 */
4247 int target_size_in, target_size_out;
4248 struct fiemap *fm;
4249 const argtype *arg_type = ie->arg_type;
4250 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
4251 void *argptr, *p;
4252 abi_long ret;
4253 int i, extent_size = thunk_type_size(extent_arg_type, 0);
4254 uint32_t outbufsz;
4255 int free_fm = 0;
4256
4257 assert(arg_type[0] == TYPE_PTR);
4258 assert(ie->access == IOC_RW);
4259 arg_type++;
4260 target_size_in = thunk_type_size(arg_type, 0);
4261 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
4262 if (!argptr) {
4263 return -TARGET_EFAULT;
4264 }
4265 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4266 unlock_user(argptr, arg, 0);
4267 fm = (struct fiemap *)buf_temp;
4268 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
4269 return -TARGET_EINVAL;
4270 }
4271
4272 outbufsz = sizeof (*fm) +
4273 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
4274
4275 if (outbufsz > MAX_STRUCT_SIZE) {
4276 /* We can't fit all the extents into the fixed size buffer.
4277 * Allocate one that is large enough and use it instead.
4278 */
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304279 fm = g_try_malloc(outbufsz);
Peter Maydell285da2b2011-01-06 15:04:18 +00004280 if (!fm) {
4281 return -TARGET_ENOMEM;
4282 }
4283 memcpy(fm, buf_temp, sizeof(struct fiemap));
4284 free_fm = 1;
4285 }
4286 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
4287 if (!is_error(ret)) {
4288 target_size_out = target_size_in;
4289 /* An extent_count of 0 means we were only counting the extents
4290 * so there are no structs to copy
4291 */
4292 if (fm->fm_extent_count != 0) {
4293 target_size_out += fm->fm_mapped_extents * extent_size;
4294 }
4295 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
4296 if (!argptr) {
4297 ret = -TARGET_EFAULT;
4298 } else {
4299 /* Convert the struct fiemap */
4300 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
4301 if (fm->fm_extent_count != 0) {
4302 p = argptr + target_size_in;
4303 /* ...and then all the struct fiemap_extents */
4304 for (i = 0; i < fm->fm_mapped_extents; i++) {
4305 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
4306 THUNK_TARGET);
4307 p += extent_size;
4308 }
4309 }
4310 unlock_user(argptr, arg, target_size_out);
4311 }
4312 }
4313 if (free_fm) {
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05304314 g_free(fm);
Peter Maydell285da2b2011-01-06 15:04:18 +00004315 }
4316 return ret;
4317}
Peter Maydelldace20d2011-01-10 13:11:24 +00004318#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00004319
Laurent Vivier059c2f22011-03-30 00:12:12 +02004320static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004321 int fd, int cmd, abi_long arg)
Laurent Vivier059c2f22011-03-30 00:12:12 +02004322{
4323 const argtype *arg_type = ie->arg_type;
4324 int target_size;
4325 void *argptr;
4326 int ret;
4327 struct ifconf *host_ifconf;
4328 uint32_t outbufsz;
4329 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
4330 int target_ifreq_size;
4331 int nb_ifreq;
4332 int free_buf = 0;
4333 int i;
4334 int target_ifc_len;
4335 abi_long target_ifc_buf;
4336 int host_ifc_len;
4337 char *host_ifc_buf;
4338
4339 assert(arg_type[0] == TYPE_PTR);
4340 assert(ie->access == IOC_RW);
4341
4342 arg_type++;
4343 target_size = thunk_type_size(arg_type, 0);
4344
4345 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4346 if (!argptr)
4347 return -TARGET_EFAULT;
4348 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4349 unlock_user(argptr, arg, 0);
4350
4351 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
4352 target_ifc_len = host_ifconf->ifc_len;
4353 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
4354
4355 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
4356 nb_ifreq = target_ifc_len / target_ifreq_size;
4357 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
4358
4359 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
4360 if (outbufsz > MAX_STRUCT_SIZE) {
4361 /* We can't fit all the extents into the fixed size buffer.
4362 * Allocate one that is large enough and use it instead.
4363 */
4364 host_ifconf = malloc(outbufsz);
4365 if (!host_ifconf) {
4366 return -TARGET_ENOMEM;
4367 }
4368 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
4369 free_buf = 1;
4370 }
4371 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
4372
4373 host_ifconf->ifc_len = host_ifc_len;
4374 host_ifconf->ifc_buf = host_ifc_buf;
4375
4376 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
4377 if (!is_error(ret)) {
4378 /* convert host ifc_len to target ifc_len */
4379
4380 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
4381 target_ifc_len = nb_ifreq * target_ifreq_size;
4382 host_ifconf->ifc_len = target_ifc_len;
4383
4384 /* restore target ifc_buf */
4385
4386 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
4387
4388 /* copy struct ifconf to target user */
4389
4390 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4391 if (!argptr)
4392 return -TARGET_EFAULT;
4393 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
4394 unlock_user(argptr, arg, target_size);
4395
4396 /* copy ifreq[] to target user */
4397
4398 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
4399 for (i = 0; i < nb_ifreq ; i++) {
4400 thunk_convert(argptr + i * target_ifreq_size,
4401 host_ifc_buf + i * sizeof(struct ifreq),
4402 ifreq_arg_type, THUNK_TARGET);
4403 }
4404 unlock_user(argptr, target_ifc_buf, target_ifc_len);
4405 }
4406
4407 if (free_buf) {
4408 free(host_ifconf);
4409 }
4410
4411 return ret;
4412}
4413
Alexander Graf56e904e2012-01-31 18:42:06 +01004414static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004415 int cmd, abi_long arg)
Alexander Graf56e904e2012-01-31 18:42:06 +01004416{
4417 void *argptr;
4418 struct dm_ioctl *host_dm;
4419 abi_long guest_data;
4420 uint32_t guest_data_size;
4421 int target_size;
4422 const argtype *arg_type = ie->arg_type;
4423 abi_long ret;
4424 void *big_buf = NULL;
4425 char *host_data;
4426
4427 arg_type++;
4428 target_size = thunk_type_size(arg_type, 0);
4429 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4430 if (!argptr) {
4431 ret = -TARGET_EFAULT;
4432 goto out;
4433 }
4434 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4435 unlock_user(argptr, arg, 0);
4436
4437 /* buf_temp is too small, so fetch things into a bigger buffer */
4438 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
4439 memcpy(big_buf, buf_temp, target_size);
4440 buf_temp = big_buf;
4441 host_dm = big_buf;
4442
4443 guest_data = arg + host_dm->data_start;
4444 if ((guest_data - arg) < 0) {
4445 ret = -EINVAL;
4446 goto out;
4447 }
4448 guest_data_size = host_dm->data_size - host_dm->data_start;
4449 host_data = (char*)host_dm + host_dm->data_start;
4450
4451 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
4452 switch (ie->host_cmd) {
4453 case DM_REMOVE_ALL:
4454 case DM_LIST_DEVICES:
4455 case DM_DEV_CREATE:
4456 case DM_DEV_REMOVE:
4457 case DM_DEV_SUSPEND:
4458 case DM_DEV_STATUS:
4459 case DM_DEV_WAIT:
4460 case DM_TABLE_STATUS:
4461 case DM_TABLE_CLEAR:
4462 case DM_TABLE_DEPS:
4463 case DM_LIST_VERSIONS:
4464 /* no input data */
4465 break;
4466 case DM_DEV_RENAME:
4467 case DM_DEV_SET_GEOMETRY:
4468 /* data contains only strings */
4469 memcpy(host_data, argptr, guest_data_size);
4470 break;
4471 case DM_TARGET_MSG:
4472 memcpy(host_data, argptr, guest_data_size);
4473 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
4474 break;
4475 case DM_TABLE_LOAD:
4476 {
4477 void *gspec = argptr;
4478 void *cur_data = host_data;
4479 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4480 int spec_size = thunk_type_size(arg_type, 0);
4481 int i;
4482
4483 for (i = 0; i < host_dm->target_count; i++) {
4484 struct dm_target_spec *spec = cur_data;
4485 uint32_t next;
4486 int slen;
4487
4488 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
4489 slen = strlen((char*)gspec + spec_size) + 1;
4490 next = spec->next;
4491 spec->next = sizeof(*spec) + slen;
4492 strcpy((char*)&spec[1], gspec + spec_size);
4493 gspec += next;
4494 cur_data += spec->next;
4495 }
4496 break;
4497 }
4498 default:
4499 ret = -TARGET_EINVAL;
Chen Gang Sdec04732015-01-25 08:00:42 +08004500 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004501 goto out;
4502 }
4503 unlock_user(argptr, guest_data, 0);
4504
4505 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4506 if (!is_error(ret)) {
4507 guest_data = arg + host_dm->data_start;
4508 guest_data_size = host_dm->data_size - host_dm->data_start;
4509 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
4510 switch (ie->host_cmd) {
4511 case DM_REMOVE_ALL:
4512 case DM_DEV_CREATE:
4513 case DM_DEV_REMOVE:
4514 case DM_DEV_RENAME:
4515 case DM_DEV_SUSPEND:
4516 case DM_DEV_STATUS:
4517 case DM_TABLE_LOAD:
4518 case DM_TABLE_CLEAR:
4519 case DM_TARGET_MSG:
4520 case DM_DEV_SET_GEOMETRY:
4521 /* no return data */
4522 break;
4523 case DM_LIST_DEVICES:
4524 {
4525 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
4526 uint32_t remaining_data = guest_data_size;
4527 void *cur_data = argptr;
4528 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
4529 int nl_size = 12; /* can't use thunk_size due to alignment */
4530
4531 while (1) {
4532 uint32_t next = nl->next;
4533 if (next) {
4534 nl->next = nl_size + (strlen(nl->name) + 1);
4535 }
4536 if (remaining_data < nl->next) {
4537 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4538 break;
4539 }
4540 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
4541 strcpy(cur_data + nl_size, nl->name);
4542 cur_data += nl->next;
4543 remaining_data -= nl->next;
4544 if (!next) {
4545 break;
4546 }
4547 nl = (void*)nl + next;
4548 }
4549 break;
4550 }
4551 case DM_DEV_WAIT:
4552 case DM_TABLE_STATUS:
4553 {
4554 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
4555 void *cur_data = argptr;
4556 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
4557 int spec_size = thunk_type_size(arg_type, 0);
4558 int i;
4559
4560 for (i = 0; i < host_dm->target_count; i++) {
4561 uint32_t next = spec->next;
4562 int slen = strlen((char*)&spec[1]) + 1;
4563 spec->next = (cur_data - argptr) + spec_size + slen;
4564 if (guest_data_size < spec->next) {
4565 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4566 break;
4567 }
4568 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
4569 strcpy(cur_data + spec_size, (char*)&spec[1]);
4570 cur_data = argptr + spec->next;
4571 spec = (void*)host_dm + host_dm->data_start + next;
4572 }
4573 break;
4574 }
4575 case DM_TABLE_DEPS:
4576 {
4577 void *hdata = (void*)host_dm + host_dm->data_start;
4578 int count = *(uint32_t*)hdata;
4579 uint64_t *hdev = hdata + 8;
4580 uint64_t *gdev = argptr + 8;
4581 int i;
4582
4583 *(uint32_t*)argptr = tswap32(count);
4584 for (i = 0; i < count; i++) {
4585 *gdev = tswap64(*hdev);
4586 gdev++;
4587 hdev++;
4588 }
4589 break;
4590 }
4591 case DM_LIST_VERSIONS:
4592 {
4593 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
4594 uint32_t remaining_data = guest_data_size;
4595 void *cur_data = argptr;
4596 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
4597 int vers_size = thunk_type_size(arg_type, 0);
4598
4599 while (1) {
4600 uint32_t next = vers->next;
4601 if (next) {
4602 vers->next = vers_size + (strlen(vers->name) + 1);
4603 }
4604 if (remaining_data < vers->next) {
4605 host_dm->flags |= DM_BUFFER_FULL_FLAG;
4606 break;
4607 }
4608 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
4609 strcpy(cur_data + vers_size, vers->name);
4610 cur_data += vers->next;
4611 remaining_data -= vers->next;
4612 if (!next) {
4613 break;
4614 }
4615 vers = (void*)vers + next;
4616 }
4617 break;
4618 }
4619 default:
Chen Gang Sdec04732015-01-25 08:00:42 +08004620 unlock_user(argptr, guest_data, 0);
Alexander Graf56e904e2012-01-31 18:42:06 +01004621 ret = -TARGET_EINVAL;
4622 goto out;
4623 }
4624 unlock_user(argptr, guest_data, guest_data_size);
4625
4626 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4627 if (!argptr) {
4628 ret = -TARGET_EFAULT;
4629 goto out;
4630 }
4631 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4632 unlock_user(argptr, arg, target_size);
4633 }
4634out:
Stefan Weilad11ad72012-09-04 22:14:19 +02004635 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01004636 return ret;
4637}
4638
Alexander Grafa59b5e32014-08-22 13:15:50 +02004639static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004640 int cmd, abi_long arg)
Alexander Grafa59b5e32014-08-22 13:15:50 +02004641{
4642 void *argptr;
4643 int target_size;
4644 const argtype *arg_type = ie->arg_type;
4645 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
4646 abi_long ret;
4647
4648 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
4649 struct blkpg_partition host_part;
4650
4651 /* Read and convert blkpg */
4652 arg_type++;
4653 target_size = thunk_type_size(arg_type, 0);
4654 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4655 if (!argptr) {
4656 ret = -TARGET_EFAULT;
4657 goto out;
4658 }
4659 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4660 unlock_user(argptr, arg, 0);
4661
4662 switch (host_blkpg->op) {
4663 case BLKPG_ADD_PARTITION:
4664 case BLKPG_DEL_PARTITION:
4665 /* payload is struct blkpg_partition */
4666 break;
4667 default:
4668 /* Unknown opcode */
4669 ret = -TARGET_EINVAL;
4670 goto out;
4671 }
4672
4673 /* Read and convert blkpg->data */
4674 arg = (abi_long)(uintptr_t)host_blkpg->data;
4675 target_size = thunk_type_size(part_arg_type, 0);
4676 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4677 if (!argptr) {
4678 ret = -TARGET_EFAULT;
4679 goto out;
4680 }
4681 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
4682 unlock_user(argptr, arg, 0);
4683
4684 /* Swizzle the data pointer to our local copy and call! */
4685 host_blkpg->data = &host_part;
4686 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
4687
4688out:
4689 return ret;
4690}
4691
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004692static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004693 int fd, int cmd, abi_long arg)
Laurent Vivier7ff7b662013-07-02 14:04:12 +01004694{
4695 const argtype *arg_type = ie->arg_type;
4696 const StructEntry *se;
4697 const argtype *field_types;
4698 const int *dst_offsets, *src_offsets;
4699 int target_size;
4700 void *argptr;
4701 abi_ulong *target_rt_dev_ptr;
4702 unsigned long *host_rt_dev_ptr;
4703 abi_long ret;
4704 int i;
4705
4706 assert(ie->access == IOC_W);
4707 assert(*arg_type == TYPE_PTR);
4708 arg_type++;
4709 assert(*arg_type == TYPE_STRUCT);
4710 target_size = thunk_type_size(arg_type, 0);
4711 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4712 if (!argptr) {
4713 return -TARGET_EFAULT;
4714 }
4715 arg_type++;
4716 assert(*arg_type == (int)STRUCT_rtentry);
4717 se = struct_entries + *arg_type++;
4718 assert(se->convert[0] == NULL);
4719 /* convert struct here to be able to catch rt_dev string */
4720 field_types = se->field_types;
4721 dst_offsets = se->field_offsets[THUNK_HOST];
4722 src_offsets = se->field_offsets[THUNK_TARGET];
4723 for (i = 0; i < se->nb_fields; i++) {
4724 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
4725 assert(*field_types == TYPE_PTRVOID);
4726 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
4727 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
4728 if (*target_rt_dev_ptr != 0) {
4729 *host_rt_dev_ptr = (unsigned long)lock_user_string(
4730 tswapal(*target_rt_dev_ptr));
4731 if (!*host_rt_dev_ptr) {
4732 unlock_user(argptr, arg, 0);
4733 return -TARGET_EFAULT;
4734 }
4735 } else {
4736 *host_rt_dev_ptr = 0;
4737 }
4738 field_types++;
4739 continue;
4740 }
4741 field_types = thunk_convert(buf_temp + dst_offsets[i],
4742 argptr + src_offsets[i],
4743 field_types, THUNK_HOST);
4744 }
4745 unlock_user(argptr, arg, 0);
4746
4747 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4748 if (*host_rt_dev_ptr != 0) {
4749 unlock_user((void *)*host_rt_dev_ptr,
4750 *target_rt_dev_ptr, 0);
4751 }
4752 return ret;
4753}
4754
Paul Burtonca56f5b2014-06-22 11:25:47 +01004755static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
Laurent Vivier45c874e2015-06-16 00:35:28 +02004756 int fd, int cmd, abi_long arg)
Paul Burtonca56f5b2014-06-22 11:25:47 +01004757{
4758 int sig = target_to_host_signal(arg);
4759 return get_errno(ioctl(fd, ie->host_cmd, sig));
4760}
4761
blueswir19f106a72008-10-05 10:52:52 +00004762static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00004763#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004764 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
4765#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
4766 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00004767#include "ioctls.h"
4768 { 0, 0, },
4769};
4770
pbrook53a59602006-03-25 19:31:22 +00004771/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00004772/* do_ioctl() Must return target values and target errnos. */
Laurent Vivier45c874e2015-06-16 00:35:28 +02004773static abi_long do_ioctl(int fd, int cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00004774{
4775 const IOCTLEntry *ie;
4776 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00004777 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00004778 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00004779 int target_size;
4780 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00004781
4782 ie = ioctl_entries;
4783 for(;;) {
4784 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00004785 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00004786 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004787 }
4788 if (ie->target_cmd == cmd)
4789 break;
4790 ie++;
4791 }
4792 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00004793#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00004794 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00004795#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00004796 if (ie->do_ioctl) {
4797 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
4798 }
4799
bellard31e31b82003-02-18 22:55:36 +00004800 switch(arg_type[0]) {
4801 case TYPE_NULL:
4802 /* no argument */
4803 ret = get_errno(ioctl(fd, ie->host_cmd));
4804 break;
4805 case TYPE_PTRVOID:
4806 case TYPE_INT:
bellard31e31b82003-02-18 22:55:36 +00004807 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
4808 break;
4809 case TYPE_PTR:
4810 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00004811 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00004812 switch(ie->access) {
4813 case IOC_R:
4814 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4815 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004816 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4817 if (!argptr)
4818 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004819 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4820 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004821 }
4822 break;
4823 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00004824 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4825 if (!argptr)
4826 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004827 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4828 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004829 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4830 break;
4831 default:
4832 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00004833 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
4834 if (!argptr)
4835 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004836 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
4837 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00004838 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
4839 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00004840 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
4841 if (!argptr)
4842 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004843 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
4844 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00004845 }
4846 break;
4847 }
4848 break;
4849 default:
j_mayer32407102007-09-26 23:01:49 +00004850 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
4851 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00004852 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00004853 break;
4854 }
4855 return ret;
4856}
4857
blueswir1b39bc502008-10-05 10:51:10 +00004858static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004859 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
4860 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
4861 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
4862 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
4863 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
4864 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
4865 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
4866 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
4867 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
4868 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
4869 { TARGET_IXON, TARGET_IXON, IXON, IXON },
4870 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
4871 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
4872 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
4873 { 0, 0, 0, 0 }
4874};
4875
blueswir1b39bc502008-10-05 10:51:10 +00004876static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004877 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
4878 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
4879 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
4880 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
4881 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
4882 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
4883 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
4884 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
4885 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
4886 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
4887 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
4888 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
4889 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
4890 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
4891 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
4892 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
4893 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
4894 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
4895 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
4896 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
4897 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
4898 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
4899 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
4900 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
4901 { 0, 0, 0, 0 }
4902};
4903
blueswir1b39bc502008-10-05 10:51:10 +00004904static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004905 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
4906 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
4907 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
4908 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
4909 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
4910 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
4911 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
4912 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
4913 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
4914 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
4915 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
4916 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
4917 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
4918 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
4919 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
4920 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
4921 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
4922 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
4923 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
4924 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
4925 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
4926 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4927 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4928 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4929 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4930 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4931 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4932 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4933 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4934 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4935 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4936 { 0, 0, 0, 0 }
4937};
4938
blueswir1b39bc502008-10-05 10:51:10 +00004939static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004940 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4941 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4942 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4943 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4944 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4945 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4946 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4947 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4948 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4949 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4950 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4951 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4952 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4953 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4954 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4955 { 0, 0, 0, 0 }
4956};
4957
4958static void target_to_host_termios (void *dst, const void *src)
4959{
4960 struct host_termios *host = dst;
4961 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004962
ths5fafdf22007-09-16 21:08:06 +00004963 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004964 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004965 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004966 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004967 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004968 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004969 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004970 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4971 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004972
Arnaud Patard44607122009-04-21 17:39:08 +03004973 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004974 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4975 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004976 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004977 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004978 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004979 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004980 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004981 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004982 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004983 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4984 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004985 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4986 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4987 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4988 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4989 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004990 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004991}
ths3b46e622007-09-17 08:09:54 +00004992
bellard31e31b82003-02-18 22:55:36 +00004993static void host_to_target_termios (void *dst, const void *src)
4994{
4995 struct target_termios *target = dst;
4996 const struct host_termios *host = src;
4997
ths5fafdf22007-09-16 21:08:06 +00004998 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004999 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005000 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00005001 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005002 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00005003 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00005004 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00005005 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
5006 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00005007
Arnaud Patard44607122009-04-21 17:39:08 +03005008 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00005009 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
5010 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
5011 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
5012 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
5013 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
5014 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
5015 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
5016 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
5017 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
5018 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
5019 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
5020 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
5021 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
5022 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
5023 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
5024 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
5025 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
5026}
5027
blueswir18e853dc2008-10-05 10:49:32 +00005028static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00005029 .convert = { host_to_target_termios, target_to_host_termios },
5030 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
5031 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
5032};
5033
bellard5286db72003-06-05 00:57:30 +00005034static bitmask_transtbl mmap_flags_tbl[] = {
5035 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
5036 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
5037 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
5038 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
5039 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
5040 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
5041 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
5042 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01005043 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
5044 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00005045 { 0, 0, 0, 0 }
5046};
5047
bellard2ab83ea2003-06-15 19:56:46 +00005048#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00005049
5050/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00005051static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00005052
bellard03acab62007-11-11 14:57:14 +00005053static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005054{
5055 int size;
pbrook53a59602006-03-25 19:31:22 +00005056 void *p;
bellard6dbad632003-03-16 18:05:05 +00005057
5058 if (!ldt_table)
5059 return 0;
5060 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
5061 if (size > bytecount)
5062 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00005063 p = lock_user(VERIFY_WRITE, ptr, size, 0);
5064 if (!p)
bellard03acab62007-11-11 14:57:14 +00005065 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00005066 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00005067 memcpy(p, ldt_table, size);
5068 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00005069 return size;
5070}
5071
5072/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00005073static abi_long write_ldt(CPUX86State *env,
5074 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00005075{
5076 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00005077 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00005078 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00005079 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00005080 uint32_t *lp, entry_1, entry_2;
5081
5082 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00005083 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00005084 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00005085 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00005086 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005087 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00005088 ldt_info.limit = tswap32(target_ldt_info->limit);
5089 ldt_info.flags = tswap32(target_ldt_info->flags);
5090 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00005091
bellard6dbad632003-03-16 18:05:05 +00005092 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00005093 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005094 seg_32bit = ldt_info.flags & 1;
5095 contents = (ldt_info.flags >> 1) & 3;
5096 read_exec_only = (ldt_info.flags >> 3) & 1;
5097 limit_in_pages = (ldt_info.flags >> 4) & 1;
5098 seg_not_present = (ldt_info.flags >> 5) & 1;
5099 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00005100#ifdef TARGET_ABI32
5101 lm = 0;
5102#else
5103 lm = (ldt_info.flags >> 7) & 1;
5104#endif
bellard6dbad632003-03-16 18:05:05 +00005105 if (contents == 3) {
5106 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00005107 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005108 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00005109 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00005110 }
5111 /* allocate the LDT */
5112 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00005113 env->ldt.base = target_mmap(0,
5114 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
5115 PROT_READ|PROT_WRITE,
5116 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
5117 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00005118 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00005119 memset(g2h(env->ldt.base), 0,
5120 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00005121 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00005122 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00005123 }
5124
5125 /* NOTE: same code as Linux kernel */
5126 /* Allow LDTs to be cleared by the user. */
5127 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5128 if (oldmode ||
5129 (contents == 0 &&
5130 read_exec_only == 1 &&
5131 seg_32bit == 0 &&
5132 limit_in_pages == 0 &&
5133 seg_not_present == 1 &&
5134 useable == 0 )) {
5135 entry_1 = 0;
5136 entry_2 = 0;
5137 goto install;
5138 }
5139 }
ths3b46e622007-09-17 08:09:54 +00005140
bellard6dbad632003-03-16 18:05:05 +00005141 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5142 (ldt_info.limit & 0x0ffff);
5143 entry_2 = (ldt_info.base_addr & 0xff000000) |
5144 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5145 (ldt_info.limit & 0xf0000) |
5146 ((read_exec_only ^ 1) << 9) |
5147 (contents << 10) |
5148 ((seg_not_present ^ 1) << 15) |
5149 (seg_32bit << 22) |
5150 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00005151 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00005152 0x7000;
5153 if (!oldmode)
5154 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00005155
bellard6dbad632003-03-16 18:05:05 +00005156 /* Install the new entry ... */
5157install:
5158 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
5159 lp[0] = tswap32(entry_1);
5160 lp[1] = tswap32(entry_2);
5161 return 0;
5162}
5163
5164/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00005165static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
5166 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00005167{
bellard03acab62007-11-11 14:57:14 +00005168 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00005169
bellard6dbad632003-03-16 18:05:05 +00005170 switch (func) {
5171 case 0:
5172 ret = read_ldt(ptr, bytecount);
5173 break;
5174 case 1:
5175 ret = write_ldt(env, ptr, bytecount, 1);
5176 break;
5177 case 0x11:
5178 ret = write_ldt(env, ptr, bytecount, 0);
5179 break;
bellard03acab62007-11-11 14:57:14 +00005180 default:
5181 ret = -TARGET_ENOSYS;
5182 break;
bellard6dbad632003-03-16 18:05:05 +00005183 }
5184 return ret;
5185}
bellard1b6b0292003-03-22 17:31:38 +00005186
blueswir14583f582008-08-24 10:35:55 +00005187#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01005188abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005189{
5190 uint64_t *gdt_table = g2h(env->gdt.base);
5191 struct target_modify_ldt_ldt_s ldt_info;
5192 struct target_modify_ldt_ldt_s *target_ldt_info;
5193 int seg_32bit, contents, read_exec_only, limit_in_pages;
5194 int seg_not_present, useable, lm;
5195 uint32_t *lp, entry_1, entry_2;
5196 int i;
5197
5198 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5199 if (!target_ldt_info)
5200 return -TARGET_EFAULT;
5201 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005202 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00005203 ldt_info.limit = tswap32(target_ldt_info->limit);
5204 ldt_info.flags = tswap32(target_ldt_info->flags);
5205 if (ldt_info.entry_number == -1) {
5206 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
5207 if (gdt_table[i] == 0) {
5208 ldt_info.entry_number = i;
5209 target_ldt_info->entry_number = tswap32(i);
5210 break;
5211 }
5212 }
5213 }
5214 unlock_user_struct(target_ldt_info, ptr, 1);
5215
5216 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
5217 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
5218 return -TARGET_EINVAL;
5219 seg_32bit = ldt_info.flags & 1;
5220 contents = (ldt_info.flags >> 1) & 3;
5221 read_exec_only = (ldt_info.flags >> 3) & 1;
5222 limit_in_pages = (ldt_info.flags >> 4) & 1;
5223 seg_not_present = (ldt_info.flags >> 5) & 1;
5224 useable = (ldt_info.flags >> 6) & 1;
5225#ifdef TARGET_ABI32
5226 lm = 0;
5227#else
5228 lm = (ldt_info.flags >> 7) & 1;
5229#endif
5230
5231 if (contents == 3) {
5232 if (seg_not_present == 0)
5233 return -TARGET_EINVAL;
5234 }
5235
5236 /* NOTE: same code as Linux kernel */
5237 /* Allow LDTs to be cleared by the user. */
5238 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
5239 if ((contents == 0 &&
5240 read_exec_only == 1 &&
5241 seg_32bit == 0 &&
5242 limit_in_pages == 0 &&
5243 seg_not_present == 1 &&
5244 useable == 0 )) {
5245 entry_1 = 0;
5246 entry_2 = 0;
5247 goto install;
5248 }
5249 }
5250
5251 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
5252 (ldt_info.limit & 0x0ffff);
5253 entry_2 = (ldt_info.base_addr & 0xff000000) |
5254 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
5255 (ldt_info.limit & 0xf0000) |
5256 ((read_exec_only ^ 1) << 9) |
5257 (contents << 10) |
5258 ((seg_not_present ^ 1) << 15) |
5259 (seg_32bit << 22) |
5260 (limit_in_pages << 23) |
5261 (useable << 20) |
5262 (lm << 21) |
5263 0x7000;
5264
5265 /* Install the new entry ... */
5266install:
5267 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
5268 lp[0] = tswap32(entry_1);
5269 lp[1] = tswap32(entry_2);
5270 return 0;
5271}
5272
blueswir18fcd3692008-08-17 20:26:25 +00005273static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00005274{
5275 struct target_modify_ldt_ldt_s *target_ldt_info;
5276 uint64_t *gdt_table = g2h(env->gdt.base);
5277 uint32_t base_addr, limit, flags;
5278 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
5279 int seg_not_present, useable, lm;
5280 uint32_t *lp, entry_1, entry_2;
5281
5282 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
5283 if (!target_ldt_info)
5284 return -TARGET_EFAULT;
5285 idx = tswap32(target_ldt_info->entry_number);
5286 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
5287 idx > TARGET_GDT_ENTRY_TLS_MAX) {
5288 unlock_user_struct(target_ldt_info, ptr, 1);
5289 return -TARGET_EINVAL;
5290 }
5291 lp = (uint32_t *)(gdt_table + idx);
5292 entry_1 = tswap32(lp[0]);
5293 entry_2 = tswap32(lp[1]);
5294
5295 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
5296 contents = (entry_2 >> 10) & 3;
5297 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
5298 seg_32bit = (entry_2 >> 22) & 1;
5299 limit_in_pages = (entry_2 >> 23) & 1;
5300 useable = (entry_2 >> 20) & 1;
5301#ifdef TARGET_ABI32
5302 lm = 0;
5303#else
5304 lm = (entry_2 >> 21) & 1;
5305#endif
5306 flags = (seg_32bit << 0) | (contents << 1) |
5307 (read_exec_only << 3) | (limit_in_pages << 4) |
5308 (seg_not_present << 5) | (useable << 6) | (lm << 7);
5309 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
5310 base_addr = (entry_1 >> 16) |
5311 (entry_2 & 0xff000000) |
5312 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005313 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00005314 target_ldt_info->limit = tswap32(limit);
5315 target_ldt_info->flags = tswap32(flags);
5316 unlock_user_struct(target_ldt_info, ptr, 1);
5317 return 0;
5318}
blueswir14583f582008-08-24 10:35:55 +00005319#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00005320
bellardd2fd1af2007-11-14 18:08:56 +00005321#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01005322abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00005323{
Juan Quintela1add8692011-06-16 17:37:09 +01005324 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00005325 abi_ulong val;
5326 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01005327
bellardd2fd1af2007-11-14 18:08:56 +00005328 switch(code) {
5329 case TARGET_ARCH_SET_GS:
5330 case TARGET_ARCH_SET_FS:
5331 if (code == TARGET_ARCH_SET_GS)
5332 idx = R_GS;
5333 else
5334 idx = R_FS;
5335 cpu_x86_load_seg(env, idx, 0);
5336 env->segs[idx].base = addr;
5337 break;
5338 case TARGET_ARCH_GET_GS:
5339 case TARGET_ARCH_GET_FS:
5340 if (code == TARGET_ARCH_GET_GS)
5341 idx = R_GS;
5342 else
5343 idx = R_FS;
5344 val = env->segs[idx].base;
5345 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01005346 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00005347 break;
5348 default:
5349 ret = -TARGET_EINVAL;
5350 break;
5351 }
Juan Quintela1add8692011-06-16 17:37:09 +01005352 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00005353}
5354#endif
5355
bellard2ab83ea2003-06-15 19:56:46 +00005356#endif /* defined(TARGET_I386) */
5357
Riku Voipio05098a92011-03-04 15:27:29 +02005358#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00005359
pbrookd865bab2008-06-07 22:12:17 +00005360
5361static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
5362typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01005363 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00005364 pthread_mutex_t mutex;
5365 pthread_cond_t cond;
5366 pthread_t thread;
5367 uint32_t tid;
5368 abi_ulong child_tidptr;
5369 abi_ulong parent_tidptr;
5370 sigset_t sigmask;
5371} new_thread_info;
5372
5373static void *clone_func(void *arg)
5374{
5375 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005376 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01005377 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005378 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00005379
Emilio G. Cota70903762015-08-23 20:23:41 -04005380 rcu_register_thread();
pbrookd865bab2008-06-07 22:12:17 +00005381 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01005382 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02005383 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02005384 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005385 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01005386 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005387 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00005388 if (info->child_tidptr)
5389 put_user_u32(info->tid, info->child_tidptr);
5390 if (info->parent_tidptr)
5391 put_user_u32(info->tid, info->parent_tidptr);
5392 /* Enable signals. */
5393 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
5394 /* Signal to the parent that we're ready. */
5395 pthread_mutex_lock(&info->mutex);
5396 pthread_cond_broadcast(&info->cond);
5397 pthread_mutex_unlock(&info->mutex);
5398 /* Wait until the parent has finshed initializing the tls state. */
5399 pthread_mutex_lock(&clone_lock);
5400 pthread_mutex_unlock(&clone_lock);
5401 cpu_loop(env);
5402 /* never exits */
5403 return NULL;
5404}
bellard1b6b0292003-03-22 17:31:38 +00005405
ths0da46a62007-10-20 20:23:07 +00005406/* do_fork() Must return host values and target errnos (unlike most
5407 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01005408static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00005409 abi_ulong parent_tidptr, target_ulong newtls,
5410 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00005411{
Andreas Färber0429a972013-08-26 18:14:44 +02005412 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00005413 int ret;
bellard5cd43932003-03-29 16:54:36 +00005414 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02005415 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01005416 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00005417 unsigned int nptl_flags;
5418 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00005419
balrog436d1242008-09-21 02:39:45 +00005420 /* Emulate vfork() with fork() */
5421 if (flags & CLONE_VFORK)
5422 flags &= ~(CLONE_VFORK | CLONE_VM);
5423
bellard1b6b0292003-03-22 17:31:38 +00005424 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02005425 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005426 new_thread_info info;
5427 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01005428
Markus Armbrusterc78d65e2015-09-14 13:53:03 +02005429 ts = g_new0(TaskState, 1);
pbrook624f7972008-05-31 16:11:38 +00005430 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00005431 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00005432 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00005433 /* Init regs that differ from the parent. */
5434 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02005435 new_cpu = ENV_GET_CPU(new_env);
5436 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03005437 ts->bprm = parent_ts->bprm;
5438 ts->info = parent_ts->info;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005439 ts->signal_mask = parent_ts->signal_mask;
pbrookd865bab2008-06-07 22:12:17 +00005440 nptl_flags = flags;
5441 flags &= ~CLONE_NPTL_FLAGS2;
5442
pbrookc2764712009-03-07 15:24:59 +00005443 if (nptl_flags & CLONE_CHILD_CLEARTID) {
5444 ts->child_tidptr = child_tidptr;
5445 }
5446
pbrookd865bab2008-06-07 22:12:17 +00005447 if (nptl_flags & CLONE_SETTLS)
5448 cpu_set_tls (new_env, newtls);
5449
5450 /* Grab a mutex so that thread setup appears atomic. */
5451 pthread_mutex_lock(&clone_lock);
5452
5453 memset(&info, 0, sizeof(info));
5454 pthread_mutex_init(&info.mutex, NULL);
5455 pthread_mutex_lock(&info.mutex);
5456 pthread_cond_init(&info.cond, NULL);
5457 info.env = new_env;
5458 if (nptl_flags & CLONE_CHILD_SETTID)
5459 info.child_tidptr = child_tidptr;
5460 if (nptl_flags & CLONE_PARENT_SETTID)
5461 info.parent_tidptr = parent_tidptr;
5462
5463 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07005464 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
5465 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00005466 /* It is not safe to deliver signals until the child has finished
5467 initializing, so temporarily block all signals. */
5468 sigfillset(&sigmask);
5469 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
5470
5471 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00005472 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00005473
5474 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
5475 pthread_attr_destroy(&attr);
5476 if (ret == 0) {
5477 /* Wait for the child to initialize. */
5478 pthread_cond_wait(&info.cond, &info.mutex);
5479 ret = info.tid;
5480 if (flags & CLONE_PARENT_SETTID)
5481 put_user_u32(ret, parent_tidptr);
5482 } else {
5483 ret = -1;
5484 }
5485 pthread_mutex_unlock(&info.mutex);
5486 pthread_cond_destroy(&info.cond);
5487 pthread_mutex_destroy(&info.mutex);
5488 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00005489 } else {
5490 /* if no CLONE_VM, we consider it is a fork */
Timothy E Baldwin93b4eff2015-08-31 00:26:21 +01005491 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
5492 return -TARGET_EINVAL;
5493 }
Timothy E Baldwin7d92d342016-05-27 15:51:58 +01005494
5495 if (block_signals()) {
5496 return -TARGET_ERESTARTSYS;
5497 }
5498
pbrookd865bab2008-06-07 22:12:17 +00005499 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00005500 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00005501 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00005502 /* Child Process. */
Paolo Bonzinia59629f2015-03-31 13:01:05 +02005503 rcu_after_fork();
pbrookd865bab2008-06-07 22:12:17 +00005504 cpu_clone_regs(env, newsp);
5505 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00005506 /* There is a race condition here. The parent process could
5507 theoretically read the TID in the child process before the child
5508 tid is set. This would require using either ptrace
5509 (not implemented) or having *_tidptr to point at a shared memory
5510 mapping. We can't repeat the spinlock hack used above because
5511 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00005512 if (flags & CLONE_CHILD_SETTID)
5513 put_user_u32(gettid(), child_tidptr);
5514 if (flags & CLONE_PARENT_SETTID)
5515 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02005516 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00005517 if (flags & CLONE_SETTLS)
5518 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00005519 if (flags & CLONE_CHILD_CLEARTID)
5520 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00005521 } else {
5522 fork_end(0);
5523 }
bellard1b6b0292003-03-22 17:31:38 +00005524 }
5525 return ret;
5526}
5527
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005528/* warning : doesn't handle linux specific flags... */
5529static int target_to_host_fcntl_cmd(int cmd)
5530{
5531 switch(cmd) {
5532 case TARGET_F_DUPFD:
5533 case TARGET_F_GETFD:
5534 case TARGET_F_SETFD:
5535 case TARGET_F_GETFL:
5536 case TARGET_F_SETFL:
5537 return cmd;
5538 case TARGET_F_GETLK:
5539 return F_GETLK;
5540 case TARGET_F_SETLK:
5541 return F_SETLK;
5542 case TARGET_F_SETLKW:
5543 return F_SETLKW;
5544 case TARGET_F_GETOWN:
5545 return F_GETOWN;
5546 case TARGET_F_SETOWN:
5547 return F_SETOWN;
5548 case TARGET_F_GETSIG:
5549 return F_GETSIG;
5550 case TARGET_F_SETSIG:
5551 return F_SETSIG;
5552#if TARGET_ABI_BITS == 32
5553 case TARGET_F_GETLK64:
5554 return F_GETLK64;
5555 case TARGET_F_SETLK64:
5556 return F_SETLK64;
5557 case TARGET_F_SETLKW64:
5558 return F_SETLKW64;
5559#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005560 case TARGET_F_SETLEASE:
5561 return F_SETLEASE;
5562 case TARGET_F_GETLEASE:
5563 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04005564#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005565 case TARGET_F_DUPFD_CLOEXEC:
5566 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04005567#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005568 case TARGET_F_NOTIFY:
5569 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005570#ifdef F_GETOWN_EX
5571 case TARGET_F_GETOWN_EX:
5572 return F_GETOWN_EX;
5573#endif
5574#ifdef F_SETOWN_EX
5575 case TARGET_F_SETOWN_EX:
5576 return F_SETOWN_EX;
5577#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005578 default:
5579 return -TARGET_EINVAL;
5580 }
5581 return -TARGET_EINVAL;
5582}
5583
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005584#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
5585static const bitmask_transtbl flock_tbl[] = {
5586 TRANSTBL_CONVERT(F_RDLCK),
5587 TRANSTBL_CONVERT(F_WRLCK),
5588 TRANSTBL_CONVERT(F_UNLCK),
5589 TRANSTBL_CONVERT(F_EXLCK),
5590 TRANSTBL_CONVERT(F_SHLCK),
5591 { 0, 0, 0, 0 }
5592};
5593
blueswir1992f48a2007-10-14 16:27:31 +00005594static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00005595{
5596 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00005597 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00005598 struct flock64 fl64;
5599 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005600#ifdef F_GETOWN_EX
5601 struct f_owner_ex fox;
5602 struct target_f_owner_ex *target_fox;
5603#endif
blueswir1992f48a2007-10-14 16:27:31 +00005604 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005605 int host_cmd = target_to_host_fcntl_cmd(cmd);
5606
5607 if (host_cmd == -TARGET_EINVAL)
5608 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00005609
bellard7775e9e2003-05-14 22:46:48 +00005610 switch(cmd) {
5611 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00005612 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
5613 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005614 fl.l_type =
5615 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00005616 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005617 fl.l_start = tswapal(target_fl->l_start);
5618 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005619 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00005620 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005621 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00005622 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00005623 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
5624 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005625 target_fl->l_type =
5626 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00005627 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005628 target_fl->l_start = tswapal(fl.l_start);
5629 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005630 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00005631 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00005632 }
5633 break;
ths3b46e622007-09-17 08:09:54 +00005634
bellard7775e9e2003-05-14 22:46:48 +00005635 case TARGET_F_SETLK:
5636 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00005637 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
5638 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005639 fl.l_type =
5640 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00005641 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005642 fl.l_start = tswapal(target_fl->l_start);
5643 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005644 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00005645 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005646 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00005647 break;
ths3b46e622007-09-17 08:09:54 +00005648
bellard7775e9e2003-05-14 22:46:48 +00005649 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00005650 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
5651 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005652 fl64.l_type =
5653 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00005654 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005655 fl64.l_start = tswap64(target_fl64->l_start);
5656 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005657 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00005658 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005659 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00005660 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00005661 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
5662 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005663 target_fl64->l_type =
5664 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00005665 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005666 target_fl64->l_start = tswap64(fl64.l_start);
5667 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005668 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00005669 unlock_user_struct(target_fl64, arg, 1);
5670 }
bellard9ee1fa22007-11-11 15:11:19 +00005671 break;
bellard7775e9e2003-05-14 22:46:48 +00005672 case TARGET_F_SETLK64:
5673 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00005674 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
5675 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01005676 fl64.l_type =
5677 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00005678 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005679 fl64.l_start = tswap64(target_fl64->l_start);
5680 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005681 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00005682 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005683 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00005684 break;
5685
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005686 case TARGET_F_GETFL:
5687 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00005688 if (ret >= 0) {
5689 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
5690 }
bellardffa65c32004-01-04 23:57:22 +00005691 break;
5692
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005693 case TARGET_F_SETFL:
5694 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
5695 break;
5696
Andreas Schwab8d5d3002014-03-07 15:24:08 +01005697#ifdef F_GETOWN_EX
5698 case TARGET_F_GETOWN_EX:
5699 ret = get_errno(fcntl(fd, host_cmd, &fox));
5700 if (ret >= 0) {
5701 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
5702 return -TARGET_EFAULT;
5703 target_fox->type = tswap32(fox.type);
5704 target_fox->pid = tswap32(fox.pid);
5705 unlock_user_struct(target_fox, arg, 1);
5706 }
5707 break;
5708#endif
5709
5710#ifdef F_SETOWN_EX
5711 case TARGET_F_SETOWN_EX:
5712 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
5713 return -TARGET_EFAULT;
5714 fox.type = tswap32(target_fox->type);
5715 fox.pid = tswap32(target_fox->pid);
5716 unlock_user_struct(target_fox, arg, 0);
5717 ret = get_errno(fcntl(fd, host_cmd, &fox));
5718 break;
5719#endif
5720
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005721 case TARGET_F_SETOWN:
5722 case TARGET_F_GETOWN:
5723 case TARGET_F_SETSIG:
5724 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02005725 case TARGET_F_SETLEASE:
5726 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02005727 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00005728 break;
5729
bellard7775e9e2003-05-14 22:46:48 +00005730 default:
bellard9ee1fa22007-11-11 15:11:19 +00005731 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00005732 break;
5733 }
5734 return ret;
5735}
5736
bellard67867302003-11-23 17:05:30 +00005737#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00005738
bellard67867302003-11-23 17:05:30 +00005739static inline int high2lowuid(int uid)
5740{
5741 if (uid > 65535)
5742 return 65534;
5743 else
5744 return uid;
5745}
5746
5747static inline int high2lowgid(int gid)
5748{
5749 if (gid > 65535)
5750 return 65534;
5751 else
5752 return gid;
5753}
5754
5755static inline int low2highuid(int uid)
5756{
5757 if ((int16_t)uid == -1)
5758 return -1;
5759 else
5760 return uid;
5761}
5762
5763static inline int low2highgid(int gid)
5764{
5765 if ((int16_t)gid == -1)
5766 return -1;
5767 else
5768 return gid;
5769}
Riku Voipio0c866a72011-04-18 15:23:06 +03005770static inline int tswapid(int id)
5771{
5772 return tswap16(id);
5773}
Peter Maydell76ca3102014-03-02 19:36:41 +00005774
5775#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
5776
Riku Voipio0c866a72011-04-18 15:23:06 +03005777#else /* !USE_UID16 */
5778static inline int high2lowuid(int uid)
5779{
5780 return uid;
5781}
5782static inline int high2lowgid(int gid)
5783{
5784 return gid;
5785}
5786static inline int low2highuid(int uid)
5787{
5788 return uid;
5789}
5790static inline int low2highgid(int gid)
5791{
5792 return gid;
5793}
5794static inline int tswapid(int id)
5795{
5796 return tswap32(id);
5797}
Peter Maydell76ca3102014-03-02 19:36:41 +00005798
5799#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
5800
bellard67867302003-11-23 17:05:30 +00005801#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00005802
Peter Maydellfd6f7792016-03-01 16:33:02 +00005803/* We must do direct syscalls for setting UID/GID, because we want to
5804 * implement the Linux system call semantics of "change only for this thread",
5805 * not the libc/POSIX semantics of "change for all threads in process".
5806 * (See http://ewontfix.com/17/ for more details.)
5807 * We use the 32-bit version of the syscalls if present; if it is not
5808 * then either the host architecture supports 32-bit UIDs natively with
5809 * the standard syscall, or the 16-bit UID is the best we can do.
5810 */
5811#ifdef __NR_setuid32
5812#define __NR_sys_setuid __NR_setuid32
5813#else
5814#define __NR_sys_setuid __NR_setuid
5815#endif
5816#ifdef __NR_setgid32
5817#define __NR_sys_setgid __NR_setgid32
5818#else
5819#define __NR_sys_setgid __NR_setgid
5820#endif
5821#ifdef __NR_setresuid32
5822#define __NR_sys_setresuid __NR_setresuid32
5823#else
5824#define __NR_sys_setresuid __NR_setresuid
5825#endif
5826#ifdef __NR_setresgid32
5827#define __NR_sys_setresgid __NR_setresgid32
5828#else
5829#define __NR_sys_setresgid __NR_setresgid
5830#endif
5831
5832_syscall1(int, sys_setuid, uid_t, uid)
5833_syscall1(int, sys_setgid, gid_t, gid)
5834_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
5835_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
5836
bellard31e31b82003-02-18 22:55:36 +00005837void syscall_init(void)
5838{
bellard2ab83ea2003-06-15 19:56:46 +00005839 IOCTLEntry *ie;
5840 const argtype *arg_type;
5841 int size;
thsb92c47c2007-11-01 00:07:38 +00005842 int i;
bellard2ab83ea2003-06-15 19:56:46 +00005843
Alexander Graf8be656b2015-05-06 23:47:32 +02005844 thunk_init(STRUCT_MAX);
5845
Blue Swirl001faf32009-05-13 17:53:17 +00005846#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00005847#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00005848#include "syscall_types.h"
5849#undef STRUCT
5850#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00005851
Peter Maydelldd6e9572012-07-23 08:07:22 +00005852 /* Build target_to_host_errno_table[] table from
5853 * host_to_target_errno_table[]. */
5854 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
5855 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
5856 }
5857
bellard2ab83ea2003-06-15 19:56:46 +00005858 /* we patch the ioctl size if necessary. We rely on the fact that
5859 no ioctl has all the bits at '1' in the size field */
5860 ie = ioctl_entries;
5861 while (ie->target_cmd != 0) {
5862 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
5863 TARGET_IOC_SIZEMASK) {
5864 arg_type = ie->arg_type;
5865 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00005866 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00005867 ie->target_cmd);
5868 exit(1);
5869 }
5870 arg_type++;
5871 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00005872 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00005873 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
5874 (size << TARGET_IOC_SIZESHIFT);
5875 }
thsb92c47c2007-11-01 00:07:38 +00005876
bellard2ab83ea2003-06-15 19:56:46 +00005877 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00005878#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
5879 (defined(__x86_64__) && defined(TARGET_X86_64))
5880 if (unlikely(ie->target_cmd != ie->host_cmd)) {
5881 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
5882 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00005883 }
5884#endif
5885 ie++;
5886 }
bellard31e31b82003-02-18 22:55:36 +00005887}
bellardc573ff62004-01-04 15:51:36 +00005888
blueswir1992f48a2007-10-14 16:27:31 +00005889#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00005890static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
5891{
thsaf325d32008-06-10 15:29:15 +00005892#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00005893 return ((uint64_t)word0 << 32) | word1;
5894#else
5895 return ((uint64_t)word1 << 32) | word0;
5896#endif
5897}
blueswir1992f48a2007-10-14 16:27:31 +00005898#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00005899static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
5900{
5901 return word0;
5902}
blueswir1992f48a2007-10-14 16:27:31 +00005903#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00005904
5905#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00005906static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
5907 abi_long arg2,
5908 abi_long arg3,
5909 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005910{
Riku Voipio48e515d2011-07-12 15:40:51 +03005911 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005912 arg2 = arg3;
5913 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005914 }
pbrookce4defa2006-02-09 16:49:55 +00005915 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
5916}
5917#endif
5918
5919#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00005920static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
5921 abi_long arg2,
5922 abi_long arg3,
5923 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00005924{
Riku Voipio48e515d2011-07-12 15:40:51 +03005925 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00005926 arg2 = arg3;
5927 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03005928 }
pbrookce4defa2006-02-09 16:49:55 +00005929 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
5930}
5931#endif
5932
bellard579a97f2007-11-11 14:26:47 +00005933static inline abi_long target_to_host_timespec(struct timespec *host_ts,
5934 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00005935{
5936 struct target_timespec *target_ts;
5937
bellard579a97f2007-11-11 14:26:47 +00005938 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
5939 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01005940 __get_user(host_ts->tv_sec, &target_ts->tv_sec);
5941 __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005942 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00005943 return 0;
pbrook53a59602006-03-25 19:31:22 +00005944}
5945
bellard579a97f2007-11-11 14:26:47 +00005946static inline abi_long host_to_target_timespec(abi_ulong target_addr,
5947 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00005948{
5949 struct target_timespec *target_ts;
5950
bellard579a97f2007-11-11 14:26:47 +00005951 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
5952 return -TARGET_EFAULT;
Peter Maydellc7e35da2016-05-19 12:01:40 +01005953 __put_user(host_ts->tv_sec, &target_ts->tv_sec);
5954 __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00005955 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00005956 return 0;
pbrook53a59602006-03-25 19:31:22 +00005957}
5958
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11005959static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
5960 abi_ulong target_addr)
5961{
5962 struct target_itimerspec *target_itspec;
5963
5964 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
5965 return -TARGET_EFAULT;
5966 }
5967
5968 host_itspec->it_interval.tv_sec =
5969 tswapal(target_itspec->it_interval.tv_sec);
5970 host_itspec->it_interval.tv_nsec =
5971 tswapal(target_itspec->it_interval.tv_nsec);
5972 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5973 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5974
5975 unlock_user_struct(target_itspec, target_addr, 1);
5976 return 0;
5977}
5978
5979static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5980 struct itimerspec *host_its)
5981{
5982 struct target_itimerspec *target_itspec;
5983
5984 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5985 return -TARGET_EFAULT;
5986 }
5987
5988 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5989 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5990
5991 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5992 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5993
5994 unlock_user_struct(target_itspec, target_addr, 0);
5995 return 0;
5996}
5997
Peter Maydellc0659762014-08-09 15:42:32 +01005998static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5999 abi_ulong target_addr)
6000{
6001 struct target_sigevent *target_sevp;
6002
6003 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
6004 return -TARGET_EFAULT;
6005 }
6006
6007 /* This union is awkward on 64 bit systems because it has a 32 bit
6008 * integer and a pointer in it; we follow the conversion approach
6009 * used for handling sigval types in signal.c so the guest should get
6010 * the correct value back even if we did a 64 bit byteswap and it's
6011 * using the 32 bit integer.
6012 */
6013 host_sevp->sigev_value.sival_ptr =
6014 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
6015 host_sevp->sigev_signo =
6016 target_to_host_signal(tswap32(target_sevp->sigev_signo));
6017 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
6018 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
6019
6020 unlock_user_struct(target_sevp, target_addr, 1);
6021 return 0;
6022}
6023
Tom Musta6f6a4032014-08-12 13:53:42 -05006024#if defined(TARGET_NR_mlockall)
6025static inline int target_to_host_mlockall_arg(int arg)
6026{
6027 int result = 0;
6028
6029 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
6030 result |= MCL_CURRENT;
6031 }
6032 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
6033 result |= MCL_FUTURE;
6034 }
6035 return result;
6036}
6037#endif
6038
balrog6a24a772008-09-20 02:23:36 +00006039static inline abi_long host_to_target_stat64(void *cpu_env,
6040 abi_ulong target_addr,
6041 struct stat *host_st)
6042{
Alexander Graf09701192013-09-03 20:12:15 +01006043#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00006044 if (((CPUARMState *)cpu_env)->eabi) {
6045 struct target_eabi_stat64 *target_st;
6046
6047 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6048 return -TARGET_EFAULT;
6049 memset(target_st, 0, sizeof(struct target_eabi_stat64));
6050 __put_user(host_st->st_dev, &target_st->st_dev);
6051 __put_user(host_st->st_ino, &target_st->st_ino);
6052#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6053 __put_user(host_st->st_ino, &target_st->__st_ino);
6054#endif
6055 __put_user(host_st->st_mode, &target_st->st_mode);
6056 __put_user(host_st->st_nlink, &target_st->st_nlink);
6057 __put_user(host_st->st_uid, &target_st->st_uid);
6058 __put_user(host_st->st_gid, &target_st->st_gid);
6059 __put_user(host_st->st_rdev, &target_st->st_rdev);
6060 __put_user(host_st->st_size, &target_st->st_size);
6061 __put_user(host_st->st_blksize, &target_st->st_blksize);
6062 __put_user(host_st->st_blocks, &target_st->st_blocks);
6063 __put_user(host_st->st_atime, &target_st->target_st_atime);
6064 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6065 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6066 unlock_user_struct(target_st, target_addr, 1);
6067 } else
6068#endif
6069 {
Stefan Weil20d155b2013-10-30 22:52:24 +01006070#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00006071 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01006072#else
6073 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00006074#endif
balrog6a24a772008-09-20 02:23:36 +00006075
6076 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
6077 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00006078 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00006079 __put_user(host_st->st_dev, &target_st->st_dev);
6080 __put_user(host_st->st_ino, &target_st->st_ino);
6081#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
6082 __put_user(host_st->st_ino, &target_st->__st_ino);
6083#endif
6084 __put_user(host_st->st_mode, &target_st->st_mode);
6085 __put_user(host_st->st_nlink, &target_st->st_nlink);
6086 __put_user(host_st->st_uid, &target_st->st_uid);
6087 __put_user(host_st->st_gid, &target_st->st_gid);
6088 __put_user(host_st->st_rdev, &target_st->st_rdev);
6089 /* XXX: better use of kernel struct */
6090 __put_user(host_st->st_size, &target_st->st_size);
6091 __put_user(host_st->st_blksize, &target_st->st_blksize);
6092 __put_user(host_st->st_blocks, &target_st->st_blocks);
6093 __put_user(host_st->st_atime, &target_st->target_st_atime);
6094 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
6095 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
6096 unlock_user_struct(target_st, target_addr, 1);
6097 }
6098
6099 return 0;
6100}
balrog6a24a772008-09-20 02:23:36 +00006101
pbrookbd0c5662008-05-29 14:34:11 +00006102/* ??? Using host futex calls even when target atomic operations
6103 are not really atomic probably breaks things. However implementing
6104 futexes locally would make futexes shared between multiple processes
6105 tricky. However they're probably useless because guest atomic
6106 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00006107static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
6108 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00006109{
6110 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07006111 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00006112
6113 /* ??? We assume FUTEX_* constants are the same on both host
6114 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03006115#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07006116 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006117#else
Nathan Froyda16aae02009-08-03 08:43:29 -07006118 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03006119#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07006120 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00006121 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07006122 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00006123 if (timeout) {
6124 pts = &ts;
6125 target_to_host_timespec(pts, timeout);
6126 } else {
6127 pts = NULL;
6128 }
Peter Maydelld509eeb2016-05-12 18:47:52 +01006129 return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07006130 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00006131 case FUTEX_WAKE:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006132 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006133 case FUTEX_FD:
Peter Maydelld509eeb2016-05-12 18:47:52 +01006134 return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00006135 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00006136 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07006137 case FUTEX_WAKE_OP:
6138 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
6139 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
6140 But the prototype takes a `struct timespec *'; insert casts
6141 to satisfy the compiler. We do not need to tswap TIMEOUT
6142 since it's not compared to guest memory. */
6143 pts = (struct timespec *)(uintptr_t) timeout;
Peter Maydelld509eeb2016-05-12 18:47:52 +01006144 return get_errno(safe_futex(g2h(uaddr), op, val, pts,
6145 g2h(uaddr2),
6146 (base_op == FUTEX_CMP_REQUEUE
6147 ? tswap32(val3)
6148 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00006149 default:
6150 return -TARGET_ENOSYS;
6151 }
6152}
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006153#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6154static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
6155 abi_long handle, abi_long mount_id,
6156 abi_long flags)
6157{
6158 struct file_handle *target_fh;
6159 struct file_handle *fh;
6160 int mid = 0;
6161 abi_long ret;
6162 char *name;
6163 unsigned int size, total_size;
6164
6165 if (get_user_s32(size, handle)) {
6166 return -TARGET_EFAULT;
6167 }
6168
6169 name = lock_user_string(pathname);
6170 if (!name) {
6171 return -TARGET_EFAULT;
6172 }
6173
6174 total_size = sizeof(struct file_handle) + size;
6175 target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
6176 if (!target_fh) {
6177 unlock_user(name, pathname, 0);
6178 return -TARGET_EFAULT;
6179 }
6180
6181 fh = g_malloc0(total_size);
6182 fh->handle_bytes = size;
6183
6184 ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
6185 unlock_user(name, pathname, 0);
6186
6187 /* man name_to_handle_at(2):
6188 * Other than the use of the handle_bytes field, the caller should treat
6189 * the file_handle structure as an opaque data type
6190 */
6191
6192 memcpy(target_fh, fh, total_size);
6193 target_fh->handle_bytes = tswap32(fh->handle_bytes);
6194 target_fh->handle_type = tswap32(fh->handle_type);
6195 g_free(fh);
6196 unlock_user(target_fh, handle, total_size);
6197
6198 if (put_user_s32(mid, mount_id)) {
6199 return -TARGET_EFAULT;
6200 }
6201
6202 return ret;
6203
6204}
6205#endif
6206
6207#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6208static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
6209 abi_long flags)
6210{
6211 struct file_handle *target_fh;
6212 struct file_handle *fh;
6213 unsigned int size, total_size;
6214 abi_long ret;
6215
6216 if (get_user_s32(size, handle)) {
6217 return -TARGET_EFAULT;
6218 }
6219
6220 total_size = sizeof(struct file_handle) + size;
6221 target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
6222 if (!target_fh) {
6223 return -TARGET_EFAULT;
6224 }
6225
Thomas Huthe9d49d52015-10-09 17:56:38 +02006226 fh = g_memdup(target_fh, total_size);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006227 fh->handle_bytes = size;
6228 fh->handle_type = tswap32(target_fh->handle_type);
6229
6230 ret = get_errno(open_by_handle_at(mount_fd, fh,
6231 target_to_host_bitmask(flags, fcntl_flags_tbl)));
6232
6233 g_free(fh);
6234
6235 unlock_user(target_fh, handle, total_size);
6236
6237 return ret;
6238}
6239#endif
pbrookbd0c5662008-05-29 14:34:11 +00006240
Laurent Viviere36800c2015-10-02 14:48:09 +02006241#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
6242
6243/* signalfd siginfo conversion */
6244
6245static void
6246host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
6247 const struct signalfd_siginfo *info)
6248{
6249 int sig = host_to_target_signal(info->ssi_signo);
6250
6251 /* linux/signalfd.h defines a ssi_addr_lsb
6252 * not defined in sys/signalfd.h but used by some kernels
6253 */
6254
6255#ifdef BUS_MCEERR_AO
6256 if (tinfo->ssi_signo == SIGBUS &&
6257 (tinfo->ssi_code == BUS_MCEERR_AR ||
6258 tinfo->ssi_code == BUS_MCEERR_AO)) {
6259 uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
6260 uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
6261 *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
6262 }
6263#endif
6264
6265 tinfo->ssi_signo = tswap32(sig);
6266 tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
6267 tinfo->ssi_code = tswap32(info->ssi_code);
6268 tinfo->ssi_pid = tswap32(info->ssi_pid);
6269 tinfo->ssi_uid = tswap32(info->ssi_uid);
6270 tinfo->ssi_fd = tswap32(info->ssi_fd);
6271 tinfo->ssi_tid = tswap32(info->ssi_tid);
6272 tinfo->ssi_band = tswap32(info->ssi_band);
6273 tinfo->ssi_overrun = tswap32(info->ssi_overrun);
6274 tinfo->ssi_trapno = tswap32(info->ssi_trapno);
6275 tinfo->ssi_status = tswap32(info->ssi_status);
6276 tinfo->ssi_int = tswap32(info->ssi_int);
6277 tinfo->ssi_ptr = tswap64(info->ssi_ptr);
6278 tinfo->ssi_utime = tswap64(info->ssi_utime);
6279 tinfo->ssi_stime = tswap64(info->ssi_stime);
6280 tinfo->ssi_addr = tswap64(info->ssi_addr);
6281}
6282
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006283static abi_long host_to_target_data_signalfd(void *buf, size_t len)
Laurent Viviere36800c2015-10-02 14:48:09 +02006284{
6285 int i;
6286
6287 for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
6288 host_to_target_signalfd_siginfo(buf + i, buf + i);
6289 }
6290
6291 return len;
6292}
6293
6294static TargetFdTrans target_signalfd_trans = {
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006295 .host_to_target_data = host_to_target_data_signalfd,
Laurent Viviere36800c2015-10-02 14:48:09 +02006296};
6297
6298static abi_long do_signalfd4(int fd, abi_long mask, int flags)
6299{
6300 int host_flags;
6301 target_sigset_t *target_mask;
6302 sigset_t host_mask;
6303 abi_long ret;
6304
6305 if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
6306 return -TARGET_EINVAL;
6307 }
6308 if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
6309 return -TARGET_EFAULT;
6310 }
6311
6312 target_to_host_sigset(&host_mask, target_mask);
6313
6314 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
6315
6316 ret = get_errno(signalfd(fd, &host_mask, host_flags));
6317 if (ret >= 0) {
6318 fd_trans_register(ret, &target_signalfd_trans);
6319 }
6320
6321 unlock_user_struct(target_mask, mask, 0);
6322
6323 return ret;
6324}
6325#endif
6326
pbrook1d9d8b52009-04-16 15:17:02 +00006327/* Map host to target signal numbers for the wait family of syscalls.
6328 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07006329int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00006330{
6331 if (WIFSIGNALED(status)) {
6332 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
6333 }
6334 if (WIFSTOPPED(status)) {
6335 return (host_to_target_signal(WSTOPSIG(status)) << 8)
6336 | (status & 0xff);
6337 }
6338 return status;
6339}
6340
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006341static int open_self_cmdline(void *cpu_env, int fd)
6342{
6343 int fd_orig = -1;
6344 bool word_skipped = false;
6345
6346 fd_orig = open("/proc/self/cmdline", O_RDONLY);
6347 if (fd_orig < 0) {
6348 return fd_orig;
6349 }
6350
6351 while (true) {
6352 ssize_t nb_read;
6353 char buf[128];
6354 char *cp_buf = buf;
6355
6356 nb_read = read(fd_orig, buf, sizeof(buf));
6357 if (nb_read < 0) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006358 int e = errno;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006359 fd_orig = close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006360 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006361 return -1;
6362 } else if (nb_read == 0) {
6363 break;
6364 }
6365
6366 if (!word_skipped) {
6367 /* Skip the first string, which is the path to qemu-*-static
6368 instead of the actual command. */
6369 cp_buf = memchr(buf, 0, sizeof(buf));
6370 if (cp_buf) {
6371 /* Null byte found, skip one string */
6372 cp_buf++;
6373 nb_read -= cp_buf - buf;
6374 word_skipped = true;
6375 }
6376 }
6377
6378 if (word_skipped) {
6379 if (write(fd, cp_buf, nb_read) != nb_read) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006380 int e = errno;
zhanghailiang680dfde2014-08-22 16:23:51 +08006381 close(fd_orig);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006382 errno = e;
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006383 return -1;
6384 }
6385 }
6386 }
6387
6388 return close(fd_orig);
6389}
6390
Alexander Graf36c08d42011-11-02 20:23:24 +01006391static int open_self_maps(void *cpu_env, int fd)
6392{
Andreas Färber0429a972013-08-26 18:14:44 +02006393 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6394 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006395 FILE *fp;
6396 char *line = NULL;
6397 size_t len = 0;
6398 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01006399
Alexander Graf1a49ef22012-05-01 16:30:28 +01006400 fp = fopen("/proc/self/maps", "r");
6401 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006402 return -1;
Alexander Graf1a49ef22012-05-01 16:30:28 +01006403 }
6404
6405 while ((read = getline(&line, &len, fp)) != -1) {
6406 int fields, dev_maj, dev_min, inode;
6407 uint64_t min, max, offset;
6408 char flag_r, flag_w, flag_x, flag_p;
6409 char path[512] = "";
6410 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
6411 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
6412 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
6413
6414 if ((fields < 10) || (fields > 11)) {
6415 continue;
6416 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006417 if (h2g_valid(min)) {
6418 int flags = page_get_flags(h2g(min));
6419 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
6420 if (page_check_range(h2g(min), max - min, flags) == -1) {
6421 continue;
6422 }
6423 if (h2g(min) == ts->info->stack_limit) {
6424 pstrcpy(path, sizeof(path), " [stack]");
6425 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01006426 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02006427 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04006428 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01006429 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02006430 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01006431 }
6432 }
6433
6434 free(line);
6435 fclose(fp);
6436
Alexander Graf36c08d42011-11-02 20:23:24 +01006437 return 0;
6438}
6439
Alexander Graf480b8e72011-11-02 20:23:25 +01006440static int open_self_stat(void *cpu_env, int fd)
6441{
Andreas Färber0429a972013-08-26 18:14:44 +02006442 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6443 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01006444 abi_ulong start_stack = ts->info->start_stack;
6445 int i;
6446
6447 for (i = 0; i < 44; i++) {
6448 char buf[128];
6449 int len;
6450 uint64_t val = 0;
6451
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006452 if (i == 0) {
6453 /* pid */
6454 val = getpid();
6455 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6456 } else if (i == 1) {
6457 /* app name */
6458 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
6459 } else if (i == 27) {
6460 /* stack bottom */
6461 val = start_stack;
6462 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
6463 } else {
6464 /* for the rest, there is MasterCard */
6465 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01006466 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00006467
Alexander Graf480b8e72011-11-02 20:23:25 +01006468 len = strlen(buf);
6469 if (write(fd, buf, len) != len) {
6470 return -1;
6471 }
6472 }
6473
6474 return 0;
6475}
6476
Alexander Graf257450e2011-11-02 20:23:26 +01006477static int open_self_auxv(void *cpu_env, int fd)
6478{
Andreas Färber0429a972013-08-26 18:14:44 +02006479 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
6480 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01006481 abi_ulong auxv = ts->info->saved_auxv;
6482 abi_ulong len = ts->info->auxv_len;
6483 char *ptr;
6484
6485 /*
6486 * Auxiliary vector is stored in target process stack.
6487 * read in whole auxv vector and copy it to file
6488 */
6489 ptr = lock_user(VERIFY_READ, auxv, len, 0);
6490 if (ptr != NULL) {
6491 while (len > 0) {
6492 ssize_t r;
6493 r = write(fd, ptr, len);
6494 if (r <= 0) {
6495 break;
6496 }
6497 len -= r;
6498 ptr += r;
6499 }
6500 lseek(fd, 0, SEEK_SET);
6501 unlock_user(ptr, auxv, len);
6502 }
6503
6504 return 0;
6505}
6506
Andreas Schwab463d8e72013-07-02 14:04:12 +01006507static int is_proc_myself(const char *filename, const char *entry)
6508{
6509 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
6510 filename += strlen("/proc/");
6511 if (!strncmp(filename, "self/", strlen("self/"))) {
6512 filename += strlen("self/");
6513 } else if (*filename >= '1' && *filename <= '9') {
6514 char myself[80];
6515 snprintf(myself, sizeof(myself), "%d/", getpid());
6516 if (!strncmp(filename, myself, strlen(myself))) {
6517 filename += strlen(myself);
6518 } else {
6519 return 0;
6520 }
6521 } else {
6522 return 0;
6523 }
6524 if (!strcmp(filename, entry)) {
6525 return 1;
6526 }
6527 }
6528 return 0;
6529}
6530
Laurent Vivierde6b9932013-08-30 01:46:40 +02006531#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6532static int is_proc(const char *filename, const char *entry)
6533{
6534 return strcmp(filename, entry) == 0;
6535}
6536
6537static int open_net_route(void *cpu_env, int fd)
6538{
6539 FILE *fp;
6540 char *line = NULL;
6541 size_t len = 0;
6542 ssize_t read;
6543
6544 fp = fopen("/proc/net/route", "r");
6545 if (fp == NULL) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006546 return -1;
Laurent Vivierde6b9932013-08-30 01:46:40 +02006547 }
6548
6549 /* read header */
6550
6551 read = getline(&line, &len, fp);
6552 dprintf(fd, "%s", line);
6553
6554 /* read routes */
6555
6556 while ((read = getline(&line, &len, fp)) != -1) {
6557 char iface[16];
6558 uint32_t dest, gw, mask;
6559 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
6560 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6561 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
6562 &mask, &mtu, &window, &irtt);
6563 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
6564 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
6565 metric, tswap32(mask), mtu, window, irtt);
6566 }
6567
6568 free(line);
6569 fclose(fp);
6570
6571 return 0;
6572}
6573#endif
6574
Riku Voipio0b2effd2014-08-06 10:36:37 +03006575static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01006576{
6577 struct fake_open {
6578 const char *filename;
6579 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02006580 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01006581 };
6582 const struct fake_open *fake_open;
6583 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006584 { "maps", open_self_maps, is_proc_myself },
6585 { "stat", open_self_stat, is_proc_myself },
6586 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02006587 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02006588#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
6589 { "/proc/net/route", open_net_route, is_proc },
6590#endif
6591 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01006592 };
6593
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006594 if (is_proc_myself(pathname, "exe")) {
6595 int execfd = qemu_getauxval(AT_EXECFD);
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006596 return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03006597 }
6598
Alexander Graf3be14d02011-11-02 20:23:23 +01006599 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02006600 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01006601 break;
6602 }
6603 }
6604
6605 if (fake_open->filename) {
6606 const char *tmpdir;
6607 char filename[PATH_MAX];
6608 int fd, r;
6609
6610 /* create temporary file to map stat to */
6611 tmpdir = getenv("TMPDIR");
6612 if (!tmpdir)
6613 tmpdir = "/tmp";
6614 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
6615 fd = mkstemp(filename);
6616 if (fd < 0) {
6617 return fd;
6618 }
6619 unlink(filename);
6620
6621 if ((r = fake_open->fill(cpu_env, fd))) {
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006622 int e = errno;
Alexander Graf3be14d02011-11-02 20:23:23 +01006623 close(fd);
Peter Maydella3ca7bb2016-05-12 18:47:26 +01006624 errno = e;
Alexander Graf3be14d02011-11-02 20:23:23 +01006625 return r;
6626 }
6627 lseek(fd, 0, SEEK_SET);
6628
6629 return fd;
6630 }
6631
Timothy E Baldwinc10a0732016-05-12 18:47:48 +01006632 return safe_openat(dirfd, path(pathname), flags, mode);
Alexander Graf3be14d02011-11-02 20:23:23 +01006633}
6634
Alexander Grafaecc8862014-11-10 21:33:03 +01006635#define TIMER_MAGIC 0x0caf0000
6636#define TIMER_MAGIC_MASK 0xffff0000
6637
6638/* Convert QEMU provided timer ID back to internal 16bit index format */
6639static target_timer_t get_timer_id(abi_long arg)
6640{
6641 target_timer_t timerid = arg;
6642
6643 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
6644 return -TARGET_EINVAL;
6645 }
6646
6647 timerid &= 0xffff;
6648
6649 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
6650 return -TARGET_EINVAL;
6651 }
6652
6653 return timerid;
6654}
6655
ths0da46a62007-10-20 20:23:07 +00006656/* do_syscall() should always have a single exit point at the end so
6657 that actions, such as logging of syscall results, can be performed.
6658 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00006659abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6660 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01006661 abi_long arg5, abi_long arg6, abi_long arg7,
6662 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00006663{
Andreas Färber182735e2013-05-29 22:29:20 +02006664 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00006665 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00006666 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00006667 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00006668 void *p;
ths3b46e622007-09-17 08:09:54 +00006669
Timothy E Baldwin71a8f7f2016-05-12 18:47:45 +01006670#if defined(DEBUG_ERESTARTSYS)
6671 /* Debug-only code for exercising the syscall-restart code paths
6672 * in the per-architecture cpu main loops: restart every syscall
6673 * the guest makes once before letting it through.
6674 */
6675 {
6676 static int flag;
6677
6678 flag = !flag;
6679 if (flag) {
6680 return -TARGET_ERESTARTSYS;
6681 }
6682 }
6683#endif
6684
bellard72f03902003-02-18 23:33:18 +00006685#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00006686 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00006687#endif
thsb92c47c2007-11-01 00:07:38 +00006688 if(do_strace)
6689 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
6690
bellard31e31b82003-02-18 22:55:36 +00006691 switch(num) {
6692 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02006693 /* In old applications this may be used to implement _exit(2).
6694 However in threaded applictions it is used for thread termination,
6695 and _exit_group is used for application termination.
6696 Do thread termination if we have more then one thread. */
Timothy E Baldwina0995882016-05-27 15:51:56 +01006697
6698 if (block_signals()) {
6699 ret = -TARGET_ERESTARTSYS;
6700 break;
6701 }
6702
Andreas Färberbdc44642013-06-24 23:50:24 +02006703 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02006704 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00006705
Andreas Färber9b056fc2013-06-24 23:53:10 +02006706 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006707 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02006708 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02006709 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02006710 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02006711 if (ts->child_tidptr) {
6712 put_user_u32(0, ts->child_tidptr);
6713 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
6714 NULL, NULL, 0);
6715 }
Andreas Färbera2247f82013-06-09 19:47:04 +02006716 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02006717 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02006718 g_free(ts);
Emilio G. Cota70903762015-08-23 20:23:41 -04006719 rcu_unregister_thread();
Andreas Färber9b056fc2013-06-24 23:53:10 +02006720 pthread_exit(NULL);
6721 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02006722#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00006723 _mcleanup();
6724#endif
bellarde9009672005-04-26 20:42:36 +00006725 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00006726 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00006727 ret = 0; /* avoid warning */
6728 break;
6729 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00006730 if (arg3 == 0)
6731 ret = 0;
6732 else {
6733 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
6734 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006735 ret = get_errno(safe_read(arg1, p, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006736 if (ret >= 0 &&
Laurent Vivier5d4d3662015-10-28 21:40:43 +01006737 fd_trans_host_to_target_data(arg1)) {
6738 ret = fd_trans_host_to_target_data(arg1)(p, ret);
Laurent Viviere36800c2015-10-02 14:48:09 +02006739 }
aurel3238d840e2009-01-30 19:48:17 +00006740 unlock_user(p, arg2, ret);
6741 }
bellard31e31b82003-02-18 22:55:36 +00006742 break;
6743 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00006744 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
6745 goto efault;
Timothy E Baldwin50afd022016-05-12 18:47:47 +01006746 ret = get_errno(safe_write(arg1, p, arg3));
pbrook53a59602006-03-25 19:31:22 +00006747 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00006748 break;
Chen Gang704eff62015-08-21 05:37:33 +08006749#ifdef TARGET_NR_open
bellard31e31b82003-02-18 22:55:36 +00006750 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00006751 if (!(p = lock_user_string(arg1)))
6752 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006753 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
6754 target_to_host_bitmask(arg2, fcntl_flags_tbl),
6755 arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02006756 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006757 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006758 break;
Chen Gang704eff62015-08-21 05:37:33 +08006759#endif
ths82424832007-09-24 09:21:55 +00006760 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00006761 if (!(p = lock_user_string(arg2)))
6762 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03006763 ret = get_errno(do_openat(cpu_env, arg1, p,
6764 target_to_host_bitmask(arg3, fcntl_flags_tbl),
6765 arg4));
Laurent Viviere36800c2015-10-02 14:48:09 +02006766 fd_trans_unregister(ret);
bellard579a97f2007-11-11 14:26:47 +00006767 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00006768 break;
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006769#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6770 case TARGET_NR_name_to_handle_at:
6771 ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
6772 break;
6773#endif
6774#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
6775 case TARGET_NR_open_by_handle_at:
6776 ret = do_open_by_handle_at(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02006777 fd_trans_unregister(ret);
Laurent Vivier0f0426f2015-09-01 22:27:33 +02006778 break;
6779#endif
bellard31e31b82003-02-18 22:55:36 +00006780 case TARGET_NR_close:
Laurent Viviere36800c2015-10-02 14:48:09 +02006781 fd_trans_unregister(arg1);
bellard31e31b82003-02-18 22:55:36 +00006782 ret = get_errno(close(arg1));
6783 break;
6784 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00006785 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00006786 break;
Chen Gang704eff62015-08-21 05:37:33 +08006787#ifdef TARGET_NR_fork
bellard31e31b82003-02-18 22:55:36 +00006788 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00006789 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00006790 break;
Chen Gang704eff62015-08-21 05:37:33 +08006791#endif
thse5febef2007-04-01 18:31:35 +00006792#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00006793 case TARGET_NR_waitpid:
6794 {
pbrook53a59602006-03-25 19:31:22 +00006795 int status;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006796 ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
Alexander Graf53795572011-11-24 00:44:43 +01006797 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00006798 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00006799 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006800 }
6801 break;
thse5febef2007-04-01 18:31:35 +00006802#endif
pbrookf0cbb612008-05-30 18:20:05 +00006803#ifdef TARGET_NR_waitid
6804 case TARGET_NR_waitid:
6805 {
6806 siginfo_t info;
6807 info.si_pid = 0;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01006808 ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
pbrookf0cbb612008-05-30 18:20:05 +00006809 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006810 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00006811 goto efault;
6812 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05006813 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00006814 }
6815 }
6816 break;
6817#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006818#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006819 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00006820 if (!(p = lock_user_string(arg1)))
6821 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006822 ret = get_errno(creat(p, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02006823 fd_trans_unregister(ret);
pbrook53a59602006-03-25 19:31:22 +00006824 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006825 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006826#endif
Chen Gang704eff62015-08-21 05:37:33 +08006827#ifdef TARGET_NR_link
bellard31e31b82003-02-18 22:55:36 +00006828 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00006829 {
6830 void * p2;
6831 p = lock_user_string(arg1);
6832 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006833 if (!p || !p2)
6834 ret = -TARGET_EFAULT;
6835 else
6836 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006837 unlock_user(p2, arg2, 0);
6838 unlock_user(p, arg1, 0);
6839 }
bellard31e31b82003-02-18 22:55:36 +00006840 break;
Chen Gang704eff62015-08-21 05:37:33 +08006841#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006842#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00006843 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00006844 {
6845 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00006846 if (!arg2 || !arg4)
6847 goto efault;
ths64f0ce42007-09-24 09:25:06 +00006848 p = lock_user_string(arg2);
6849 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006850 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006851 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00006852 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006853 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00006854 unlock_user(p, arg2, 0);
6855 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00006856 }
6857 break;
6858#endif
Chen Gang704eff62015-08-21 05:37:33 +08006859#ifdef TARGET_NR_unlink
bellard31e31b82003-02-18 22:55:36 +00006860 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00006861 if (!(p = lock_user_string(arg1)))
6862 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006863 ret = get_errno(unlink(p));
6864 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006865 break;
Chen Gang704eff62015-08-21 05:37:33 +08006866#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006867#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00006868 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00006869 if (!(p = lock_user_string(arg2)))
6870 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006871 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006872 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00006873 break;
balrogb7d35e62007-12-12 00:40:24 +00006874#endif
bellard31e31b82003-02-18 22:55:36 +00006875 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00006876 {
6877 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00006878 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00006879 abi_ulong gp;
6880 abi_ulong guest_argp;
6881 abi_ulong guest_envp;
6882 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00006883 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006884 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00006885
bellardf7341ff2003-03-30 21:00:25 +00006886 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00006887 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00006888 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006889 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006890 goto efault;
ths03aa1972007-12-02 06:28:08 +00006891 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006892 break;
bellard7854b052003-03-29 17:22:23 +00006893 argc++;
bellard2f619692007-11-16 10:46:05 +00006894 }
bellardf7341ff2003-03-30 21:00:25 +00006895 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00006896 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00006897 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00006898 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00006899 goto efault;
ths03aa1972007-12-02 06:28:08 +00006900 if (!addr)
bellard2f619692007-11-16 10:46:05 +00006901 break;
bellard7854b052003-03-29 17:22:23 +00006902 envc++;
bellard2f619692007-11-16 10:46:05 +00006903 }
bellard7854b052003-03-29 17:22:23 +00006904
bellardf7341ff2003-03-30 21:00:25 +00006905 argp = alloca((argc + 1) * sizeof(void *));
6906 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00006907
pbrookda94d262008-05-30 18:24:00 +00006908 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006909 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006910 if (get_user_ual(addr, gp))
6911 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006912 if (!addr)
6913 break;
bellard2f619692007-11-16 10:46:05 +00006914 if (!(*q = lock_user_string(addr)))
6915 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006916 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006917 }
bellardf7341ff2003-03-30 21:00:25 +00006918 *q = NULL;
6919
pbrookda94d262008-05-30 18:24:00 +00006920 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00006921 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006922 if (get_user_ual(addr, gp))
6923 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00006924 if (!addr)
6925 break;
bellard2f619692007-11-16 10:46:05 +00006926 if (!(*q = lock_user_string(addr)))
6927 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01006928 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00006929 }
bellardf7341ff2003-03-30 21:00:25 +00006930 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00006931
bellard2f619692007-11-16 10:46:05 +00006932 if (!(p = lock_user_string(arg1)))
6933 goto execve_efault;
Timothy E Baldwinffdcbe22016-05-12 18:47:50 +01006934 /* Although execve() is not an interruptible syscall it is
6935 * a special case where we must use the safe_syscall wrapper:
6936 * if we allow a signal to happen before we make the host
6937 * syscall then we will 'lose' it, because at the point of
6938 * execve the process leaves QEMU's control. So we use the
6939 * safe syscall wrapper to ensure that we either take the
6940 * signal as a guest signal, or else it does not happen
6941 * before the execve completes and makes it the other
6942 * program's problem.
6943 */
6944 ret = get_errno(safe_execve(p, argp, envp));
pbrook53a59602006-03-25 19:31:22 +00006945 unlock_user(p, arg1, 0);
6946
bellard2f619692007-11-16 10:46:05 +00006947 goto execve_end;
6948
6949 execve_efault:
6950 ret = -TARGET_EFAULT;
6951
6952 execve_end:
pbrook53a59602006-03-25 19:31:22 +00006953 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006954 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006955 if (get_user_ual(addr, gp)
6956 || !addr)
6957 break;
pbrook53a59602006-03-25 19:31:22 +00006958 unlock_user(*q, addr, 0);
6959 }
6960 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00006961 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00006962 if (get_user_ual(addr, gp)
6963 || !addr)
6964 break;
pbrook53a59602006-03-25 19:31:22 +00006965 unlock_user(*q, addr, 0);
6966 }
bellard7854b052003-03-29 17:22:23 +00006967 }
bellard31e31b82003-02-18 22:55:36 +00006968 break;
6969 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00006970 if (!(p = lock_user_string(arg1)))
6971 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006972 ret = get_errno(chdir(p));
6973 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006974 break;
bellarda315a142005-01-30 22:59:18 +00006975#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00006976 case TARGET_NR_time:
6977 {
pbrook53a59602006-03-25 19:31:22 +00006978 time_t host_time;
6979 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00006980 if (!is_error(ret)
6981 && arg1
6982 && put_user_sal(host_time, arg1))
6983 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006984 }
6985 break;
bellarda315a142005-01-30 22:59:18 +00006986#endif
Chen Gang704eff62015-08-21 05:37:33 +08006987#ifdef TARGET_NR_mknod
bellard31e31b82003-02-18 22:55:36 +00006988 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00006989 if (!(p = lock_user_string(arg1)))
6990 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006991 ret = get_errno(mknod(p, arg2, arg3));
6992 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006993 break;
Chen Gang704eff62015-08-21 05:37:33 +08006994#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01006995#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00006996 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00006997 if (!(p = lock_user_string(arg2)))
6998 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006999 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00007000 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00007001 break;
7002#endif
Chen Gang704eff62015-08-21 05:37:33 +08007003#ifdef TARGET_NR_chmod
bellard31e31b82003-02-18 22:55:36 +00007004 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00007005 if (!(p = lock_user_string(arg1)))
7006 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007007 ret = get_errno(chmod(p, arg2));
7008 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007009 break;
Chen Gang704eff62015-08-21 05:37:33 +08007010#endif
bellardebc05482003-09-30 21:08:41 +00007011#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00007012 case TARGET_NR_break:
7013 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007014#endif
7015#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00007016 case TARGET_NR_oldstat:
7017 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007018#endif
bellard31e31b82003-02-18 22:55:36 +00007019 case TARGET_NR_lseek:
7020 ret = get_errno(lseek(arg1, arg2, arg3));
7021 break;
Richard Henderson92317332010-05-03 10:07:53 -07007022#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
7023 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00007024 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07007025 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00007026 ret = get_errno(getpid());
7027 break;
Richard Henderson92317332010-05-03 10:07:53 -07007028#endif
7029#ifdef TARGET_NR_getpid
7030 case TARGET_NR_getpid:
7031 ret = get_errno(getpid());
7032 break;
7033#endif
bellard31e31b82003-02-18 22:55:36 +00007034 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01007035 {
7036 /* need to look at the data field */
7037 void *p2, *p3;
7038
7039 if (arg1) {
7040 p = lock_user_string(arg1);
7041 if (!p) {
7042 goto efault;
7043 }
7044 } else {
7045 p = NULL;
7046 }
7047
7048 p2 = lock_user_string(arg2);
7049 if (!p2) {
7050 if (arg1) {
7051 unlock_user(p, arg1, 0);
7052 }
7053 goto efault;
7054 }
7055
7056 if (arg3) {
7057 p3 = lock_user_string(arg3);
7058 if (!p3) {
7059 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007060 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01007061 }
7062 unlock_user(p2, arg2, 0);
7063 goto efault;
7064 }
7065 } else {
7066 p3 = NULL;
7067 }
7068
7069 /* FIXME - arg5 should be locked, but it isn't clear how to
7070 * do that since it's not guaranteed to be a NULL-terminated
7071 * string.
7072 */
7073 if (!arg5) {
7074 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
7075 } else {
7076 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
7077 }
7078 ret = get_errno(ret);
7079
7080 if (arg1) {
7081 unlock_user(p, arg1, 0);
7082 }
7083 unlock_user(p2, arg2, 0);
7084 if (arg3) {
7085 unlock_user(p3, arg3, 0);
7086 }
7087 }
7088 break;
thse5febef2007-04-01 18:31:35 +00007089#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00007090 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00007091 if (!(p = lock_user_string(arg1)))
7092 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007093 ret = get_errno(umount(p));
7094 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007095 break;
thse5febef2007-04-01 18:31:35 +00007096#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007097#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007098 case TARGET_NR_stime:
7099 {
pbrook53a59602006-03-25 19:31:22 +00007100 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00007101 if (get_user_sal(host_time, arg1))
7102 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007103 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00007104 }
7105 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007106#endif
bellard31e31b82003-02-18 22:55:36 +00007107 case TARGET_NR_ptrace:
7108 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00007109#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007110 case TARGET_NR_alarm:
7111 ret = alarm(arg1);
7112 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007113#endif
bellardebc05482003-09-30 21:08:41 +00007114#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00007115 case TARGET_NR_oldfstat:
7116 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007117#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007118#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007119 case TARGET_NR_pause:
Timothy E Baldwinf59ec602016-05-27 15:51:55 +01007120 if (!block_signals()) {
7121 sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
7122 }
7123 ret = -TARGET_EINTR;
bellard31e31b82003-02-18 22:55:36 +00007124 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007125#endif
thse5febef2007-04-01 18:31:35 +00007126#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00007127 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00007128 {
pbrook53a59602006-03-25 19:31:22 +00007129 struct utimbuf tbuf, *host_tbuf;
7130 struct target_utimbuf *target_tbuf;
7131 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007132 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
7133 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007134 tbuf.actime = tswapal(target_tbuf->actime);
7135 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00007136 unlock_user_struct(target_tbuf, arg2, 0);
7137 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00007138 } else {
pbrook53a59602006-03-25 19:31:22 +00007139 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00007140 }
bellard579a97f2007-11-11 14:26:47 +00007141 if (!(p = lock_user_string(arg1)))
7142 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007143 ret = get_errno(utime(p, host_tbuf));
7144 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00007145 }
7146 break;
thse5febef2007-04-01 18:31:35 +00007147#endif
Chen Gang704eff62015-08-21 05:37:33 +08007148#ifdef TARGET_NR_utimes
bellard978a66f2004-12-06 22:58:05 +00007149 case TARGET_NR_utimes:
7150 {
bellard978a66f2004-12-06 22:58:05 +00007151 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00007152 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00007153 if (copy_from_user_timeval(&tv[0], arg2)
7154 || copy_from_user_timeval(&tv[1],
7155 arg2 + sizeof(struct target_timeval)))
7156 goto efault;
bellard978a66f2004-12-06 22:58:05 +00007157 tvp = tv;
7158 } else {
7159 tvp = NULL;
7160 }
bellard579a97f2007-11-11 14:26:47 +00007161 if (!(p = lock_user_string(arg1)))
7162 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007163 ret = get_errno(utimes(p, tvp));
7164 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00007165 }
7166 break;
Chen Gang704eff62015-08-21 05:37:33 +08007167#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007168#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00007169 case TARGET_NR_futimesat:
7170 {
7171 struct timeval *tvp, tv[2];
7172 if (arg3) {
7173 if (copy_from_user_timeval(&tv[0], arg3)
7174 || copy_from_user_timeval(&tv[1],
7175 arg3 + sizeof(struct target_timeval)))
7176 goto efault;
7177 tvp = tv;
7178 } else {
7179 tvp = NULL;
7180 }
7181 if (!(p = lock_user_string(arg2)))
7182 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007183 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00007184 unlock_user(p, arg2, 0);
7185 }
7186 break;
7187#endif
bellardebc05482003-09-30 21:08:41 +00007188#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00007189 case TARGET_NR_stty:
7190 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007191#endif
7192#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00007193 case TARGET_NR_gtty:
7194 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007195#endif
Chen Gang704eff62015-08-21 05:37:33 +08007196#ifdef TARGET_NR_access
bellard31e31b82003-02-18 22:55:36 +00007197 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00007198 if (!(p = lock_user_string(arg1)))
7199 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02007200 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00007201 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007202 break;
Chen Gang704eff62015-08-21 05:37:33 +08007203#endif
ths92a34c12007-09-24 09:27:49 +00007204#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
7205 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00007206 if (!(p = lock_user_string(arg2)))
7207 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007208 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00007209 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00007210 break;
7211#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007212#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007213 case TARGET_NR_nice:
7214 ret = get_errno(nice(arg1));
7215 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007216#endif
bellardebc05482003-09-30 21:08:41 +00007217#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_ftime:
7219 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007220#endif
bellard31e31b82003-02-18 22:55:36 +00007221 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00007222 sync();
7223 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00007224 break;
7225 case TARGET_NR_kill:
Peter Maydellbef653d2016-05-27 15:51:57 +01007226 ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00007227 break;
Chen Gang704eff62015-08-21 05:37:33 +08007228#ifdef TARGET_NR_rename
bellard31e31b82003-02-18 22:55:36 +00007229 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00007230 {
7231 void *p2;
7232 p = lock_user_string(arg1);
7233 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00007234 if (!p || !p2)
7235 ret = -TARGET_EFAULT;
7236 else
7237 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00007238 unlock_user(p2, arg2, 0);
7239 unlock_user(p, arg1, 0);
7240 }
bellard31e31b82003-02-18 22:55:36 +00007241 break;
Chen Gang704eff62015-08-21 05:37:33 +08007242#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007243#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00007244 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00007245 {
bellard579a97f2007-11-11 14:26:47 +00007246 void *p2;
ths722183f2007-09-24 09:24:37 +00007247 p = lock_user_string(arg2);
7248 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00007249 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00007250 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00007251 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01007252 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00007253 unlock_user(p2, arg4, 0);
7254 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00007255 }
7256 break;
7257#endif
Chen Gang704eff62015-08-21 05:37:33 +08007258#ifdef TARGET_NR_mkdir
bellard31e31b82003-02-18 22:55:36 +00007259 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00007260 if (!(p = lock_user_string(arg1)))
7261 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007262 ret = get_errno(mkdir(p, arg2));
7263 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007264 break;
Chen Gang704eff62015-08-21 05:37:33 +08007265#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007266#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00007267 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00007268 if (!(p = lock_user_string(arg2)))
7269 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007270 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00007271 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00007272 break;
7273#endif
Chen Gang704eff62015-08-21 05:37:33 +08007274#ifdef TARGET_NR_rmdir
bellard31e31b82003-02-18 22:55:36 +00007275 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00007276 if (!(p = lock_user_string(arg1)))
7277 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007278 ret = get_errno(rmdir(p));
7279 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007280 break;
Chen Gang704eff62015-08-21 05:37:33 +08007281#endif
bellard31e31b82003-02-18 22:55:36 +00007282 case TARGET_NR_dup:
7283 ret = get_errno(dup(arg1));
Laurent Viviere36800c2015-10-02 14:48:09 +02007284 if (ret >= 0) {
7285 fd_trans_dup(arg1, ret);
7286 }
bellard31e31b82003-02-18 22:55:36 +00007287 break;
Chen Gang704eff62015-08-21 05:37:33 +08007288#ifdef TARGET_NR_pipe
bellard31e31b82003-02-18 22:55:36 +00007289 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07007290 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00007291 break;
Chen Gang704eff62015-08-21 05:37:33 +08007292#endif
Riku Voipio099d6b02009-05-05 12:10:04 +03007293#ifdef TARGET_NR_pipe2
7294 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07007295 ret = do_pipe(cpu_env, arg1,
7296 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03007297 break;
7298#endif
bellard31e31b82003-02-18 22:55:36 +00007299 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00007300 {
pbrook53a59602006-03-25 19:31:22 +00007301 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00007302 struct tms tms;
7303 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00007304 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00007305 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
7306 if (!tmsp)
7307 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007308 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
7309 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
7310 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
7311 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00007312 }
bellardc596ed12003-07-13 17:32:31 +00007313 if (!is_error(ret))
7314 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00007315 }
7316 break;
bellardebc05482003-09-30 21:08:41 +00007317#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00007318 case TARGET_NR_prof:
7319 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007320#endif
thse5febef2007-04-01 18:31:35 +00007321#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00007322 case TARGET_NR_signal:
7323 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007324#endif
bellard31e31b82003-02-18 22:55:36 +00007325 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00007326 if (arg1 == 0) {
7327 ret = get_errno(acct(NULL));
7328 } else {
7329 if (!(p = lock_user_string(arg1)))
7330 goto efault;
7331 ret = get_errno(acct(path(p)));
7332 unlock_user(p, arg1, 0);
7333 }
pbrook24836682006-04-16 14:14:53 +00007334 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10007335#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00007336 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00007337 if (!(p = lock_user_string(arg1)))
7338 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007339 ret = get_errno(umount2(p, arg2));
7340 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007341 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007342#endif
bellardebc05482003-09-30 21:08:41 +00007343#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00007344 case TARGET_NR_lock:
7345 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007346#endif
bellard31e31b82003-02-18 22:55:36 +00007347 case TARGET_NR_ioctl:
7348 ret = do_ioctl(arg1, arg2, arg3);
7349 break;
7350 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00007351 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00007352 break;
bellardebc05482003-09-30 21:08:41 +00007353#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00007354 case TARGET_NR_mpx:
7355 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007356#endif
bellard31e31b82003-02-18 22:55:36 +00007357 case TARGET_NR_setpgid:
7358 ret = get_errno(setpgid(arg1, arg2));
7359 break;
bellardebc05482003-09-30 21:08:41 +00007360#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00007361 case TARGET_NR_ulimit:
7362 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007363#endif
7364#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00007365 case TARGET_NR_oldolduname:
7366 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007367#endif
bellard31e31b82003-02-18 22:55:36 +00007368 case TARGET_NR_umask:
7369 ret = get_errno(umask(arg1));
7370 break;
7371 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00007372 if (!(p = lock_user_string(arg1)))
7373 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007374 ret = get_errno(chroot(p));
7375 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007376 break;
Chen Gang704eff62015-08-21 05:37:33 +08007377#ifdef TARGET_NR_ustat
bellard31e31b82003-02-18 22:55:36 +00007378 case TARGET_NR_ustat:
7379 goto unimplemented;
Chen Gang704eff62015-08-21 05:37:33 +08007380#endif
7381#ifdef TARGET_NR_dup2
bellard31e31b82003-02-18 22:55:36 +00007382 case TARGET_NR_dup2:
7383 ret = get_errno(dup2(arg1, arg2));
Laurent Viviere36800c2015-10-02 14:48:09 +02007384 if (ret >= 0) {
7385 fd_trans_dup(arg1, arg2);
7386 }
bellard31e31b82003-02-18 22:55:36 +00007387 break;
Chen Gang704eff62015-08-21 05:37:33 +08007388#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03007389#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
7390 case TARGET_NR_dup3:
7391 ret = get_errno(dup3(arg1, arg2, arg3));
Laurent Viviere36800c2015-10-02 14:48:09 +02007392 if (ret >= 0) {
7393 fd_trans_dup(arg1, arg2);
7394 }
Ulrich Hechtd0927932009-09-17 20:22:14 +03007395 break;
7396#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007397#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007398 case TARGET_NR_getppid:
7399 ret = get_errno(getppid());
7400 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007401#endif
Chen Gang704eff62015-08-21 05:37:33 +08007402#ifdef TARGET_NR_getpgrp
bellard31e31b82003-02-18 22:55:36 +00007403 case TARGET_NR_getpgrp:
7404 ret = get_errno(getpgrp());
7405 break;
Chen Gang704eff62015-08-21 05:37:33 +08007406#endif
bellard31e31b82003-02-18 22:55:36 +00007407 case TARGET_NR_setsid:
7408 ret = get_errno(setsid());
7409 break;
thse5febef2007-04-01 18:31:35 +00007410#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00007411 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00007412 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007413#if defined(TARGET_ALPHA)
7414 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00007415 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00007416 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007417 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7418 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007419 act._sa_handler = old_act->_sa_handler;
7420 target_siginitset(&act.sa_mask, old_act->sa_mask);
7421 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08007422 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00007423 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007424 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00007425 }
7426 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00007427 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007428 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7429 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007430 old_act->_sa_handler = oact._sa_handler;
7431 old_act->sa_mask = oact.sa_mask.sig[0];
7432 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00007433 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00007434 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007435#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00007436 struct target_sigaction act, oact, *pact, *old_act;
7437
7438 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00007439 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7440 goto efault;
bellard106ec872006-06-27 21:08:10 +00007441 act._sa_handler = old_act->_sa_handler;
7442 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
7443 act.sa_flags = old_act->sa_flags;
7444 unlock_user_struct(old_act, arg2, 0);
7445 pact = &act;
7446 } else {
7447 pact = NULL;
7448 }
7449
7450 ret = get_errno(do_sigaction(arg1, pact, &oact));
7451
7452 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00007453 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7454 goto efault;
bellard106ec872006-06-27 21:08:10 +00007455 old_act->_sa_handler = oact._sa_handler;
7456 old_act->sa_flags = oact.sa_flags;
7457 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
7458 old_act->sa_mask.sig[1] = 0;
7459 old_act->sa_mask.sig[2] = 0;
7460 old_act->sa_mask.sig[3] = 0;
7461 unlock_user_struct(old_act, arg3, 1);
7462 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08007463#else
7464 struct target_old_sigaction *old_act;
7465 struct target_sigaction act, oact, *pact;
7466 if (arg2) {
7467 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
7468 goto efault;
7469 act._sa_handler = old_act->_sa_handler;
7470 target_siginitset(&act.sa_mask, old_act->sa_mask);
7471 act.sa_flags = old_act->sa_flags;
7472 act.sa_restorer = old_act->sa_restorer;
7473 unlock_user_struct(old_act, arg2, 0);
7474 pact = &act;
7475 } else {
7476 pact = NULL;
7477 }
7478 ret = get_errno(do_sigaction(arg1, pact, &oact));
7479 if (!is_error(ret) && arg3) {
7480 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
7481 goto efault;
7482 old_act->_sa_handler = oact._sa_handler;
7483 old_act->sa_mask = oact.sa_mask.sig[0];
7484 old_act->sa_flags = oact.sa_flags;
7485 old_act->sa_restorer = oact.sa_restorer;
7486 unlock_user_struct(old_act, arg3, 1);
7487 }
ths388bb212007-05-13 13:58:00 +00007488#endif
bellard31e31b82003-02-18 22:55:36 +00007489 }
7490 break;
thse5febef2007-04-01 18:31:35 +00007491#endif
bellard66fb9762003-03-23 01:06:05 +00007492 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00007493 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08007494#if defined(TARGET_ALPHA)
7495 struct target_sigaction act, oact, *pact = 0;
7496 struct target_rt_sigaction *rt_act;
7497 /* ??? arg4 == sizeof(sigset_t). */
7498 if (arg2) {
7499 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
7500 goto efault;
7501 act._sa_handler = rt_act->_sa_handler;
7502 act.sa_mask = rt_act->sa_mask;
7503 act.sa_flags = rt_act->sa_flags;
7504 act.sa_restorer = arg5;
7505 unlock_user_struct(rt_act, arg2, 0);
7506 pact = &act;
7507 }
7508 ret = get_errno(do_sigaction(arg1, pact, &oact));
7509 if (!is_error(ret) && arg3) {
7510 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
7511 goto efault;
7512 rt_act->_sa_handler = oact._sa_handler;
7513 rt_act->sa_mask = oact.sa_mask;
7514 rt_act->sa_flags = oact.sa_flags;
7515 unlock_user_struct(rt_act, arg3, 1);
7516 }
7517#else
pbrook53a59602006-03-25 19:31:22 +00007518 struct target_sigaction *act;
7519 struct target_sigaction *oact;
7520
bellard579a97f2007-11-11 14:26:47 +00007521 if (arg2) {
7522 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
7523 goto efault;
7524 } else
pbrook53a59602006-03-25 19:31:22 +00007525 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00007526 if (arg3) {
7527 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
7528 ret = -TARGET_EFAULT;
7529 goto rt_sigaction_fail;
7530 }
7531 } else
pbrook53a59602006-03-25 19:31:22 +00007532 oact = NULL;
7533 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00007534 rt_sigaction_fail:
7535 if (act)
pbrook53a59602006-03-25 19:31:22 +00007536 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007537 if (oact)
pbrook53a59602006-03-25 19:31:22 +00007538 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08007539#endif
pbrook53a59602006-03-25 19:31:22 +00007540 }
bellard66fb9762003-03-23 01:06:05 +00007541 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007542#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007543 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00007544 {
7545 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007546 abi_ulong target_set;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007547 ret = do_sigprocmask(0, NULL, &cur_set);
7548 if (!ret) {
7549 host_to_target_old_sigset(&target_set, &cur_set);
7550 ret = target_set;
7551 }
bellard66fb9762003-03-23 01:06:05 +00007552 }
7553 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007554#endif
7555#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007556 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00007557 {
7558 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00007559 abi_ulong target_set = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007560 /* We only have one word of the new mask so we must read
7561 * the rest of it with do_sigprocmask() and OR in this word.
7562 * We are guaranteed that a do_sigprocmask() that only queries
7563 * the signal mask will not fail.
7564 */
7565 ret = do_sigprocmask(0, NULL, &cur_set);
7566 assert(!ret);
bellard66fb9762003-03-23 01:06:05 +00007567 target_to_host_old_sigset(&set, &target_set);
7568 sigorset(&set, &set, &cur_set);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007569 ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
7570 if (!ret) {
7571 host_to_target_old_sigset(&target_set, &oset);
7572 ret = target_set;
7573 }
bellard66fb9762003-03-23 01:06:05 +00007574 }
7575 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007576#endif
thse5febef2007-04-01 18:31:35 +00007577#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00007578 case TARGET_NR_sigprocmask:
7579 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007580#if defined(TARGET_ALPHA)
7581 sigset_t set, oldset;
7582 abi_ulong mask;
7583 int how;
7584
7585 switch (arg1) {
7586 case TARGET_SIG_BLOCK:
7587 how = SIG_BLOCK;
7588 break;
7589 case TARGET_SIG_UNBLOCK:
7590 how = SIG_UNBLOCK;
7591 break;
7592 case TARGET_SIG_SETMASK:
7593 how = SIG_SETMASK;
7594 break;
7595 default:
7596 ret = -TARGET_EINVAL;
7597 goto fail;
7598 }
7599 mask = arg2;
7600 target_to_host_old_sigset(&set, &mask);
7601
Peter Maydell3d3efba2016-05-27 15:51:49 +01007602 ret = do_sigprocmask(how, &set, &oldset);
Richard Hendersona5b3b132010-05-03 10:07:55 -07007603 if (!is_error(ret)) {
7604 host_to_target_old_sigset(&mask, &oldset);
7605 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07007606 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07007607 }
7608#else
bellard66fb9762003-03-23 01:06:05 +00007609 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07007610 int how;
ths3b46e622007-09-17 08:09:54 +00007611
pbrook53a59602006-03-25 19:31:22 +00007612 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07007613 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00007614 case TARGET_SIG_BLOCK:
7615 how = SIG_BLOCK;
7616 break;
7617 case TARGET_SIG_UNBLOCK:
7618 how = SIG_UNBLOCK;
7619 break;
7620 case TARGET_SIG_SETMASK:
7621 how = SIG_SETMASK;
7622 break;
7623 default:
ths0da46a62007-10-20 20:23:07 +00007624 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007625 goto fail;
7626 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007627 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007628 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007629 target_to_host_old_sigset(&set, p);
7630 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007631 set_ptr = &set;
7632 } else {
7633 how = 0;
7634 set_ptr = NULL;
7635 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007636 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007637 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007638 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007639 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007640 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007641 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007642 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07007643#endif
bellard66fb9762003-03-23 01:06:05 +00007644 }
7645 break;
thse5febef2007-04-01 18:31:35 +00007646#endif
bellard66fb9762003-03-23 01:06:05 +00007647 case TARGET_NR_rt_sigprocmask:
7648 {
7649 int how = arg1;
7650 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00007651
pbrook53a59602006-03-25 19:31:22 +00007652 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007653 switch(how) {
7654 case TARGET_SIG_BLOCK:
7655 how = SIG_BLOCK;
7656 break;
7657 case TARGET_SIG_UNBLOCK:
7658 how = SIG_UNBLOCK;
7659 break;
7660 case TARGET_SIG_SETMASK:
7661 how = SIG_SETMASK;
7662 break;
7663 default:
ths0da46a62007-10-20 20:23:07 +00007664 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00007665 goto fail;
7666 }
Anthony Liguoric227f092009-10-01 16:12:16 -05007667 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007668 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007669 target_to_host_sigset(&set, p);
7670 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00007671 set_ptr = &set;
7672 } else {
7673 how = 0;
7674 set_ptr = NULL;
7675 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01007676 ret = do_sigprocmask(how, set_ptr, &oldset);
pbrook53a59602006-03-25 19:31:22 +00007677 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007678 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007679 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007680 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05007681 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007682 }
7683 }
7684 break;
thse5febef2007-04-01 18:31:35 +00007685#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00007686 case TARGET_NR_sigpending:
7687 {
7688 sigset_t set;
7689 ret = get_errno(sigpending(&set));
7690 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007691 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007692 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007693 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007694 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007695 }
7696 }
7697 break;
thse5febef2007-04-01 18:31:35 +00007698#endif
bellard66fb9762003-03-23 01:06:05 +00007699 case TARGET_NR_rt_sigpending:
7700 {
7701 sigset_t set;
7702 ret = get_errno(sigpending(&set));
7703 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05007704 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00007705 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007706 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05007707 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00007708 }
7709 }
7710 break;
thse5febef2007-04-01 18:31:35 +00007711#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00007712 case TARGET_NR_sigsuspend:
7713 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007714 TaskState *ts = cpu->opaque;
Richard Hendersonf43ce122010-05-03 10:07:54 -07007715#if defined(TARGET_ALPHA)
7716 abi_ulong mask = arg1;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007717 target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007718#else
Anthony Liguoric227f092009-10-01 16:12:16 -05007719 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007720 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007721 target_to_host_old_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007722 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07007723#endif
Peter Maydell3d3efba2016-05-27 15:51:49 +01007724 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7725 SIGSET_T_SIZE));
7726 if (ret != -TARGET_ERESTARTSYS) {
7727 ts->in_sigsuspend = 1;
7728 }
bellard66fb9762003-03-23 01:06:05 +00007729 }
7730 break;
thse5febef2007-04-01 18:31:35 +00007731#endif
bellard66fb9762003-03-23 01:06:05 +00007732 case TARGET_NR_rt_sigsuspend:
7733 {
Peter Maydell3d3efba2016-05-27 15:51:49 +01007734 TaskState *ts = cpu->opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05007735 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007736 goto efault;
Peter Maydell3d3efba2016-05-27 15:51:49 +01007737 target_to_host_sigset(&ts->sigsuspend_mask, p);
pbrook53a59602006-03-25 19:31:22 +00007738 unlock_user(p, arg1, 0);
Peter Maydell3d3efba2016-05-27 15:51:49 +01007739 ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
7740 SIGSET_T_SIZE));
7741 if (ret != -TARGET_ERESTARTSYS) {
7742 ts->in_sigsuspend = 1;
7743 }
bellard66fb9762003-03-23 01:06:05 +00007744 }
7745 break;
7746 case TARGET_NR_rt_sigtimedwait:
7747 {
bellard66fb9762003-03-23 01:06:05 +00007748 sigset_t set;
7749 struct timespec uts, *puts;
7750 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00007751
Anthony Liguoric227f092009-10-01 16:12:16 -05007752 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007753 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007754 target_to_host_sigset(&set, p);
7755 unlock_user(p, arg1, 0);
7756 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00007757 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00007758 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00007759 } else {
7760 puts = NULL;
7761 }
Peter Maydellb3f82332016-06-06 19:58:08 +01007762 ret = get_errno(safe_rt_sigtimedwait(&set, &uinfo, puts,
7763 SIGSET_T_SIZE));
Petar Jovanovic974a1962014-03-03 15:07:41 +01007764 if (!is_error(ret)) {
7765 if (arg2) {
7766 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
7767 0);
7768 if (!p) {
7769 goto efault;
7770 }
7771 host_to_target_siginfo(p, &uinfo);
7772 unlock_user(p, arg2, sizeof(target_siginfo_t));
7773 }
7774 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00007775 }
7776 }
7777 break;
7778 case TARGET_NR_rt_sigqueueinfo:
7779 {
7780 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05007781 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00007782 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007783 target_to_host_siginfo(&uinfo, p);
7784 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00007785 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
7786 }
7787 break;
thse5febef2007-04-01 18:31:35 +00007788#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00007789 case TARGET_NR_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007790 if (block_signals()) {
7791 ret = -TARGET_ERESTARTSYS;
7792 } else {
7793 ret = do_sigreturn(cpu_env);
7794 }
bellard66fb9762003-03-23 01:06:05 +00007795 break;
thse5febef2007-04-01 18:31:35 +00007796#endif
bellard66fb9762003-03-23 01:06:05 +00007797 case TARGET_NR_rt_sigreturn:
Peter Maydell3d3efba2016-05-27 15:51:49 +01007798 if (block_signals()) {
7799 ret = -TARGET_ERESTARTSYS;
7800 } else {
7801 ret = do_rt_sigreturn(cpu_env);
7802 }
bellard66fb9762003-03-23 01:06:05 +00007803 break;
bellard31e31b82003-02-18 22:55:36 +00007804 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00007805 if (!(p = lock_user_string(arg1)))
7806 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007807 ret = get_errno(sethostname(p, arg2));
7808 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007809 break;
7810 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00007811 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007812 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007813 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007814 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00007815 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
7816 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007817 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
7818 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007819 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00007820 ret = get_errno(setrlimit(resource, &rlim));
7821 }
7822 break;
bellard31e31b82003-02-18 22:55:36 +00007823 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00007824 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007825 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00007826 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00007827 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00007828
bellard9de5e442003-03-23 16:49:39 +00007829 ret = get_errno(getrlimit(resource, &rlim));
7830 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007831 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7832 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007833 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7834 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007835 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00007836 }
7837 }
7838 break;
bellard31e31b82003-02-18 22:55:36 +00007839 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00007840 {
7841 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00007842 ret = get_errno(getrusage(arg1, &rusage));
7843 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02007844 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00007845 }
7846 }
7847 break;
bellard31e31b82003-02-18 22:55:36 +00007848 case TARGET_NR_gettimeofday:
7849 {
bellard31e31b82003-02-18 22:55:36 +00007850 struct timeval tv;
7851 ret = get_errno(gettimeofday(&tv, NULL));
7852 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00007853 if (copy_to_user_timeval(arg1, &tv))
7854 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007855 }
7856 }
7857 break;
7858 case TARGET_NR_settimeofday:
7859 {
Paul Burtonb67d8032014-06-22 11:25:41 +01007860 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01007861 struct timezone tz, *ptz = NULL;
7862
Paul Burtonb67d8032014-06-22 11:25:41 +01007863 if (arg1) {
7864 if (copy_from_user_timeval(&tv, arg1)) {
7865 goto efault;
7866 }
7867 ptv = &tv;
7868 }
Paul Burtonef4467e2014-06-22 11:25:40 +01007869
7870 if (arg2) {
7871 if (copy_from_user_timezone(&tz, arg2)) {
7872 goto efault;
7873 }
7874 ptz = &tz;
7875 }
7876
Paul Burtonb67d8032014-06-22 11:25:41 +01007877 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00007878 }
7879 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007880#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00007881 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007882#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
7883 ret = do_select(arg1, arg2, arg3, arg4, arg5);
7884#else
bellardf2674e32003-07-09 12:26:09 +00007885 {
pbrook53a59602006-03-25 19:31:22 +00007886 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00007887 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00007888 long nsel;
7889
bellard579a97f2007-11-11 14:26:47 +00007890 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
7891 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007892 nsel = tswapal(sel->n);
7893 inp = tswapal(sel->inp);
7894 outp = tswapal(sel->outp);
7895 exp = tswapal(sel->exp);
7896 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00007897 unlock_user_struct(sel, arg1, 0);
7898 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00007899 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007900#endif
bellardf2674e32003-07-09 12:26:09 +00007901 break;
bellard048f6b42005-11-26 18:47:20 +00007902#endif
Riku Voipio9e423822010-05-07 12:28:05 +00007903#ifdef TARGET_NR_pselect6
7904 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04007905 {
7906 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
7907 fd_set rfds, wfds, efds;
7908 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
7909 struct timespec ts, *ts_ptr;
7910
7911 /*
7912 * The 6th arg is actually two args smashed together,
7913 * so we cannot use the C library.
7914 */
7915 sigset_t set;
7916 struct {
7917 sigset_t *set;
7918 size_t size;
7919 } sig, *sig_ptr;
7920
7921 abi_ulong arg_sigset, arg_sigsize, *arg7;
7922 target_sigset_t *target_sigset;
7923
7924 n = arg1;
7925 rfd_addr = arg2;
7926 wfd_addr = arg3;
7927 efd_addr = arg4;
7928 ts_addr = arg5;
7929
7930 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
7931 if (ret) {
7932 goto fail;
7933 }
7934 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
7935 if (ret) {
7936 goto fail;
7937 }
7938 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
7939 if (ret) {
7940 goto fail;
7941 }
7942
7943 /*
7944 * This takes a timespec, and not a timeval, so we cannot
7945 * use the do_select() helper ...
7946 */
7947 if (ts_addr) {
7948 if (target_to_host_timespec(&ts, ts_addr)) {
7949 goto efault;
7950 }
7951 ts_ptr = &ts;
7952 } else {
7953 ts_ptr = NULL;
7954 }
7955
7956 /* Extract the two packed args for the sigset */
7957 if (arg6) {
7958 sig_ptr = &sig;
Peter Maydellb28a1f32016-05-27 15:51:47 +01007959 sig.size = SIGSET_T_SIZE;
Mike Frysinger055e0902011-06-03 17:01:49 -04007960
7961 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
7962 if (!arg7) {
7963 goto efault;
7964 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007965 arg_sigset = tswapal(arg7[0]);
7966 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04007967 unlock_user(arg7, arg6, 0);
7968
7969 if (arg_sigset) {
7970 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01007971 if (arg_sigsize != sizeof(*target_sigset)) {
7972 /* Like the kernel, we enforce correct size sigsets */
7973 ret = -TARGET_EINVAL;
7974 goto fail;
7975 }
Mike Frysinger055e0902011-06-03 17:01:49 -04007976 target_sigset = lock_user(VERIFY_READ, arg_sigset,
7977 sizeof(*target_sigset), 1);
7978 if (!target_sigset) {
7979 goto efault;
7980 }
7981 target_to_host_sigset(&set, target_sigset);
7982 unlock_user(target_sigset, arg_sigset, 0);
7983 } else {
7984 sig.set = NULL;
7985 }
7986 } else {
7987 sig_ptr = NULL;
7988 }
7989
Peter Maydell6df9d382016-05-12 18:47:51 +01007990 ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
7991 ts_ptr, sig_ptr));
Mike Frysinger055e0902011-06-03 17:01:49 -04007992
7993 if (!is_error(ret)) {
7994 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
7995 goto efault;
7996 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
7997 goto efault;
7998 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
7999 goto efault;
8000
8001 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
8002 goto efault;
8003 }
8004 }
8005 break;
Riku Voipio9e423822010-05-07 12:28:05 +00008006#endif
Chen Gang704eff62015-08-21 05:37:33 +08008007#ifdef TARGET_NR_symlink
bellard31e31b82003-02-18 22:55:36 +00008008 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00008009 {
8010 void *p2;
8011 p = lock_user_string(arg1);
8012 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008013 if (!p || !p2)
8014 ret = -TARGET_EFAULT;
8015 else
8016 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00008017 unlock_user(p2, arg2, 0);
8018 unlock_user(p, arg1, 0);
8019 }
bellard31e31b82003-02-18 22:55:36 +00008020 break;
Chen Gang704eff62015-08-21 05:37:33 +08008021#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008022#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00008023 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00008024 {
bellard579a97f2007-11-11 14:26:47 +00008025 void *p2;
thsf0b62432007-09-24 09:25:40 +00008026 p = lock_user_string(arg1);
8027 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00008028 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00008029 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00008030 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01008031 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00008032 unlock_user(p2, arg3, 0);
8033 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00008034 }
8035 break;
8036#endif
bellardebc05482003-09-30 21:08:41 +00008037#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00008038 case TARGET_NR_oldlstat:
8039 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008040#endif
Chen Gang704eff62015-08-21 05:37:33 +08008041#ifdef TARGET_NR_readlink
bellard31e31b82003-02-18 22:55:36 +00008042 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00008043 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01008044 void *p2;
pbrook53a59602006-03-25 19:31:22 +00008045 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00008046 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008047 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00008048 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09008049 } else if (!arg3) {
8050 /* Short circuit this for the magic exe check. */
8051 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01008052 } else if (is_proc_myself((const char *)p, "exe")) {
8053 char real[PATH_MAX], *temp;
8054 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09008055 /* Return value is # of bytes that we wrote to the buffer. */
8056 if (temp == NULL) {
8057 ret = get_errno(-1);
8058 } else {
8059 /* Don't worry about sign mismatch as earlier mapping
8060 * logic would have thrown a bad address error. */
8061 ret = MIN(strlen(real), arg3);
8062 /* We cannot NUL terminate the string. */
8063 memcpy(p2, real, ret);
8064 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01008065 } else {
8066 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00008067 }
pbrook53a59602006-03-25 19:31:22 +00008068 unlock_user(p2, arg2, ret);
8069 unlock_user(p, arg1, 0);
8070 }
bellard31e31b82003-02-18 22:55:36 +00008071 break;
Chen Gang704eff62015-08-21 05:37:33 +08008072#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008073#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00008074 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00008075 {
bellard579a97f2007-11-11 14:26:47 +00008076 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00008077 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00008078 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01008079 if (!p || !p2) {
8080 ret = -TARGET_EFAULT;
8081 } else if (is_proc_myself((const char *)p, "exe")) {
8082 char real[PATH_MAX], *temp;
8083 temp = realpath(exec_path, real);
8084 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
8085 snprintf((char *)p2, arg4, "%s", real);
8086 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01008087 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01008088 }
bellard579a97f2007-11-11 14:26:47 +00008089 unlock_user(p2, arg3, ret);
8090 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00008091 }
8092 break;
8093#endif
thse5febef2007-04-01 18:31:35 +00008094#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00008095 case TARGET_NR_uselib:
8096 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008097#endif
8098#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00008099 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00008100 if (!(p = lock_user_string(arg1)))
8101 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008102 ret = get_errno(swapon(p, arg2));
8103 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008104 break;
thse5febef2007-04-01 18:31:35 +00008105#endif
bellard31e31b82003-02-18 22:55:36 +00008106 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00008107 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
8108 /* arg4 must be ignored in all other cases */
8109 p = lock_user_string(arg4);
8110 if (!p) {
8111 goto efault;
8112 }
8113 ret = get_errno(reboot(arg1, arg2, arg3, p));
8114 unlock_user(p, arg4, 0);
8115 } else {
8116 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
8117 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02008118 break;
thse5febef2007-04-01 18:31:35 +00008119#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00008120 case TARGET_NR_readdir:
8121 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008122#endif
8123#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00008124 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01008125#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
8126 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008127 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
8128 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00008129 {
blueswir1992f48a2007-10-14 16:27:31 +00008130 abi_ulong *v;
8131 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00008132 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
8133 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008134 v1 = tswapal(v[0]);
8135 v2 = tswapal(v[1]);
8136 v3 = tswapal(v[2]);
8137 v4 = tswapal(v[3]);
8138 v5 = tswapal(v[4]);
8139 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00008140 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00008141 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00008142 target_to_host_bitmask(v4, mmap_flags_tbl),
8143 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00008144 }
bellard31e31b82003-02-18 22:55:36 +00008145#else
ths5fafdf22007-09-16 21:08:06 +00008146 ret = get_errno(target_mmap(arg1, arg2, arg3,
8147 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00008148 arg5,
8149 arg6));
bellard31e31b82003-02-18 22:55:36 +00008150#endif
bellard6fb883e2003-07-09 17:12:39 +00008151 break;
thse5febef2007-04-01 18:31:35 +00008152#endif
bellarda315a142005-01-30 22:59:18 +00008153#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00008154 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00008155#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00008156#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00008157#endif
ths5fafdf22007-09-16 21:08:06 +00008158 ret = get_errno(target_mmap(arg1, arg2, arg3,
8159 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00008160 arg5,
bellardc573ff62004-01-04 15:51:36 +00008161 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00008162 break;
bellarda315a142005-01-30 22:59:18 +00008163#endif
bellard31e31b82003-02-18 22:55:36 +00008164 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00008165 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00008166 break;
bellard9de5e442003-03-23 16:49:39 +00008167 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01008168 {
Andreas Färber0429a972013-08-26 18:14:44 +02008169 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01008170 /* Special hack to detect libc making the stack executable. */
8171 if ((arg3 & PROT_GROWSDOWN)
8172 && arg1 >= ts->info->stack_limit
8173 && arg1 <= ts->info->start_stack) {
8174 arg3 &= ~PROT_GROWSDOWN;
8175 arg2 = arg2 + arg1 - ts->info->stack_limit;
8176 arg1 = ts->info->stack_limit;
8177 }
8178 }
bellard54936002003-05-13 00:25:15 +00008179 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008180 break;
thse5febef2007-04-01 18:31:35 +00008181#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00008182 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00008183 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00008184 break;
thse5febef2007-04-01 18:31:35 +00008185#endif
pbrook53a59602006-03-25 19:31:22 +00008186 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00008187#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00008188 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00008189 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00008190 break;
thse5febef2007-04-01 18:31:35 +00008191#endif
8192#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00008193 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00008194 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008195 break;
thse5febef2007-04-01 18:31:35 +00008196#endif
8197#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00008198 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00008199 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00008200 break;
thse5febef2007-04-01 18:31:35 +00008201#endif
8202#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00008203 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05008204 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00008205 break;
thse5febef2007-04-01 18:31:35 +00008206#endif
8207#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00008208 case TARGET_NR_munlockall:
8209 ret = get_errno(munlockall());
8210 break;
thse5febef2007-04-01 18:31:35 +00008211#endif
bellard31e31b82003-02-18 22:55:36 +00008212 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00008213 if (!(p = lock_user_string(arg1)))
8214 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008215 ret = get_errno(truncate(p, arg2));
8216 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008217 break;
8218 case TARGET_NR_ftruncate:
8219 ret = get_errno(ftruncate(arg1, arg2));
8220 break;
8221 case TARGET_NR_fchmod:
8222 ret = get_errno(fchmod(arg1, arg2));
8223 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008224#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00008225 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00008226 if (!(p = lock_user_string(arg2)))
8227 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008228 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00008229 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00008230 break;
8231#endif
bellard31e31b82003-02-18 22:55:36 +00008232 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07008233 /* Note that negative values are valid for getpriority, so we must
8234 differentiate based on errno settings. */
8235 errno = 0;
8236 ret = getpriority(arg1, arg2);
8237 if (ret == -1 && errno != 0) {
8238 ret = -host_to_target_errno(errno);
8239 break;
8240 }
8241#ifdef TARGET_ALPHA
8242 /* Return value is the unbiased priority. Signal no error. */
8243 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
8244#else
8245 /* Return value is a biased priority to avoid negative numbers. */
8246 ret = 20 - ret;
8247#endif
bellard31e31b82003-02-18 22:55:36 +00008248 break;
8249 case TARGET_NR_setpriority:
8250 ret = get_errno(setpriority(arg1, arg2, arg3));
8251 break;
bellardebc05482003-09-30 21:08:41 +00008252#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_profil:
8254 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008255#endif
bellard31e31b82003-02-18 22:55:36 +00008256 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00008257 if (!(p = lock_user_string(arg1)))
8258 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008259 ret = get_errno(statfs(path(p), &stfs));
8260 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008261 convert_statfs:
8262 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008263 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008264
bellard579a97f2007-11-11 14:26:47 +00008265 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
8266 goto efault;
8267 __put_user(stfs.f_type, &target_stfs->f_type);
8268 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8269 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8270 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8271 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8272 __put_user(stfs.f_files, &target_stfs->f_files);
8273 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8274 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8275 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8276 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008277 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8278 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00008279 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008280 }
8281 break;
8282 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00008283 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00008284 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00008285#ifdef TARGET_NR_statfs64
8286 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00008287 if (!(p = lock_user_string(arg1)))
8288 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008289 ret = get_errno(statfs(path(p), &stfs));
8290 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00008291 convert_statfs64:
8292 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008293 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00008294
bellard579a97f2007-11-11 14:26:47 +00008295 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
8296 goto efault;
8297 __put_user(stfs.f_type, &target_stfs->f_type);
8298 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
8299 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
8300 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
8301 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
8302 __put_user(stfs.f_files, &target_stfs->f_files);
8303 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
8304 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
8305 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
8306 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02008307 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
8308 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00008309 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00008310 }
8311 break;
8312 case TARGET_NR_fstatfs64:
8313 ret = get_errno(fstatfs(arg1, &stfs));
8314 goto convert_statfs64;
8315#endif
bellardebc05482003-09-30 21:08:41 +00008316#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_ioperm:
8318 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008319#endif
thse5febef2007-04-01 18:31:35 +00008320#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00008321 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00008322 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00008323 break;
thse5febef2007-04-01 18:31:35 +00008324#endif
bellard3532fa72006-06-24 15:06:03 +00008325#ifdef TARGET_NR_accept
8326 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00008327 ret = do_accept4(arg1, arg2, arg3, 0);
8328 break;
8329#endif
8330#ifdef TARGET_NR_accept4
8331 case TARGET_NR_accept4:
8332#ifdef CONFIG_ACCEPT4
8333 ret = do_accept4(arg1, arg2, arg3, arg4);
8334#else
8335 goto unimplemented;
8336#endif
bellard3532fa72006-06-24 15:06:03 +00008337 break;
8338#endif
8339#ifdef TARGET_NR_bind
8340 case TARGET_NR_bind:
8341 ret = do_bind(arg1, arg2, arg3);
8342 break;
8343#endif
8344#ifdef TARGET_NR_connect
8345 case TARGET_NR_connect:
8346 ret = do_connect(arg1, arg2, arg3);
8347 break;
8348#endif
8349#ifdef TARGET_NR_getpeername
8350 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00008351 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008352 break;
8353#endif
8354#ifdef TARGET_NR_getsockname
8355 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00008356 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00008357 break;
8358#endif
8359#ifdef TARGET_NR_getsockopt
8360 case TARGET_NR_getsockopt:
8361 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
8362 break;
8363#endif
8364#ifdef TARGET_NR_listen
8365 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00008366 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008367 break;
8368#endif
8369#ifdef TARGET_NR_recv
8370 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00008371 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008372 break;
8373#endif
8374#ifdef TARGET_NR_recvfrom
8375 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00008376 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008377 break;
8378#endif
8379#ifdef TARGET_NR_recvmsg
8380 case TARGET_NR_recvmsg:
8381 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
8382 break;
8383#endif
8384#ifdef TARGET_NR_send
8385 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00008386 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00008387 break;
8388#endif
8389#ifdef TARGET_NR_sendmsg
8390 case TARGET_NR_sendmsg:
8391 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
8392 break;
8393#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00008394#ifdef TARGET_NR_sendmmsg
8395 case TARGET_NR_sendmmsg:
8396 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
8397 break;
8398 case TARGET_NR_recvmmsg:
8399 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
8400 break;
8401#endif
bellard3532fa72006-06-24 15:06:03 +00008402#ifdef TARGET_NR_sendto
8403 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00008404 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00008405 break;
8406#endif
8407#ifdef TARGET_NR_shutdown
8408 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00008409 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00008410 break;
8411#endif
Laurent Vivierf894efd2016-02-21 10:56:23 +01008412#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
8413 case TARGET_NR_getrandom:
8414 p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
8415 if (!p) {
8416 goto efault;
8417 }
8418 ret = get_errno(getrandom(p, arg2, arg3));
8419 unlock_user(p, arg1, ret);
8420 break;
8421#endif
bellard3532fa72006-06-24 15:06:03 +00008422#ifdef TARGET_NR_socket
8423 case TARGET_NR_socket:
8424 ret = do_socket(arg1, arg2, arg3);
Laurent Viviere36800c2015-10-02 14:48:09 +02008425 fd_trans_unregister(ret);
bellard3532fa72006-06-24 15:06:03 +00008426 break;
8427#endif
8428#ifdef TARGET_NR_socketpair
8429 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00008430 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00008431 break;
8432#endif
8433#ifdef TARGET_NR_setsockopt
8434 case TARGET_NR_setsockopt:
8435 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
8436 break;
8437#endif
ths7494b0f2007-02-11 18:26:53 +00008438
bellard31e31b82003-02-18 22:55:36 +00008439 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00008440 if (!(p = lock_user_string(arg2)))
8441 goto efault;
thse5574482007-02-11 20:03:13 +00008442 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
8443 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00008444 break;
8445
bellard31e31b82003-02-18 22:55:36 +00008446 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00008447 {
bellard66fb9762003-03-23 01:06:05 +00008448 struct itimerval value, ovalue, *pvalue;
8449
pbrook53a59602006-03-25 19:31:22 +00008450 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00008451 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00008452 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
8453 || copy_from_user_timeval(&pvalue->it_value,
8454 arg2 + sizeof(struct target_timeval)))
8455 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008456 } else {
8457 pvalue = NULL;
8458 }
8459 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00008460 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00008461 if (copy_to_user_timeval(arg3,
8462 &ovalue.it_interval)
8463 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
8464 &ovalue.it_value))
8465 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008466 }
8467 }
8468 break;
bellard31e31b82003-02-18 22:55:36 +00008469 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00008470 {
bellard66fb9762003-03-23 01:06:05 +00008471 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00008472
bellard66fb9762003-03-23 01:06:05 +00008473 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00008474 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00008475 if (copy_to_user_timeval(arg2,
8476 &value.it_interval)
8477 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
8478 &value.it_value))
8479 goto efault;
bellard66fb9762003-03-23 01:06:05 +00008480 }
8481 }
8482 break;
Chen Gang704eff62015-08-21 05:37:33 +08008483#ifdef TARGET_NR_stat
bellard31e31b82003-02-18 22:55:36 +00008484 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00008485 if (!(p = lock_user_string(arg1)))
8486 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008487 ret = get_errno(stat(path(p), &st));
8488 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008489 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008490#endif
8491#ifdef TARGET_NR_lstat
bellard31e31b82003-02-18 22:55:36 +00008492 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00008493 if (!(p = lock_user_string(arg1)))
8494 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008495 ret = get_errno(lstat(path(p), &st));
8496 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008497 goto do_stat;
Chen Gang704eff62015-08-21 05:37:33 +08008498#endif
bellard31e31b82003-02-18 22:55:36 +00008499 case TARGET_NR_fstat:
8500 {
8501 ret = get_errno(fstat(arg1, &st));
Chen Gang704eff62015-08-21 05:37:33 +08008502#if defined(TARGET_NR_stat) || defined(TARGET_NR_lstat)
bellard31e31b82003-02-18 22:55:36 +00008503 do_stat:
Chen Gang704eff62015-08-21 05:37:33 +08008504#endif
bellard31e31b82003-02-18 22:55:36 +00008505 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008506 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00008507
bellard579a97f2007-11-11 14:26:47 +00008508 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
8509 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02008510 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00008511 __put_user(st.st_dev, &target_st->st_dev);
8512 __put_user(st.st_ino, &target_st->st_ino);
8513 __put_user(st.st_mode, &target_st->st_mode);
8514 __put_user(st.st_uid, &target_st->st_uid);
8515 __put_user(st.st_gid, &target_st->st_gid);
8516 __put_user(st.st_nlink, &target_st->st_nlink);
8517 __put_user(st.st_rdev, &target_st->st_rdev);
8518 __put_user(st.st_size, &target_st->st_size);
8519 __put_user(st.st_blksize, &target_st->st_blksize);
8520 __put_user(st.st_blocks, &target_st->st_blocks);
8521 __put_user(st.st_atime, &target_st->target_st_atime);
8522 __put_user(st.st_mtime, &target_st->target_st_mtime);
8523 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00008524 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00008525 }
8526 }
8527 break;
bellardebc05482003-09-30 21:08:41 +00008528#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00008529 case TARGET_NR_olduname:
8530 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008531#endif
8532#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00008533 case TARGET_NR_iopl:
8534 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008535#endif
bellard31e31b82003-02-18 22:55:36 +00008536 case TARGET_NR_vhangup:
8537 ret = get_errno(vhangup());
8538 break;
bellardebc05482003-09-30 21:08:41 +00008539#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00008540 case TARGET_NR_idle:
8541 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008542#endif
bellard42ad6ae2005-01-03 22:48:11 +00008543#ifdef TARGET_NR_syscall
8544 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01008545 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
8546 arg6, arg7, arg8, 0);
8547 break;
bellard42ad6ae2005-01-03 22:48:11 +00008548#endif
bellard31e31b82003-02-18 22:55:36 +00008549 case TARGET_NR_wait4:
8550 {
8551 int status;
blueswir1992f48a2007-10-14 16:27:31 +00008552 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00008553 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00008554 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02008555 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00008556 if (target_rusage)
8557 rusage_ptr = &rusage;
8558 else
8559 rusage_ptr = NULL;
Timothy E Baldwin4af80a32016-05-12 18:47:49 +01008560 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
bellard31e31b82003-02-18 22:55:36 +00008561 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01008562 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00008563 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00008564 if (put_user_s32(status, status_ptr))
8565 goto efault;
bellard31e31b82003-02-18 22:55:36 +00008566 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02008567 if (target_rusage) {
8568 rusage_err = host_to_target_rusage(target_rusage, &rusage);
8569 if (rusage_err) {
8570 ret = rusage_err;
8571 }
8572 }
bellard31e31b82003-02-18 22:55:36 +00008573 }
8574 }
8575 break;
thse5febef2007-04-01 18:31:35 +00008576#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00008577 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00008578 if (!(p = lock_user_string(arg1)))
8579 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008580 ret = get_errno(swapoff(p));
8581 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008582 break;
thse5febef2007-04-01 18:31:35 +00008583#endif
bellard31e31b82003-02-18 22:55:36 +00008584 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00008585 {
pbrook53a59602006-03-25 19:31:22 +00008586 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00008587 struct sysinfo value;
8588 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00008589 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00008590 {
bellard579a97f2007-11-11 14:26:47 +00008591 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
8592 goto efault;
bellarda5448a72004-06-19 16:59:03 +00008593 __put_user(value.uptime, &target_value->uptime);
8594 __put_user(value.loads[0], &target_value->loads[0]);
8595 __put_user(value.loads[1], &target_value->loads[1]);
8596 __put_user(value.loads[2], &target_value->loads[2]);
8597 __put_user(value.totalram, &target_value->totalram);
8598 __put_user(value.freeram, &target_value->freeram);
8599 __put_user(value.sharedram, &target_value->sharedram);
8600 __put_user(value.bufferram, &target_value->bufferram);
8601 __put_user(value.totalswap, &target_value->totalswap);
8602 __put_user(value.freeswap, &target_value->freeswap);
8603 __put_user(value.procs, &target_value->procs);
8604 __put_user(value.totalhigh, &target_value->totalhigh);
8605 __put_user(value.freehigh, &target_value->freehigh);
8606 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00008607 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00008608 }
8609 }
8610 break;
thse5febef2007-04-01 18:31:35 +00008611#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00008612 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00008613 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
8614 break;
thse5febef2007-04-01 18:31:35 +00008615#endif
aurel32e5289082009-04-18 16:16:12 +00008616#ifdef TARGET_NR_semget
8617 case TARGET_NR_semget:
8618 ret = get_errno(semget(arg1, arg2, arg3));
8619 break;
8620#endif
8621#ifdef TARGET_NR_semop
8622 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00008623 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00008624 break;
8625#endif
8626#ifdef TARGET_NR_semctl
8627 case TARGET_NR_semctl:
Stefan Weild1c002b2015-02-08 15:40:58 +01008628 ret = do_semctl(arg1, arg2, arg3, arg4);
aurel32e5289082009-04-18 16:16:12 +00008629 break;
8630#endif
aurel32eeb438c2008-10-13 21:08:55 +00008631#ifdef TARGET_NR_msgctl
8632 case TARGET_NR_msgctl:
8633 ret = do_msgctl(arg1, arg2, arg3);
8634 break;
8635#endif
8636#ifdef TARGET_NR_msgget
8637 case TARGET_NR_msgget:
8638 ret = get_errno(msgget(arg1, arg2));
8639 break;
8640#endif
8641#ifdef TARGET_NR_msgrcv
8642 case TARGET_NR_msgrcv:
8643 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
8644 break;
8645#endif
8646#ifdef TARGET_NR_msgsnd
8647 case TARGET_NR_msgsnd:
8648 ret = do_msgsnd(arg1, arg2, arg3, arg4);
8649 break;
8650#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03008651#ifdef TARGET_NR_shmget
8652 case TARGET_NR_shmget:
8653 ret = get_errno(shmget(arg1, arg2, arg3));
8654 break;
8655#endif
8656#ifdef TARGET_NR_shmctl
8657 case TARGET_NR_shmctl:
8658 ret = do_shmctl(arg1, arg2, arg3);
8659 break;
8660#endif
8661#ifdef TARGET_NR_shmat
8662 case TARGET_NR_shmat:
8663 ret = do_shmat(arg1, arg2, arg3);
8664 break;
8665#endif
8666#ifdef TARGET_NR_shmdt
8667 case TARGET_NR_shmdt:
8668 ret = do_shmdt(arg1);
8669 break;
8670#endif
bellard31e31b82003-02-18 22:55:36 +00008671 case TARGET_NR_fsync:
8672 ret = get_errno(fsync(arg1));
8673 break;
bellard31e31b82003-02-18 22:55:36 +00008674 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01008675 /* Linux manages to have three different orderings for its
8676 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
8677 * match the kernel's CONFIG_CLONE_* settings.
8678 * Microblaze is further special in that it uses a sixth
8679 * implicit argument to clone for the TLS pointer.
8680 */
8681#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02008682 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01008683#elif defined(TARGET_CLONE_BACKWARDS)
8684 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
8685#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02008686 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008687#else
Peter Maydell4ce62432013-07-16 18:44:57 +01008688 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00008689#endif
bellard1b6b0292003-03-22 17:31:38 +00008690 break;
bellardec86b0f2003-04-11 00:15:04 +00008691#ifdef __NR_exit_group
8692 /* new thread calls */
8693 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02008694#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00008695 _mcleanup();
8696#endif
bellarde9009672005-04-26 20:42:36 +00008697 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00008698 ret = get_errno(exit_group(arg1));
8699 break;
8700#endif
bellard31e31b82003-02-18 22:55:36 +00008701 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00008702 if (!(p = lock_user_string(arg1)))
8703 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008704 ret = get_errno(setdomainname(p, arg2));
8705 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00008706 break;
8707 case TARGET_NR_uname:
8708 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00008709 {
8710 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00008711
bellard579a97f2007-11-11 14:26:47 +00008712 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
8713 goto efault;
bellard29e619b2004-09-13 21:41:04 +00008714 ret = get_errno(sys_uname(buf));
8715 if (!is_error(ret)) {
8716 /* Overrite the native machine name with whatever is being
8717 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01008718 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00008719 /* Allow the user to override the reported release. */
8720 if (qemu_uname_release && *qemu_uname_release)
8721 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00008722 }
pbrook53a59602006-03-25 19:31:22 +00008723 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00008724 }
bellard31e31b82003-02-18 22:55:36 +00008725 break;
bellard6dbad632003-03-16 18:05:05 +00008726#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00008727 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00008728 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00008729 break;
j_mayer84409dd2007-04-06 08:56:50 +00008730#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00008731 case TARGET_NR_vm86old:
8732 goto unimplemented;
8733 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00008734 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00008735 break;
8736#endif
j_mayer84409dd2007-04-06 08:56:50 +00008737#endif
bellard31e31b82003-02-18 22:55:36 +00008738 case TARGET_NR_adjtimex:
8739 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008740#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00008741 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00008742#endif
bellard31e31b82003-02-18 22:55:36 +00008743 case TARGET_NR_init_module:
8744 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00008745#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00008746 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00008747#endif
bellard31e31b82003-02-18 22:55:36 +00008748 goto unimplemented;
8749 case TARGET_NR_quotactl:
8750 goto unimplemented;
8751 case TARGET_NR_getpgid:
8752 ret = get_errno(getpgid(arg1));
8753 break;
8754 case TARGET_NR_fchdir:
8755 ret = get_errno(fchdir(arg1));
8756 break;
j_mayer84409dd2007-04-06 08:56:50 +00008757#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00008758 case TARGET_NR_bdflush:
8759 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00008760#endif
thse5febef2007-04-01 18:31:35 +00008761#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00008762 case TARGET_NR_sysfs:
8763 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008764#endif
bellard31e31b82003-02-18 22:55:36 +00008765 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00008766 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00008767 break;
thse5febef2007-04-01 18:31:35 +00008768#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00008769 case TARGET_NR_afs_syscall:
8770 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00008771#endif
j_mayer7a3148a2007-04-05 07:13:51 +00008772#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00008773 case TARGET_NR__llseek:
8774 {
8775 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00008776#if !defined(__NR_llseek)
8777 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
8778 if (res == -1) {
8779 ret = get_errno(res);
8780 } else {
8781 ret = 0;
8782 }
8783#else
bellard31e31b82003-02-18 22:55:36 +00008784 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00008785#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00008786 if ((ret == 0) && put_user_s64(res, arg4)) {
8787 goto efault;
8788 }
bellard31e31b82003-02-18 22:55:36 +00008789 }
8790 break;
j_mayer7a3148a2007-04-05 07:13:51 +00008791#endif
Chen Gang704eff62015-08-21 05:37:33 +08008792#ifdef TARGET_NR_getdents
bellard31e31b82003-02-18 22:55:36 +00008793 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01008794#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02008795#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00008796 {
pbrook53a59602006-03-25 19:31:22 +00008797 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00008798 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008799 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00008800
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308801 dirp = g_try_malloc(count);
8802 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00008803 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00008804 goto fail;
8805 }
ths3b46e622007-09-17 08:09:54 +00008806
bellard4add45b2003-06-05 01:52:59 +00008807 ret = get_errno(sys_getdents(arg1, dirp, count));
8808 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008809 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00008810 struct target_dirent *tde;
8811 int len = ret;
8812 int reclen, treclen;
8813 int count1, tnamelen;
8814
8815 count1 = 0;
8816 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00008817 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8818 goto efault;
bellard4add45b2003-06-05 01:52:59 +00008819 tde = target_dirp;
8820 while (len > 0) {
8821 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008822 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
8823 assert(tnamelen >= 0);
8824 treclen = tnamelen + offsetof(struct target_dirent, d_name);
8825 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00008826 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02008827 tde->d_ino = tswapal(de->d_ino);
8828 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04008829 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00008830 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00008831 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00008832 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00008833 count1 += treclen;
8834 }
8835 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00008836 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00008837 }
Harmandeep Kaur0e173b22015-10-06 21:47:12 +05308838 g_free(dirp);
bellard4add45b2003-06-05 01:52:59 +00008839 }
8840#else
bellard31e31b82003-02-18 22:55:36 +00008841 {
aurel326556a832008-10-13 21:08:17 +00008842 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008843 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00008844
bellard579a97f2007-11-11 14:26:47 +00008845 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8846 goto efault;
bellard72f03902003-02-18 23:33:18 +00008847 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00008848 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008849 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00008850 int len = ret;
8851 int reclen;
8852 de = dirp;
8853 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008854 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00008855 if (reclen > len)
8856 break;
bellard8083a3e2003-03-24 23:12:16 +00008857 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00008858 tswapls(&de->d_ino);
8859 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008860 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00008861 len -= reclen;
8862 }
8863 }
pbrook53a59602006-03-25 19:31:22 +00008864 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00008865 }
bellard4add45b2003-06-05 01:52:59 +00008866#endif
Peter Maydell3307e232013-06-12 16:20:21 +01008867#else
8868 /* Implement getdents in terms of getdents64 */
8869 {
8870 struct linux_dirent64 *dirp;
8871 abi_long count = arg3;
8872
8873 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
8874 if (!dirp) {
8875 goto efault;
8876 }
8877 ret = get_errno(sys_getdents64(arg1, dirp, count));
8878 if (!is_error(ret)) {
8879 /* Convert the dirent64 structs to target dirent. We do this
8880 * in-place, since we can guarantee that a target_dirent is no
8881 * larger than a dirent64; however this means we have to be
8882 * careful to read everything before writing in the new format.
8883 */
8884 struct linux_dirent64 *de;
8885 struct target_dirent *tde;
8886 int len = ret;
8887 int tlen = 0;
8888
8889 de = dirp;
8890 tde = (struct target_dirent *)dirp;
8891 while (len > 0) {
8892 int namelen, treclen;
8893 int reclen = de->d_reclen;
8894 uint64_t ino = de->d_ino;
8895 int64_t off = de->d_off;
8896 uint8_t type = de->d_type;
8897
8898 namelen = strlen(de->d_name);
8899 treclen = offsetof(struct target_dirent, d_name)
8900 + namelen + 2;
8901 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
8902
8903 memmove(tde->d_name, de->d_name, namelen + 1);
8904 tde->d_ino = tswapal(ino);
8905 tde->d_off = tswapal(off);
8906 tde->d_reclen = tswap16(treclen);
8907 /* The target_dirent type is in what was formerly a padding
8908 * byte at the end of the structure:
8909 */
8910 *(((char *)tde) + treclen - 1) = type;
8911
8912 de = (struct linux_dirent64 *)((char *)de + reclen);
8913 tde = (struct target_dirent *)((char *)tde + treclen);
8914 len -= reclen;
8915 tlen += treclen;
8916 }
8917 ret = tlen;
8918 }
8919 unlock_user(dirp, arg2, ret);
8920 }
8921#endif
bellard31e31b82003-02-18 22:55:36 +00008922 break;
Chen Gang704eff62015-08-21 05:37:33 +08008923#endif /* TARGET_NR_getdents */
ths3ae43202007-09-16 21:39:48 +00008924#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00008925 case TARGET_NR_getdents64:
8926 {
aurel326556a832008-10-13 21:08:17 +00008927 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00008928 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00008929 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
8930 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00008931 ret = get_errno(sys_getdents64(arg1, dirp, count));
8932 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00008933 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00008934 int len = ret;
8935 int reclen;
8936 de = dirp;
8937 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00008938 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00008939 if (reclen > len)
8940 break;
bellard8083a3e2003-03-24 23:12:16 +00008941 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00008942 tswap64s((uint64_t *)&de->d_ino);
8943 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00008944 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00008945 len -= reclen;
8946 }
8947 }
pbrook53a59602006-03-25 19:31:22 +00008948 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00008949 }
8950 break;
bellarda541f292004-04-12 20:39:29 +00008951#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01008952#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00008953 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00008954 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00008955 break;
thse5febef2007-04-01 18:31:35 +00008956#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05008957#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
8958# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00008959 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05008960# endif
8961# ifdef TARGET_NR_ppoll
8962 case TARGET_NR_ppoll:
8963# endif
bellard9de5e442003-03-23 16:49:39 +00008964 {
pbrook53a59602006-03-25 19:31:22 +00008965 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00008966 unsigned int nfds = arg2;
8967 int timeout = arg3;
8968 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00008969 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00008970
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008971 pfd = NULL;
8972 target_pfd = NULL;
8973 if (nfds) {
8974 target_pfd = lock_user(VERIFY_WRITE, arg1,
8975 sizeof(struct target_pollfd) * nfds, 1);
8976 if (!target_pfd) {
8977 goto efault;
8978 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008979
Laurent Vivier3e24bb32015-10-06 01:20:48 +02008980 pfd = alloca(sizeof(struct pollfd) * nfds);
8981 for (i = 0; i < nfds; i++) {
8982 pfd[i].fd = tswap32(target_pfd[i].fd);
8983 pfd[i].events = tswap16(target_pfd[i].events);
8984 }
bellard9de5e442003-03-23 16:49:39 +00008985 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05008986
8987# ifdef TARGET_NR_ppoll
8988 if (num == TARGET_NR_ppoll) {
8989 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
8990 target_sigset_t *target_set;
8991 sigset_t _set, *set = &_set;
8992
8993 if (arg3) {
8994 if (target_to_host_timespec(timeout_ts, arg3)) {
8995 unlock_user(target_pfd, arg1, 0);
8996 goto efault;
8997 }
8998 } else {
8999 timeout_ts = NULL;
9000 }
9001
9002 if (arg4) {
9003 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
9004 if (!target_set) {
9005 unlock_user(target_pfd, arg1, 0);
9006 goto efault;
9007 }
9008 target_to_host_sigset(set, target_set);
9009 } else {
9010 set = NULL;
9011 }
9012
Peter Maydellb28a1f32016-05-27 15:51:47 +01009013 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts,
9014 set, SIGSET_T_SIZE));
Mike Frysingerd8035d42011-02-07 01:05:51 -05009015
9016 if (!is_error(ret) && arg3) {
9017 host_to_target_timespec(arg3, timeout_ts);
9018 }
9019 if (arg4) {
9020 unlock_user(target_set, arg4, 0);
9021 }
9022 } else
9023# endif
9024 ret = get_errno(poll(pfd, nfds, timeout));
9025
bellard9de5e442003-03-23 16:49:39 +00009026 if (!is_error(ret)) {
9027 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00009028 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00009029 }
9030 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00009031 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00009032 }
9033 break;
thse5febef2007-04-01 18:31:35 +00009034#endif
bellard31e31b82003-02-18 22:55:36 +00009035 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00009036 /* NOTE: the flock constant seems to be the same for every
9037 Linux platform */
Peter Maydell2a845982016-06-06 19:58:07 +01009038 ret = get_errno(safe_flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00009039 break;
9040 case TARGET_NR_readv:
9041 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009042 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
9043 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009044 ret = get_errno(safe_readv(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009045 unlock_iovec(vec, arg2, arg3, 1);
9046 } else {
9047 ret = -host_to_target_errno(errno);
9048 }
bellard31e31b82003-02-18 22:55:36 +00009049 }
9050 break;
9051 case TARGET_NR_writev:
9052 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009053 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9054 if (vec != NULL) {
Peter Maydell918c03e2016-06-06 19:58:02 +01009055 ret = get_errno(safe_writev(arg1, vec, arg3));
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009056 unlock_iovec(vec, arg2, arg3, 0);
9057 } else {
9058 ret = -host_to_target_errno(errno);
9059 }
bellard31e31b82003-02-18 22:55:36 +00009060 }
9061 break;
9062 case TARGET_NR_getsid:
9063 ret = get_errno(getsid(arg1));
9064 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009065#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00009066 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00009067 ret = get_errno(fdatasync(arg1));
9068 break;
j_mayer7a3148a2007-04-05 07:13:51 +00009069#endif
Chen Gang704eff62015-08-21 05:37:33 +08009070#ifdef TARGET_NR__sysctl
bellard31e31b82003-02-18 22:55:36 +00009071 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00009072 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00009073 return value. */
ths0da46a62007-10-20 20:23:07 +00009074 ret = -TARGET_ENOTDIR;
9075 break;
Chen Gang704eff62015-08-21 05:37:33 +08009076#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -05009077 case TARGET_NR_sched_getaffinity:
9078 {
9079 unsigned int mask_size;
9080 unsigned long *mask;
9081
9082 /*
9083 * sched_getaffinity needs multiples of ulong, so need to take
9084 * care of mismatches between target ulong and host ulong sizes.
9085 */
9086 if (arg2 & (sizeof(abi_ulong) - 1)) {
9087 ret = -TARGET_EINVAL;
9088 break;
9089 }
9090 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9091
9092 mask = alloca(mask_size);
9093 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
9094
9095 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01009096 if (ret > arg2) {
9097 /* More data returned than the caller's buffer will fit.
9098 * This only happens if sizeof(abi_long) < sizeof(long)
9099 * and the caller passed us a buffer holding an odd number
9100 * of abi_longs. If the host kernel is actually using the
9101 * extra 4 bytes then fail EINVAL; otherwise we can just
9102 * ignore them and only copy the interesting part.
9103 */
9104 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
9105 if (numcpus > arg2 * 8) {
9106 ret = -TARGET_EINVAL;
9107 break;
9108 }
9109 ret = arg2;
9110 }
9111
Mike McCormackcd18f052011-04-18 14:43:36 +09009112 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05009113 goto efault;
9114 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05009115 }
9116 }
9117 break;
9118 case TARGET_NR_sched_setaffinity:
9119 {
9120 unsigned int mask_size;
9121 unsigned long *mask;
9122
9123 /*
9124 * sched_setaffinity needs multiples of ulong, so need to take
9125 * care of mismatches between target ulong and host ulong sizes.
9126 */
9127 if (arg2 & (sizeof(abi_ulong) - 1)) {
9128 ret = -TARGET_EINVAL;
9129 break;
9130 }
9131 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
9132
9133 mask = alloca(mask_size);
9134 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
9135 goto efault;
9136 }
9137 memcpy(mask, p, arg2);
9138 unlock_user_struct(p, arg2, 0);
9139
9140 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
9141 }
9142 break;
bellard31e31b82003-02-18 22:55:36 +00009143 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00009144 {
pbrook53a59602006-03-25 19:31:22 +00009145 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009146 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00009147
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009148 if (arg2 == 0) {
9149 return -TARGET_EINVAL;
9150 }
bellard579a97f2007-11-11 14:26:47 +00009151 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
9152 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009153 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009154 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00009155 ret = get_errno(sched_setparam(arg1, &schp));
9156 }
9157 break;
bellard31e31b82003-02-18 22:55:36 +00009158 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00009159 {
pbrook53a59602006-03-25 19:31:22 +00009160 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009161 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009162
9163 if (arg2 == 0) {
9164 return -TARGET_EINVAL;
9165 }
bellard5cd43932003-03-29 16:54:36 +00009166 ret = get_errno(sched_getparam(arg1, &schp));
9167 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009168 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
9169 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009170 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009171 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00009172 }
9173 }
9174 break;
bellard31e31b82003-02-18 22:55:36 +00009175 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00009176 {
pbrook53a59602006-03-25 19:31:22 +00009177 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00009178 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05009179 if (arg3 == 0) {
9180 return -TARGET_EINVAL;
9181 }
bellard579a97f2007-11-11 14:26:47 +00009182 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
9183 goto efault;
bellard5cd43932003-03-29 16:54:36 +00009184 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00009185 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00009186 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
9187 }
9188 break;
bellard31e31b82003-02-18 22:55:36 +00009189 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00009190 ret = get_errno(sched_getscheduler(arg1));
9191 break;
bellard31e31b82003-02-18 22:55:36 +00009192 case TARGET_NR_sched_yield:
9193 ret = get_errno(sched_yield());
9194 break;
9195 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00009196 ret = get_errno(sched_get_priority_max(arg1));
9197 break;
bellard31e31b82003-02-18 22:55:36 +00009198 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00009199 ret = get_errno(sched_get_priority_min(arg1));
9200 break;
bellard31e31b82003-02-18 22:55:36 +00009201 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00009202 {
bellard5cd43932003-03-29 16:54:36 +00009203 struct timespec ts;
9204 ret = get_errno(sched_rr_get_interval(arg1, &ts));
9205 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05009206 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00009207 }
9208 }
9209 break;
bellard31e31b82003-02-18 22:55:36 +00009210 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00009211 {
bellard1b6b0292003-03-22 17:31:38 +00009212 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00009213 target_to_host_timespec(&req, arg1);
Peter Maydell9e518222016-06-06 19:58:09 +01009214 ret = get_errno(safe_nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00009215 if (is_error(ret) && arg2) {
9216 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00009217 }
9218 }
9219 break;
thse5febef2007-04-01 18:31:35 +00009220#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00009221 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00009222 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009223#endif
9224#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00009225 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00009226 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00009227#endif
bellard31e31b82003-02-18 22:55:36 +00009228 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00009229 switch (arg1) {
9230 case PR_GET_PDEATHSIG:
9231 {
9232 int deathsig;
9233 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
9234 if (!is_error(ret) && arg2
9235 && put_user_ual(deathsig, arg2)) {
9236 goto efault;
thse5574482007-02-11 20:03:13 +00009237 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00009238 break;
9239 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00009240#ifdef PR_GET_NAME
9241 case PR_GET_NAME:
9242 {
9243 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
9244 if (!name) {
9245 goto efault;
9246 }
9247 ret = get_errno(prctl(arg1, (unsigned long)name,
9248 arg3, arg4, arg5));
9249 unlock_user(name, arg2, 16);
9250 break;
9251 }
9252 case PR_SET_NAME:
9253 {
9254 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
9255 if (!name) {
9256 goto efault;
9257 }
9258 ret = get_errno(prctl(arg1, (unsigned long)name,
9259 arg3, arg4, arg5));
9260 unlock_user(name, arg2, 0);
9261 break;
9262 }
9263#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00009264 default:
9265 /* Most prctl options have no pointer arguments */
9266 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
9267 break;
9268 }
ths39b9aae2007-02-11 18:36:44 +00009269 break;
bellardd2fd1af2007-11-14 18:08:56 +00009270#ifdef TARGET_NR_arch_prctl
9271 case TARGET_NR_arch_prctl:
9272#if defined(TARGET_I386) && !defined(TARGET_ABI32)
9273 ret = do_arch_prctl(cpu_env, arg1, arg2);
9274 break;
9275#else
9276 goto unimplemented;
9277#endif
9278#endif
aurel32f2c7ba12008-03-28 22:32:06 +00009279#ifdef TARGET_NR_pread64
9280 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00009281 if (regpairs_aligned(cpu_env)) {
9282 arg4 = arg5;
9283 arg5 = arg6;
9284 }
aurel32f2c7ba12008-03-28 22:32:06 +00009285 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
9286 goto efault;
9287 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
9288 unlock_user(p, arg2, ret);
9289 break;
9290 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00009291 if (regpairs_aligned(cpu_env)) {
9292 arg4 = arg5;
9293 arg5 = arg6;
9294 }
aurel32f2c7ba12008-03-28 22:32:06 +00009295 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
9296 goto efault;
9297 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
9298 unlock_user(p, arg2, 0);
9299 break;
9300#endif
bellard31e31b82003-02-18 22:55:36 +00009301 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00009302 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
9303 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009304 ret = get_errno(sys_getcwd1(p, arg2));
9305 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00009306 break;
9307 case TARGET_NR_capget:
9308 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00009309 {
9310 struct target_user_cap_header *target_header;
9311 struct target_user_cap_data *target_data = NULL;
9312 struct __user_cap_header_struct header;
9313 struct __user_cap_data_struct data[2];
9314 struct __user_cap_data_struct *dataptr = NULL;
9315 int i, target_datalen;
9316 int data_items = 1;
9317
9318 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
9319 goto efault;
9320 }
9321 header.version = tswap32(target_header->version);
9322 header.pid = tswap32(target_header->pid);
9323
Peter Maydellec864872014-03-19 16:07:30 +00009324 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00009325 /* Version 2 and up takes pointer to two user_data structs */
9326 data_items = 2;
9327 }
9328
9329 target_datalen = sizeof(*target_data) * data_items;
9330
9331 if (arg2) {
9332 if (num == TARGET_NR_capget) {
9333 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
9334 } else {
9335 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
9336 }
9337 if (!target_data) {
9338 unlock_user_struct(target_header, arg1, 0);
9339 goto efault;
9340 }
9341
9342 if (num == TARGET_NR_capset) {
9343 for (i = 0; i < data_items; i++) {
9344 data[i].effective = tswap32(target_data[i].effective);
9345 data[i].permitted = tswap32(target_data[i].permitted);
9346 data[i].inheritable = tswap32(target_data[i].inheritable);
9347 }
9348 }
9349
9350 dataptr = data;
9351 }
9352
9353 if (num == TARGET_NR_capget) {
9354 ret = get_errno(capget(&header, dataptr));
9355 } else {
9356 ret = get_errno(capset(&header, dataptr));
9357 }
9358
9359 /* The kernel always updates version for both capget and capset */
9360 target_header->version = tswap32(header.version);
9361 unlock_user_struct(target_header, arg1, 1);
9362
9363 if (arg2) {
9364 if (num == TARGET_NR_capget) {
9365 for (i = 0; i < data_items; i++) {
9366 target_data[i].effective = tswap32(data[i].effective);
9367 target_data[i].permitted = tswap32(data[i].permitted);
9368 target_data[i].inheritable = tswap32(data[i].inheritable);
9369 }
9370 unlock_user(target_data, arg2, target_datalen);
9371 } else {
9372 unlock_user(target_data, arg2, 0);
9373 }
9374 }
9375 break;
9376 }
bellard31e31b82003-02-18 22:55:36 +00009377 case TARGET_NR_sigaltstack:
Andreas Färber9349b4f2012-03-14 01:38:32 +01009378 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00009379 break;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009380
9381#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00009382 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009383 {
9384 off_t *offp = NULL;
9385 off_t off;
9386 if (arg3) {
9387 ret = get_user_sal(off, arg3);
9388 if (is_error(ret)) {
9389 break;
9390 }
9391 offp = &off;
9392 }
9393 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9394 if (!is_error(ret) && arg3) {
9395 abi_long ret2 = put_user_sal(off, arg3);
9396 if (is_error(ret2)) {
9397 ret = ret2;
9398 }
9399 }
9400 break;
9401 }
9402#ifdef TARGET_NR_sendfile64
9403 case TARGET_NR_sendfile64:
9404 {
9405 off_t *offp = NULL;
9406 off_t off;
9407 if (arg3) {
9408 ret = get_user_s64(off, arg3);
9409 if (is_error(ret)) {
9410 break;
9411 }
9412 offp = &off;
9413 }
9414 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
9415 if (!is_error(ret) && arg3) {
9416 abi_long ret2 = put_user_s64(off, arg3);
9417 if (is_error(ret2)) {
9418 ret = ret2;
9419 }
9420 }
9421 break;
9422 }
9423#endif
9424#else
9425 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01009426#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009427 case TARGET_NR_sendfile64:
9428#endif
bellard5cd43932003-03-29 16:54:36 +00009429 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00009430#endif
9431
bellardebc05482003-09-30 21:08:41 +00009432#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00009433 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00009434 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009435#endif
9436#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00009437 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00009438 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00009439#endif
bellard048f6b42005-11-26 18:47:20 +00009440#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00009441 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00009442 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
9443 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00009444 break;
bellard048f6b42005-11-26 18:47:20 +00009445#endif
bellardebc05482003-09-30 21:08:41 +00009446#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00009447 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00009448 {
9449 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03009450 int resource = target_to_host_resource(arg1);
9451 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00009452 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00009453 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00009454 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
9455 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09009456 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
9457 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00009458 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00009459 }
9460 break;
9461 }
bellardebc05482003-09-30 21:08:41 +00009462#endif
bellarda315a142005-01-30 22:59:18 +00009463#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00009464 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00009465 if (!(p = lock_user_string(arg1)))
9466 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009467 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
9468 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00009469 break;
bellarda315a142005-01-30 22:59:18 +00009470#endif
9471#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00009472 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00009473 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00009474 break;
bellarda315a142005-01-30 22:59:18 +00009475#endif
9476#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00009477 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00009478 if (!(p = lock_user_string(arg1)))
9479 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009480 ret = get_errno(stat(path(p), &st));
9481 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009482 if (!is_error(ret))
9483 ret = host_to_target_stat64(cpu_env, arg2, &st);
9484 break;
bellarda315a142005-01-30 22:59:18 +00009485#endif
9486#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00009487 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00009488 if (!(p = lock_user_string(arg1)))
9489 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009490 ret = get_errno(lstat(path(p), &st));
9491 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00009492 if (!is_error(ret))
9493 ret = host_to_target_stat64(cpu_env, arg2, &st);
9494 break;
bellarda315a142005-01-30 22:59:18 +00009495#endif
9496#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00009497 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00009498 ret = get_errno(fstat(arg1, &st));
9499 if (!is_error(ret))
9500 ret = host_to_target_stat64(cpu_env, arg2, &st);
9501 break;
bellardec86b0f2003-04-11 00:15:04 +00009502#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01009503#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00009504#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00009505 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00009506#endif
9507#ifdef TARGET_NR_newfstatat
9508 case TARGET_NR_newfstatat:
9509#endif
balrog6a24a772008-09-20 02:23:36 +00009510 if (!(p = lock_user_string(arg2)))
9511 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009512 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00009513 if (!is_error(ret))
9514 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00009515 break;
bellarda315a142005-01-30 22:59:18 +00009516#endif
Chen Gang704eff62015-08-21 05:37:33 +08009517#ifdef TARGET_NR_lchown
bellard67867302003-11-23 17:05:30 +00009518 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00009519 if (!(p = lock_user_string(arg1)))
9520 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009521 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
9522 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009523 break;
Chen Gang704eff62015-08-21 05:37:33 +08009524#endif
Riku Voipio0c866a72011-04-18 15:23:06 +03009525#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00009526 case TARGET_NR_getuid:
9527 ret = get_errno(high2lowuid(getuid()));
9528 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009529#endif
9530#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00009531 case TARGET_NR_getgid:
9532 ret = get_errno(high2lowgid(getgid()));
9533 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009534#endif
9535#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00009536 case TARGET_NR_geteuid:
9537 ret = get_errno(high2lowuid(geteuid()));
9538 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009539#endif
9540#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00009541 case TARGET_NR_getegid:
9542 ret = get_errno(high2lowgid(getegid()));
9543 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03009544#endif
bellard67867302003-11-23 17:05:30 +00009545 case TARGET_NR_setreuid:
9546 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
9547 break;
9548 case TARGET_NR_setregid:
9549 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
9550 break;
9551 case TARGET_NR_getgroups:
9552 {
9553 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009554 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00009555 gid_t *grouplist;
9556 int i;
9557
9558 grouplist = alloca(gidsetsize * sizeof(gid_t));
9559 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009560 if (gidsetsize == 0)
9561 break;
bellard67867302003-11-23 17:05:30 +00009562 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00009563 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00009564 if (!target_grouplist)
9565 goto efault;
balroga2155fc2008-09-20 02:12:08 +00009566 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03009567 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009568 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00009569 }
9570 }
9571 break;
9572 case TARGET_NR_setgroups:
9573 {
9574 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03009575 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009576 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00009577 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009578 if (gidsetsize) {
9579 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00009580 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05009581 if (!target_grouplist) {
9582 ret = -TARGET_EFAULT;
9583 goto fail;
9584 }
9585 for (i = 0; i < gidsetsize; i++) {
9586 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
9587 }
9588 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00009589 }
bellard67867302003-11-23 17:05:30 +00009590 ret = get_errno(setgroups(gidsetsize, grouplist));
9591 }
9592 break;
9593 case TARGET_NR_fchown:
9594 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
9595 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009596#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00009597 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00009598 if (!(p = lock_user_string(arg2)))
9599 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01009600 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
9601 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00009602 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00009603 break;
9604#endif
bellard67867302003-11-23 17:05:30 +00009605#ifdef TARGET_NR_setresuid
9606 case TARGET_NR_setresuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009607 ret = get_errno(sys_setresuid(low2highuid(arg1),
9608 low2highuid(arg2),
9609 low2highuid(arg3)));
bellard67867302003-11-23 17:05:30 +00009610 break;
9611#endif
9612#ifdef TARGET_NR_getresuid
9613 case TARGET_NR_getresuid:
9614 {
pbrook53a59602006-03-25 19:31:22 +00009615 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00009616 ret = get_errno(getresuid(&ruid, &euid, &suid));
9617 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009618 if (put_user_id(high2lowuid(ruid), arg1)
9619 || put_user_id(high2lowuid(euid), arg2)
9620 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00009621 goto efault;
bellard67867302003-11-23 17:05:30 +00009622 }
9623 }
9624 break;
9625#endif
9626#ifdef TARGET_NR_getresgid
9627 case TARGET_NR_setresgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009628 ret = get_errno(sys_setresgid(low2highgid(arg1),
9629 low2highgid(arg2),
9630 low2highgid(arg3)));
bellard67867302003-11-23 17:05:30 +00009631 break;
9632#endif
9633#ifdef TARGET_NR_getresgid
9634 case TARGET_NR_getresgid:
9635 {
pbrook53a59602006-03-25 19:31:22 +00009636 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00009637 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9638 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00009639 if (put_user_id(high2lowgid(rgid), arg1)
9640 || put_user_id(high2lowgid(egid), arg2)
9641 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00009642 goto efault;
bellard67867302003-11-23 17:05:30 +00009643 }
9644 }
9645 break;
9646#endif
Chen Gang704eff62015-08-21 05:37:33 +08009647#ifdef TARGET_NR_chown
bellard67867302003-11-23 17:05:30 +00009648 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00009649 if (!(p = lock_user_string(arg1)))
9650 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009651 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
9652 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00009653 break;
Chen Gang704eff62015-08-21 05:37:33 +08009654#endif
bellard67867302003-11-23 17:05:30 +00009655 case TARGET_NR_setuid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009656 ret = get_errno(sys_setuid(low2highuid(arg1)));
bellard67867302003-11-23 17:05:30 +00009657 break;
9658 case TARGET_NR_setgid:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009659 ret = get_errno(sys_setgid(low2highgid(arg1)));
bellard67867302003-11-23 17:05:30 +00009660 break;
9661 case TARGET_NR_setfsuid:
9662 ret = get_errno(setfsuid(arg1));
9663 break;
9664 case TARGET_NR_setfsgid:
9665 ret = get_errno(setfsgid(arg1));
9666 break;
bellard67867302003-11-23 17:05:30 +00009667
bellarda315a142005-01-30 22:59:18 +00009668#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00009669 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00009670 if (!(p = lock_user_string(arg1)))
9671 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009672 ret = get_errno(lchown(p, arg2, arg3));
9673 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009674 break;
bellarda315a142005-01-30 22:59:18 +00009675#endif
9676#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00009677 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00009678 ret = get_errno(getuid());
9679 break;
bellarda315a142005-01-30 22:59:18 +00009680#endif
aurel3264b4d282008-11-14 17:20:15 +00009681
9682#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
9683 /* Alpha specific */
9684 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009685 {
9686 uid_t euid;
9687 euid=geteuid();
9688 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
9689 }
aurel3264b4d282008-11-14 17:20:15 +00009690 ret = get_errno(getuid());
9691 break;
9692#endif
9693#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
9694 /* Alpha specific */
9695 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009696 {
9697 uid_t egid;
9698 egid=getegid();
9699 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
9700 }
aurel3264b4d282008-11-14 17:20:15 +00009701 ret = get_errno(getgid());
9702 break;
9703#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08009704#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
9705 /* Alpha specific */
9706 case TARGET_NR_osf_getsysinfo:
9707 ret = -TARGET_EOPNOTSUPP;
9708 switch (arg1) {
9709 case TARGET_GSI_IEEE_FP_CONTROL:
9710 {
9711 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
9712
9713 /* Copied from linux ieee_fpcr_to_swcr. */
9714 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
9715 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
9716 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
9717 | SWCR_TRAP_ENABLE_DZE
9718 | SWCR_TRAP_ENABLE_OVF);
9719 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
9720 | SWCR_TRAP_ENABLE_INE);
9721 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
9722 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
9723
9724 if (put_user_u64 (swcr, arg2))
9725 goto efault;
9726 ret = 0;
9727 }
9728 break;
9729
9730 /* case GSI_IEEE_STATE_AT_SIGNAL:
9731 -- Not implemented in linux kernel.
9732 case GSI_UACPROC:
9733 -- Retrieves current unaligned access state; not much used.
9734 case GSI_PROC_TYPE:
9735 -- Retrieves implver information; surely not used.
9736 case GSI_GET_HWRPB:
9737 -- Grabs a copy of the HWRPB; surely not used.
9738 */
9739 }
9740 break;
9741#endif
9742#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
9743 /* Alpha specific */
9744 case TARGET_NR_osf_setsysinfo:
9745 ret = -TARGET_EOPNOTSUPP;
9746 switch (arg1) {
9747 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08009748 {
9749 uint64_t swcr, fpcr, orig_fpcr;
9750
Richard Henderson6e06d512012-06-01 09:08:21 -07009751 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08009752 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07009753 }
9754 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009755 fpcr = orig_fpcr & FPCR_DYN_MASK;
9756
9757 /* Copied from linux ieee_swcr_to_fpcr. */
9758 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
9759 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
9760 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
9761 | SWCR_TRAP_ENABLE_DZE
9762 | SWCR_TRAP_ENABLE_OVF)) << 48;
9763 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
9764 | SWCR_TRAP_ENABLE_INE)) << 57;
9765 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
9766 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
9767
Richard Henderson6e06d512012-06-01 09:08:21 -07009768 cpu_alpha_store_fpcr(cpu_env, fpcr);
9769 ret = 0;
9770 }
9771 break;
9772
9773 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
9774 {
9775 uint64_t exc, fpcr, orig_fpcr;
9776 int si_code;
9777
9778 if (get_user_u64(exc, arg2)) {
9779 goto efault;
9780 }
9781
9782 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
9783
9784 /* We only add to the exception status here. */
9785 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
9786
9787 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009788 ret = 0;
9789
Richard Henderson6e06d512012-06-01 09:08:21 -07009790 /* Old exceptions are not signaled. */
9791 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009792
Richard Henderson6e06d512012-06-01 09:08:21 -07009793 /* If any exceptions set by this call,
9794 and are unmasked, send a signal. */
9795 si_code = 0;
9796 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
9797 si_code = TARGET_FPE_FLTRES;
9798 }
9799 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
9800 si_code = TARGET_FPE_FLTUND;
9801 }
9802 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
9803 si_code = TARGET_FPE_FLTOVF;
9804 }
9805 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
9806 si_code = TARGET_FPE_FLTDIV;
9807 }
9808 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
9809 si_code = TARGET_FPE_FLTINV;
9810 }
9811 if (si_code != 0) {
9812 target_siginfo_t info;
9813 info.si_signo = SIGFPE;
9814 info.si_errno = 0;
9815 info.si_code = si_code;
9816 info._sifields._sigfault._addr
9817 = ((CPUArchState *)cpu_env)->pc;
9818 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08009819 }
9820 }
9821 break;
9822
9823 /* case SSI_NVPAIRS:
9824 -- Used with SSIN_UACPROC to enable unaligned accesses.
9825 case SSI_IEEE_STATE_AT_SIGNAL:
9826 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
9827 -- Not implemented in linux kernel
9828 */
9829 }
9830 break;
9831#endif
9832#ifdef TARGET_NR_osf_sigprocmask
9833 /* Alpha specific. */
9834 case TARGET_NR_osf_sigprocmask:
9835 {
9836 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01009837 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08009838 sigset_t set, oldset;
9839
9840 switch(arg1) {
9841 case TARGET_SIG_BLOCK:
9842 how = SIG_BLOCK;
9843 break;
9844 case TARGET_SIG_UNBLOCK:
9845 how = SIG_UNBLOCK;
9846 break;
9847 case TARGET_SIG_SETMASK:
9848 how = SIG_SETMASK;
9849 break;
9850 default:
9851 ret = -TARGET_EINVAL;
9852 goto fail;
9853 }
9854 mask = arg2;
9855 target_to_host_old_sigset(&set, &mask);
Peter Maydell3d3efba2016-05-27 15:51:49 +01009856 ret = do_sigprocmask(how, &set, &oldset);
9857 if (!ret) {
9858 host_to_target_old_sigset(&mask, &oldset);
9859 ret = mask;
9860 }
Richard Hendersonba0e2762009-12-09 15:56:29 -08009861 }
9862 break;
9863#endif
aurel3264b4d282008-11-14 17:20:15 +00009864
bellarda315a142005-01-30 22:59:18 +00009865#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00009866 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00009867 ret = get_errno(getgid());
9868 break;
bellarda315a142005-01-30 22:59:18 +00009869#endif
9870#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00009871 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00009872 ret = get_errno(geteuid());
9873 break;
bellarda315a142005-01-30 22:59:18 +00009874#endif
9875#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00009876 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00009877 ret = get_errno(getegid());
9878 break;
bellarda315a142005-01-30 22:59:18 +00009879#endif
9880#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00009881 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00009882 ret = get_errno(setreuid(arg1, arg2));
9883 break;
bellarda315a142005-01-30 22:59:18 +00009884#endif
9885#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00009886 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00009887 ret = get_errno(setregid(arg1, arg2));
9888 break;
bellarda315a142005-01-30 22:59:18 +00009889#endif
9890#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00009891 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00009892 {
9893 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009894 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009895 gid_t *grouplist;
9896 int i;
9897
9898 grouplist = alloca(gidsetsize * sizeof(gid_t));
9899 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00009900 if (gidsetsize == 0)
9901 break;
bellard99c475a2005-01-31 20:45:13 +00009902 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00009903 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
9904 if (!target_grouplist) {
9905 ret = -TARGET_EFAULT;
9906 goto fail;
9907 }
balroga2155fc2008-09-20 02:12:08 +00009908 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00009909 target_grouplist[i] = tswap32(grouplist[i]);
9910 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00009911 }
9912 }
9913 break;
bellarda315a142005-01-30 22:59:18 +00009914#endif
9915#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00009916 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00009917 {
9918 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00009919 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00009920 gid_t *grouplist;
9921 int i;
ths3b46e622007-09-17 08:09:54 +00009922
bellard99c475a2005-01-31 20:45:13 +00009923 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00009924 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
9925 if (!target_grouplist) {
9926 ret = -TARGET_EFAULT;
9927 goto fail;
9928 }
bellard99c475a2005-01-31 20:45:13 +00009929 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00009930 grouplist[i] = tswap32(target_grouplist[i]);
9931 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00009932 ret = get_errno(setgroups(gidsetsize, grouplist));
9933 }
9934 break;
bellarda315a142005-01-30 22:59:18 +00009935#endif
9936#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00009937 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00009938 ret = get_errno(fchown(arg1, arg2, arg3));
9939 break;
bellarda315a142005-01-30 22:59:18 +00009940#endif
9941#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00009942 case TARGET_NR_setresuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009943 ret = get_errno(sys_setresuid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +00009944 break;
bellarda315a142005-01-30 22:59:18 +00009945#endif
9946#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00009947 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00009948 {
pbrook53a59602006-03-25 19:31:22 +00009949 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00009950 ret = get_errno(getresuid(&ruid, &euid, &suid));
9951 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009952 if (put_user_u32(ruid, arg1)
9953 || put_user_u32(euid, arg2)
9954 || put_user_u32(suid, arg3))
9955 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009956 }
9957 }
9958 break;
bellarda315a142005-01-30 22:59:18 +00009959#endif
9960#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00009961 case TARGET_NR_setresgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009962 ret = get_errno(sys_setresgid(arg1, arg2, arg3));
bellardb03c60f2003-03-23 17:19:56 +00009963 break;
bellarda315a142005-01-30 22:59:18 +00009964#endif
9965#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00009966 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00009967 {
pbrook53a59602006-03-25 19:31:22 +00009968 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00009969 ret = get_errno(getresgid(&rgid, &egid, &sgid));
9970 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00009971 if (put_user_u32(rgid, arg1)
9972 || put_user_u32(egid, arg2)
9973 || put_user_u32(sgid, arg3))
9974 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00009975 }
9976 }
9977 break;
bellarda315a142005-01-30 22:59:18 +00009978#endif
9979#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00009980 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00009981 if (!(p = lock_user_string(arg1)))
9982 goto efault;
pbrook53a59602006-03-25 19:31:22 +00009983 ret = get_errno(chown(p, arg2, arg3));
9984 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00009985 break;
bellarda315a142005-01-30 22:59:18 +00009986#endif
9987#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00009988 case TARGET_NR_setuid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009989 ret = get_errno(sys_setuid(arg1));
bellardb03c60f2003-03-23 17:19:56 +00009990 break;
bellarda315a142005-01-30 22:59:18 +00009991#endif
9992#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00009993 case TARGET_NR_setgid32:
Peter Maydellfd6f7792016-03-01 16:33:02 +00009994 ret = get_errno(sys_setgid(arg1));
bellardb03c60f2003-03-23 17:19:56 +00009995 break;
bellarda315a142005-01-30 22:59:18 +00009996#endif
9997#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00009998 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00009999 ret = get_errno(setfsuid(arg1));
10000 break;
bellarda315a142005-01-30 22:59:18 +000010001#endif
10002#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +000010003 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +000010004 ret = get_errno(setfsgid(arg1));
10005 break;
bellarda315a142005-01-30 22:59:18 +000010006#endif
bellard67867302003-11-23 17:05:30 +000010007
bellard31e31b82003-02-18 22:55:36 +000010008 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +000010009 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +000010010#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +000010011 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +000010012 {
10013 void *a;
10014 ret = -TARGET_EFAULT;
10015 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
10016 goto efault;
10017 if (!(p = lock_user_string(arg3)))
10018 goto mincore_fail;
10019 ret = get_errno(mincore(a, arg2, p));
10020 unlock_user(p, arg3, ret);
10021 mincore_fail:
10022 unlock_user(a, arg1, 0);
10023 }
10024 break;
bellardffa65c32004-01-04 23:57:22 +000010025#endif
aurel32408321b2008-10-01 21:46:32 +000010026#ifdef TARGET_NR_arm_fadvise64_64
10027 case TARGET_NR_arm_fadvise64_64:
Peter Maydelle0156a92016-05-31 15:45:09 +010010028 /* arm_fadvise64_64 looks like fadvise64_64 but
10029 * with different argument order: fd, advice, offset, len
10030 * rather than the usual fd, offset, len, advice.
10031 * Note that offset and len are both 64-bit so appear as
10032 * pairs of 32-bit registers.
10033 */
10034 ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
10035 target_offset64(arg5, arg6), arg2);
10036 ret = -host_to_target_errno(ret);
10037 break;
aurel32408321b2008-10-01 21:46:32 +000010038#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010039
10040#if TARGET_ABI_BITS == 32
10041
10042#ifdef TARGET_NR_fadvise64_64
10043 case TARGET_NR_fadvise64_64:
10044 /* 6 args: fd, offset (high, low), len (high, low), advice */
10045 if (regpairs_aligned(cpu_env)) {
10046 /* offset is in (3,4), len in (5,6) and advice in 7 */
10047 arg2 = arg3;
10048 arg3 = arg4;
10049 arg4 = arg5;
10050 arg5 = arg6;
10051 arg6 = arg7;
10052 }
10053 ret = -host_to_target_errno(posix_fadvise(arg1,
10054 target_offset64(arg2, arg3),
10055 target_offset64(arg4, arg5),
10056 arg6));
10057 break;
10058#endif
10059
10060#ifdef TARGET_NR_fadvise64
10061 case TARGET_NR_fadvise64:
10062 /* 5 args: fd, offset (high, low), len, advice */
10063 if (regpairs_aligned(cpu_env)) {
10064 /* offset is in (3,4), len in 5 and advice in 6 */
10065 arg2 = arg3;
10066 arg3 = arg4;
10067 arg4 = arg5;
10068 arg5 = arg6;
10069 }
10070 ret = -host_to_target_errno(posix_fadvise(arg1,
10071 target_offset64(arg2, arg3),
10072 arg4, arg5));
10073 break;
10074#endif
10075
10076#else /* not a 32-bit ABI */
Peter Maydelle0156a92016-05-31 15:45:09 +010010077#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +000010078#ifdef TARGET_NR_fadvise64_64
10079 case TARGET_NR_fadvise64_64:
10080#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +020010081#ifdef TARGET_NR_fadvise64
10082 case TARGET_NR_fadvise64:
10083#endif
10084#ifdef TARGET_S390X
10085 switch (arg4) {
10086 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
10087 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
10088 case 6: arg4 = POSIX_FADV_DONTNEED; break;
10089 case 7: arg4 = POSIX_FADV_NOREUSE; break;
10090 default: break;
10091 }
10092#endif
Peter Maydell977d8242016-05-31 15:45:11 +010010093 ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
10094 break;
aurel32408321b2008-10-01 21:46:32 +000010095#endif
Peter Maydellbadd3cd2016-05-31 15:45:10 +010010096#endif /* end of 64-bit ABI fadvise handling */
10097
bellardffa65c32004-01-04 23:57:22 +000010098#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +000010099 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +000010100 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +080010101 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +000010102 This will break MADV_DONTNEED.
10103 This is a hint, so ignoring and returning success is ok. */
10104 ret = get_errno(0);
10105 break;
bellardffa65c32004-01-04 23:57:22 +000010106#endif
blueswir1992f48a2007-10-14 16:27:31 +000010107#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +000010108 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +000010109 {
thsb1e341e2007-03-20 21:50:52 +000010110 int cmd;
bellard77e46722003-04-29 20:39:06 +000010111 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +000010112 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +000010113#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +000010114 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +000010115#endif
bellard77e46722003-04-29 20:39:06 +000010116
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010117 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +000010118 if (cmd == -TARGET_EINVAL) {
10119 ret = cmd;
10120 break;
10121 }
thsb1e341e2007-03-20 21:50:52 +000010122
bellard60cd49d2003-03-16 22:53:56 +000010123 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +000010124 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +000010125#ifdef TARGET_ARM
10126 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +000010127 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
10128 goto efault;
ths58134272007-03-31 18:59:32 +000010129 fl.l_type = tswap16(target_efl->l_type);
10130 fl.l_whence = tswap16(target_efl->l_whence);
10131 fl.l_start = tswap64(target_efl->l_start);
10132 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010133 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +000010134 unlock_user_struct(target_efl, arg3, 0);
10135 } else
10136#endif
10137 {
bellard9ee1fa22007-11-11 15:11:19 +000010138 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
10139 goto efault;
ths58134272007-03-31 18:59:32 +000010140 fl.l_type = tswap16(target_fl->l_type);
10141 fl.l_whence = tswap16(target_fl->l_whence);
10142 fl.l_start = tswap64(target_fl->l_start);
10143 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010144 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +000010145 unlock_user_struct(target_fl, arg3, 0);
10146 }
thsb1e341e2007-03-20 21:50:52 +000010147 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010148 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +000010149#ifdef TARGET_ARM
10150 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +000010151 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
10152 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010153 target_efl->l_type = tswap16(fl.l_type);
10154 target_efl->l_whence = tswap16(fl.l_whence);
10155 target_efl->l_start = tswap64(fl.l_start);
10156 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010157 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +000010158 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +000010159 } else
10160#endif
10161 {
bellard9ee1fa22007-11-11 15:11:19 +000010162 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
10163 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010164 target_fl->l_type = tswap16(fl.l_type);
10165 target_fl->l_whence = tswap16(fl.l_whence);
10166 target_fl->l_start = tswap64(fl.l_start);
10167 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010168 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +000010169 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +000010170 }
bellard77e46722003-04-29 20:39:06 +000010171 }
10172 break;
10173
thsb1e341e2007-03-20 21:50:52 +000010174 case TARGET_F_SETLK64:
10175 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +000010176#ifdef TARGET_ARM
10177 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +000010178 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
10179 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010180 fl.l_type = tswap16(target_efl->l_type);
10181 fl.l_whence = tswap16(target_efl->l_whence);
10182 fl.l_start = tswap64(target_efl->l_start);
10183 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010184 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +000010185 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +000010186 } else
10187#endif
10188 {
bellard9ee1fa22007-11-11 15:11:19 +000010189 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
10190 goto efault;
pbrookce4defa2006-02-09 16:49:55 +000010191 fl.l_type = tswap16(target_fl->l_type);
10192 fl.l_whence = tswap16(target_fl->l_whence);
10193 fl.l_start = tswap64(target_fl->l_start);
10194 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +020010195 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +000010196 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +000010197 }
thsb1e341e2007-03-20 21:50:52 +000010198 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +000010199 break;
bellard60cd49d2003-03-16 22:53:56 +000010200 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +020010201 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +000010202 break;
10203 }
bellard77e46722003-04-29 20:39:06 +000010204 break;
10205 }
bellard60cd49d2003-03-16 22:53:56 +000010206#endif
ths7d600c82006-12-08 01:32:58 +000010207#ifdef TARGET_NR_cacheflush
10208 case TARGET_NR_cacheflush:
10209 /* self-modifying code is handled automatically, so nothing needed */
10210 ret = 0;
10211 break;
10212#endif
bellardebc05482003-09-30 21:08:41 +000010213#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +000010214 case TARGET_NR_security:
10215 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +000010216#endif
bellardc573ff62004-01-04 15:51:36 +000010217#ifdef TARGET_NR_getpagesize
10218 case TARGET_NR_getpagesize:
10219 ret = TARGET_PAGE_SIZE;
10220 break;
10221#endif
bellard31e31b82003-02-18 22:55:36 +000010222 case TARGET_NR_gettid:
10223 ret = get_errno(gettid());
10224 break;
thse5febef2007-04-01 18:31:35 +000010225#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +000010226 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +000010227#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +030010228 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +000010229 arg2 = arg3;
10230 arg3 = arg4;
10231 arg4 = arg5;
10232 }
aurel322054ac92008-10-13 21:08:07 +000010233 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
10234#else
10235 ret = get_errno(readahead(arg1, arg2, arg3));
10236#endif
10237 break;
thse5febef2007-04-01 18:31:35 +000010238#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010239#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +000010240#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +000010241 case TARGET_NR_listxattr:
10242 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +000010243 {
10244 void *p, *b = 0;
10245 if (arg2) {
10246 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10247 if (!b) {
10248 ret = -TARGET_EFAULT;
10249 break;
10250 }
10251 }
10252 p = lock_user_string(arg1);
10253 if (p) {
10254 if (num == TARGET_NR_listxattr) {
10255 ret = get_errno(listxattr(p, b, arg3));
10256 } else {
10257 ret = get_errno(llistxattr(p, b, arg3));
10258 }
10259 } else {
10260 ret = -TARGET_EFAULT;
10261 }
10262 unlock_user(p, arg1, 0);
10263 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +030010264 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +000010265 }
10266 case TARGET_NR_flistxattr:
10267 {
10268 void *b = 0;
10269 if (arg2) {
10270 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
10271 if (!b) {
10272 ret = -TARGET_EFAULT;
10273 break;
10274 }
10275 }
10276 ret = get_errno(flistxattr(arg1, b, arg3));
10277 unlock_user(b, arg2, arg3);
10278 break;
10279 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010280 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010281 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010282 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010283 void *p, *n, *v = 0;
10284 if (arg3) {
10285 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10286 if (!v) {
10287 ret = -TARGET_EFAULT;
10288 break;
10289 }
10290 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010291 p = lock_user_string(arg1);
10292 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010293 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010294 if (num == TARGET_NR_setxattr) {
10295 ret = get_errno(setxattr(p, n, v, arg4, arg5));
10296 } else {
10297 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
10298 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010299 } else {
10300 ret = -TARGET_EFAULT;
10301 }
10302 unlock_user(p, arg1, 0);
10303 unlock_user(n, arg2, 0);
10304 unlock_user(v, arg3, 0);
10305 }
10306 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010307 case TARGET_NR_fsetxattr:
10308 {
10309 void *n, *v = 0;
10310 if (arg3) {
10311 v = lock_user(VERIFY_READ, arg3, arg4, 1);
10312 if (!v) {
10313 ret = -TARGET_EFAULT;
10314 break;
10315 }
10316 }
10317 n = lock_user_string(arg2);
10318 if (n) {
10319 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
10320 } else {
10321 ret = -TARGET_EFAULT;
10322 }
10323 unlock_user(n, arg2, 0);
10324 unlock_user(v, arg3, 0);
10325 }
10326 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010327 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010328 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010329 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010330 void *p, *n, *v = 0;
10331 if (arg3) {
10332 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10333 if (!v) {
10334 ret = -TARGET_EFAULT;
10335 break;
10336 }
10337 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010338 p = lock_user_string(arg1);
10339 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +000010340 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010341 if (num == TARGET_NR_getxattr) {
10342 ret = get_errno(getxattr(p, n, v, arg4));
10343 } else {
10344 ret = get_errno(lgetxattr(p, n, v, arg4));
10345 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010346 } else {
10347 ret = -TARGET_EFAULT;
10348 }
10349 unlock_user(p, arg1, 0);
10350 unlock_user(n, arg2, 0);
10351 unlock_user(v, arg3, arg4);
10352 }
10353 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010354 case TARGET_NR_fgetxattr:
10355 {
10356 void *n, *v = 0;
10357 if (arg3) {
10358 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
10359 if (!v) {
10360 ret = -TARGET_EFAULT;
10361 break;
10362 }
10363 }
10364 n = lock_user_string(arg2);
10365 if (n) {
10366 ret = get_errno(fgetxattr(arg1, n, v, arg4));
10367 } else {
10368 ret = -TARGET_EFAULT;
10369 }
10370 unlock_user(n, arg2, 0);
10371 unlock_user(v, arg3, arg4);
10372 }
10373 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010374 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +000010375 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010376 {
10377 void *p, *n;
10378 p = lock_user_string(arg1);
10379 n = lock_user_string(arg2);
10380 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +000010381 if (num == TARGET_NR_removexattr) {
10382 ret = get_errno(removexattr(p, n));
10383 } else {
10384 ret = get_errno(lremovexattr(p, n));
10385 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010386 } else {
10387 ret = -TARGET_EFAULT;
10388 }
10389 unlock_user(p, arg1, 0);
10390 unlock_user(n, arg2, 0);
10391 }
10392 break;
Peter Maydell30297b52011-12-14 15:37:18 +000010393 case TARGET_NR_fremovexattr:
10394 {
10395 void *n;
10396 n = lock_user_string(arg2);
10397 if (n) {
10398 ret = get_errno(fremovexattr(arg1, n));
10399 } else {
10400 ret = -TARGET_EFAULT;
10401 }
10402 unlock_user(n, arg2, 0);
10403 }
10404 break;
bellardebc05482003-09-30 21:08:41 +000010405#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070010406#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +000010407#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +000010408 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010409#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +020010410 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +000010411 ret = 0;
10412 break;
edgar_iglef967792009-01-07 14:19:38 +000010413#elif defined(TARGET_CRIS)
10414 if (arg1 & 0xff)
10415 ret = -TARGET_EINVAL;
10416 else {
10417 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
10418 ret = 0;
10419 }
10420 break;
bellard8d18e892007-11-14 15:18:40 +000010421#elif defined(TARGET_I386) && defined(TARGET_ABI32)
10422 ret = do_set_thread_area(cpu_env, arg1);
10423 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010424#elif defined(TARGET_M68K)
10425 {
Andreas Färber0429a972013-08-26 18:14:44 +020010426 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010427 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +010010428 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010429 break;
10430 }
ths6f5b89a2007-03-02 20:48:00 +000010431#else
10432 goto unimplemented_nowarn;
10433#endif
10434#endif
10435#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +000010436 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +000010437#if defined(TARGET_I386) && defined(TARGET_ABI32)
10438 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +010010439 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010440#elif defined(TARGET_M68K)
10441 {
Andreas Färber0429a972013-08-26 18:14:44 +020010442 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +010010443 ret = ts->tp_value;
10444 break;
10445 }
bellard8d18e892007-11-14 15:18:40 +000010446#else
bellard5cd43932003-03-29 16:54:36 +000010447 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +000010448#endif
bellard8d18e892007-11-14 15:18:40 +000010449#endif
bellard48dc41e2006-06-21 18:15:50 +000010450#ifdef TARGET_NR_getdomainname
10451 case TARGET_NR_getdomainname:
10452 goto unimplemented_nowarn;
10453#endif
ths6f5b89a2007-03-02 20:48:00 +000010454
thsb5906f92007-03-19 13:32:45 +000010455#ifdef TARGET_NR_clock_gettime
10456 case TARGET_NR_clock_gettime:
10457 {
10458 struct timespec ts;
10459 ret = get_errno(clock_gettime(arg1, &ts));
10460 if (!is_error(ret)) {
10461 host_to_target_timespec(arg2, &ts);
10462 }
10463 break;
10464 }
10465#endif
10466#ifdef TARGET_NR_clock_getres
10467 case TARGET_NR_clock_getres:
10468 {
10469 struct timespec ts;
10470 ret = get_errno(clock_getres(arg1, &ts));
10471 if (!is_error(ret)) {
10472 host_to_target_timespec(arg2, &ts);
10473 }
10474 break;
10475 }
10476#endif
pbrook63d76512008-05-29 13:43:29 +000010477#ifdef TARGET_NR_clock_nanosleep
10478 case TARGET_NR_clock_nanosleep:
10479 {
10480 struct timespec ts;
10481 target_to_host_timespec(&ts, arg3);
Peter Maydell9e518222016-06-06 19:58:09 +010010482 ret = get_errno(safe_clock_nanosleep(arg1, arg2,
10483 &ts, arg4 ? &ts : NULL));
pbrook63d76512008-05-29 13:43:29 +000010484 if (arg4)
10485 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010486
10487#if defined(TARGET_PPC)
10488 /* clock_nanosleep is odd in that it returns positive errno values.
10489 * On PPC, CR0 bit 3 should be set in such a situation. */
Peter Maydell9e518222016-06-06 19:58:09 +010010490 if (ret && ret != -TARGET_ERESTARTSYS) {
Tom Musta8fbe8fd2014-08-12 13:53:41 -050010491 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
10492 }
10493#endif
pbrook63d76512008-05-29 13:43:29 +000010494 break;
10495 }
10496#endif
thsb5906f92007-03-19 13:32:45 +000010497
ths6f5b89a2007-03-02 20:48:00 +000010498#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
10499 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +000010500 ret = get_errno(set_tid_address((int *)g2h(arg1)));
10501 break;
ths6f5b89a2007-03-02 20:48:00 +000010502#endif
10503
ths4cae1d12007-07-12 11:06:53 +000010504 case TARGET_NR_tkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010505 ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +000010506 break;
ths4cae1d12007-07-12 11:06:53 +000010507
ths71455572007-06-21 21:45:30 +000010508 case TARGET_NR_tgkill:
Peter Maydellbef653d2016-05-27 15:51:57 +010010509 ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
pbrook4cb05962008-05-30 18:05:19 +000010510 target_to_host_signal(arg3)));
Peter Maydellbef653d2016-05-27 15:51:57 +010010511 break;
ths71455572007-06-21 21:45:30 +000010512
ths4f2b1fe2007-06-21 21:57:12 +000010513#ifdef TARGET_NR_set_robust_list
10514 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +000010515 case TARGET_NR_get_robust_list:
10516 /* The ABI for supporting robust futexes has userspace pass
10517 * the kernel a pointer to a linked list which is updated by
10518 * userspace after the syscall; the list is walked by the kernel
10519 * when the thread exits. Since the linked list in QEMU guest
10520 * memory isn't a valid linked list for the host and we have
10521 * no way to reliably intercept the thread-death event, we can't
10522 * support these. Silently return ENOSYS so that guest userspace
10523 * falls back to a non-robust futex implementation (which should
10524 * be OK except in the corner case of the guest crashing while
10525 * holding a mutex that is shared with another process via
10526 * shared memory).
10527 */
10528 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +000010529#endif
10530
Peter Maydell1acae9f2013-07-02 14:04:12 +010010531#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +000010532 case TARGET_NR_utimensat:
10533 {
Riku Voipioebc996f2009-04-21 15:01:51 +030010534 struct timespec *tsp, ts[2];
10535 if (!arg3) {
10536 tsp = NULL;
10537 } else {
10538 target_to_host_timespec(ts, arg3);
10539 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
10540 tsp = ts;
10541 }
ths9007f0e2007-09-25 17:50:37 +000010542 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +030010543 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +000010544 else {
bellard579a97f2007-11-11 14:26:47 +000010545 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +000010546 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +000010547 goto fail;
10548 }
Riku Voipioebc996f2009-04-21 15:01:51 +030010549 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +000010550 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +000010551 }
10552 }
10553 break;
10554#endif
pbrookbd0c5662008-05-29 14:34:11 +000010555 case TARGET_NR_futex:
10556 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
10557 break;
aurel32dbfe4c32009-04-08 21:29:30 +000010558#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +000010559 case TARGET_NR_inotify_init:
10560 ret = get_errno(sys_inotify_init());
10561 break;
10562#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010563#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +000010564#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
10565 case TARGET_NR_inotify_init1:
10566 ret = get_errno(sys_inotify_init1(arg1));
10567 break;
10568#endif
Stefan Weila1606b02010-03-28 11:44:41 +020010569#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010570#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +000010571 case TARGET_NR_inotify_add_watch:
10572 p = lock_user_string(arg2);
10573 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
10574 unlock_user(p, arg2, 0);
10575 break;
10576#endif
aurel32dbfe4c32009-04-08 21:29:30 +000010577#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +000010578 case TARGET_NR_inotify_rm_watch:
10579 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
10580 break;
10581#endif
ths9007f0e2007-09-25 17:50:37 +000010582
Nathan Froyd8ec9cf82009-07-22 09:14:36 -070010583#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +000010584 case TARGET_NR_mq_open:
10585 {
Tom Mustab6ce1f62014-08-12 13:53:36 -050010586 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +000010587
10588 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010589 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +000010590 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -050010591 attrp = &posix_mq_attr;
10592 } else {
10593 attrp = 0;
10594 }
10595 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +000010596 unlock_user (p, arg1, 0);
10597 }
10598 break;
10599
10600 case TARGET_NR_mq_unlink:
10601 p = lock_user_string(arg1 - 1);
10602 ret = get_errno(mq_unlink(p));
10603 unlock_user (p, arg1, 0);
10604 break;
10605
10606 case TARGET_NR_mq_timedsend:
10607 {
10608 struct timespec ts;
10609
10610 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10611 if (arg5 != 0) {
10612 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010613 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, &ts));
aurel3224e10032009-04-15 16:11:43 +000010614 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010615 } else {
10616 ret = get_errno(safe_mq_timedsend(arg1, p, arg3, arg4, NULL));
aurel3224e10032009-04-15 16:11:43 +000010617 }
aurel3224e10032009-04-15 16:11:43 +000010618 unlock_user (p, arg2, arg3);
10619 }
10620 break;
10621
10622 case TARGET_NR_mq_timedreceive:
10623 {
10624 struct timespec ts;
10625 unsigned int prio;
10626
10627 p = lock_user (VERIFY_READ, arg2, arg3, 1);
10628 if (arg5 != 0) {
10629 target_to_host_timespec(&ts, arg5);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010630 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10631 &prio, &ts));
aurel3224e10032009-04-15 16:11:43 +000010632 host_to_target_timespec(arg5, &ts);
Peter Maydelld40ecd62016-06-06 19:58:06 +010010633 } else {
10634 ret = get_errno(safe_mq_timedreceive(arg1, p, arg3,
10635 &prio, NULL));
aurel3224e10032009-04-15 16:11:43 +000010636 }
aurel3224e10032009-04-15 16:11:43 +000010637 unlock_user (p, arg2, arg3);
10638 if (arg4 != 0)
10639 put_user_u32(prio, arg4);
10640 }
10641 break;
10642
10643 /* Not implemented for now... */
10644/* case TARGET_NR_mq_notify: */
10645/* break; */
10646
10647 case TARGET_NR_mq_getsetattr:
10648 {
10649 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
10650 ret = 0;
10651 if (arg3 != 0) {
10652 ret = mq_getattr(arg1, &posix_mq_attr_out);
10653 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
10654 }
10655 if (arg2 != 0) {
10656 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
10657 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
10658 }
10659
10660 }
10661 break;
10662#endif
10663
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010664#ifdef CONFIG_SPLICE
10665#ifdef TARGET_NR_tee
10666 case TARGET_NR_tee:
10667 {
10668 ret = get_errno(tee(arg1,arg2,arg3,arg4));
10669 }
10670 break;
10671#endif
10672#ifdef TARGET_NR_splice
10673 case TARGET_NR_splice:
10674 {
10675 loff_t loff_in, loff_out;
10676 loff_t *ploff_in = NULL, *ploff_out = NULL;
Andreas Schwab17644b32015-03-10 17:11:35 +010010677 if (arg2) {
10678 if (get_user_u64(loff_in, arg2)) {
10679 goto efault;
10680 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010681 ploff_in = &loff_in;
10682 }
Andreas Schwab17644b32015-03-10 17:11:35 +010010683 if (arg4) {
10684 if (get_user_u64(loff_out, arg4)) {
10685 goto efault;
10686 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010687 ploff_out = &loff_out;
10688 }
10689 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
Andreas Schwab17644b32015-03-10 17:11:35 +010010690 if (arg2) {
10691 if (put_user_u64(loff_in, arg2)) {
10692 goto efault;
10693 }
10694 }
10695 if (arg4) {
10696 if (put_user_u64(loff_out, arg4)) {
10697 goto efault;
10698 }
10699 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010700 }
10701 break;
10702#endif
10703#ifdef TARGET_NR_vmsplice
10704 case TARGET_NR_vmsplice:
10705 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -070010706 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
10707 if (vec != NULL) {
10708 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
10709 unlock_iovec(vec, arg2, arg3, 0);
10710 } else {
10711 ret = -host_to_target_errno(errno);
10712 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +053010713 }
10714 break;
10715#endif
10716#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +030010717#ifdef CONFIG_EVENTFD
10718#if defined(TARGET_NR_eventfd)
10719 case TARGET_NR_eventfd:
10720 ret = get_errno(eventfd(arg1, 0));
Laurent Viviere36800c2015-10-02 14:48:09 +020010721 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010722 break;
10723#endif
10724#if defined(TARGET_NR_eventfd2)
10725 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +020010726 {
10727 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
10728 if (arg2 & TARGET_O_NONBLOCK) {
10729 host_flags |= O_NONBLOCK;
10730 }
10731 if (arg2 & TARGET_O_CLOEXEC) {
10732 host_flags |= O_CLOEXEC;
10733 }
10734 ret = get_errno(eventfd(arg1, host_flags));
Laurent Viviere36800c2015-10-02 14:48:09 +020010735 fd_trans_unregister(ret);
Riku Voipioc2882b92009-08-12 15:08:24 +030010736 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +020010737 }
Riku Voipioc2882b92009-08-12 15:08:24 +030010738#endif
10739#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +030010740#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
10741 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +010010742#if TARGET_ABI_BITS == 32
10743 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
10744 target_offset64(arg5, arg6)));
10745#else
Ulrich Hechtd0927932009-09-17 20:22:14 +030010746 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +010010747#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +030010748 break;
10749#endif
Peter Maydellc727f472011-01-06 11:05:10 +000010750#if defined(CONFIG_SYNC_FILE_RANGE)
10751#if defined(TARGET_NR_sync_file_range)
10752 case TARGET_NR_sync_file_range:
10753#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +030010754#if defined(TARGET_MIPS)
10755 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10756 target_offset64(arg5, arg6), arg7));
10757#else
Peter Maydellc727f472011-01-06 11:05:10 +000010758 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
10759 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +030010760#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +000010761#else
10762 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
10763#endif
10764 break;
10765#endif
10766#if defined(TARGET_NR_sync_file_range2)
10767 case TARGET_NR_sync_file_range2:
10768 /* This is like sync_file_range but the arguments are reordered */
10769#if TARGET_ABI_BITS == 32
10770 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
10771 target_offset64(arg5, arg6), arg2));
10772#else
10773 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
10774#endif
10775 break;
10776#endif
10777#endif
Laurent Viviere36800c2015-10-02 14:48:09 +020010778#if defined(TARGET_NR_signalfd4)
10779 case TARGET_NR_signalfd4:
10780 ret = do_signalfd4(arg1, arg2, arg4);
10781 break;
10782#endif
10783#if defined(TARGET_NR_signalfd)
10784 case TARGET_NR_signalfd:
10785 ret = do_signalfd4(arg1, arg2, 0);
10786 break;
10787#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000010788#if defined(CONFIG_EPOLL)
10789#if defined(TARGET_NR_epoll_create)
10790 case TARGET_NR_epoll_create:
10791 ret = get_errno(epoll_create(arg1));
10792 break;
10793#endif
10794#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
10795 case TARGET_NR_epoll_create1:
10796 ret = get_errno(epoll_create1(arg1));
10797 break;
10798#endif
10799#if defined(TARGET_NR_epoll_ctl)
10800 case TARGET_NR_epoll_ctl:
10801 {
10802 struct epoll_event ep;
10803 struct epoll_event *epp = 0;
10804 if (arg4) {
10805 struct target_epoll_event *target_ep;
10806 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
10807 goto efault;
10808 }
10809 ep.events = tswap32(target_ep->events);
10810 /* The epoll_data_t union is just opaque data to the kernel,
10811 * so we transfer all 64 bits across and need not worry what
10812 * actual data type it is.
10813 */
10814 ep.data.u64 = tswap64(target_ep->data.u64);
10815 unlock_user_struct(target_ep, arg4, 0);
10816 epp = &ep;
10817 }
10818 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
10819 break;
10820 }
10821#endif
10822
10823#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
10824#define IMPLEMENT_EPOLL_PWAIT
10825#endif
10826#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
10827#if defined(TARGET_NR_epoll_wait)
10828 case TARGET_NR_epoll_wait:
10829#endif
10830#if defined(IMPLEMENT_EPOLL_PWAIT)
10831 case TARGET_NR_epoll_pwait:
10832#endif
10833 {
10834 struct target_epoll_event *target_ep;
10835 struct epoll_event *ep;
10836 int epfd = arg1;
10837 int maxevents = arg3;
10838 int timeout = arg4;
10839
10840 target_ep = lock_user(VERIFY_WRITE, arg2,
10841 maxevents * sizeof(struct target_epoll_event), 1);
10842 if (!target_ep) {
10843 goto efault;
10844 }
10845
10846 ep = alloca(maxevents * sizeof(struct epoll_event));
10847
10848 switch (num) {
10849#if defined(IMPLEMENT_EPOLL_PWAIT)
10850 case TARGET_NR_epoll_pwait:
10851 {
10852 target_sigset_t *target_set;
10853 sigset_t _set, *set = &_set;
10854
10855 if (arg5) {
10856 target_set = lock_user(VERIFY_READ, arg5,
10857 sizeof(target_sigset_t), 1);
10858 if (!target_set) {
10859 unlock_user(target_ep, arg2, 0);
10860 goto efault;
10861 }
10862 target_to_host_sigset(set, target_set);
10863 unlock_user(target_set, arg5, 0);
10864 } else {
10865 set = NULL;
10866 }
10867
10868 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
10869 break;
10870 }
10871#endif
10872#if defined(TARGET_NR_epoll_wait)
10873 case TARGET_NR_epoll_wait:
10874 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
10875 break;
10876#endif
10877 default:
10878 ret = -TARGET_ENOSYS;
10879 }
10880 if (!is_error(ret)) {
10881 int i;
10882 for (i = 0; i < ret; i++) {
10883 target_ep[i].events = tswap32(ep[i].events);
10884 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
10885 }
10886 }
10887 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
10888 break;
10889 }
10890#endif
10891#endif
Peter Maydell163a05a2011-06-27 17:44:52 +010010892#ifdef TARGET_NR_prlimit64
10893 case TARGET_NR_prlimit64:
10894 {
10895 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
10896 struct target_rlimit64 *target_rnew, *target_rold;
10897 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +010010898 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +010010899 if (arg3) {
10900 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
10901 goto efault;
10902 }
10903 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
10904 rnew.rlim_max = tswap64(target_rnew->rlim_max);
10905 unlock_user_struct(target_rnew, arg3, 0);
10906 rnewp = &rnew;
10907 }
10908
Felix Janda95018012014-12-02 22:11:17 +010010909 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +010010910 if (!is_error(ret) && arg4) {
10911 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
10912 goto efault;
10913 }
10914 target_rold->rlim_cur = tswap64(rold.rlim_cur);
10915 target_rold->rlim_max = tswap64(rold.rlim_max);
10916 unlock_user_struct(target_rold, arg4, 1);
10917 }
10918 break;
10919 }
10920#endif
Richard Henderson3d21d292012-09-15 13:20:46 -070010921#ifdef TARGET_NR_gethostname
10922 case TARGET_NR_gethostname:
10923 {
10924 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
10925 if (name) {
10926 ret = get_errno(gethostname(name, arg2));
10927 unlock_user(name, arg1, arg2);
10928 } else {
10929 ret = -TARGET_EFAULT;
10930 }
10931 break;
10932 }
10933#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010934#ifdef TARGET_NR_atomic_cmpxchg_32
10935 case TARGET_NR_atomic_cmpxchg_32:
10936 {
10937 /* should use start_exclusive from main.c */
10938 abi_ulong mem_value;
10939 if (get_user_u32(mem_value, arg6)) {
10940 target_siginfo_t info;
10941 info.si_signo = SIGSEGV;
10942 info.si_errno = 0;
10943 info.si_code = TARGET_SEGV_MAPERR;
10944 info._sifields._sigfault._addr = arg6;
10945 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
10946 ret = 0xdeadbeef;
10947
10948 }
10949 if (mem_value == arg2)
10950 put_user_u32(arg1, arg6);
10951 ret = mem_value;
10952 break;
10953 }
10954#endif
10955#ifdef TARGET_NR_atomic_barrier
10956 case TARGET_NR_atomic_barrier:
10957 {
10958 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +000010959 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +030010960 break;
10961 }
10962#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010963
10964#ifdef TARGET_NR_timer_create
10965 case TARGET_NR_timer_create:
10966 {
10967 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
10968
10969 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010970
10971 int clkid = arg1;
10972 int timer_index = next_free_host_timer();
10973
10974 if (timer_index < 0) {
10975 ret = -TARGET_EAGAIN;
10976 } else {
10977 timer_t *phtimer = g_posix_timers + timer_index;
10978
10979 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010980 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +010010981 ret = target_to_host_sigevent(phost_sevp, arg2);
10982 if (ret != 0) {
10983 break;
10984 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010985 }
10986
10987 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
10988 if (ret) {
10989 phtimer = NULL;
10990 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +010010991 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010992 goto efault;
10993 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110010994 }
10995 }
10996 break;
10997 }
10998#endif
10999
11000#ifdef TARGET_NR_timer_settime
11001 case TARGET_NR_timer_settime:
11002 {
11003 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
11004 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011005 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011006
Alexander Grafaecc8862014-11-10 21:33:03 +010011007 if (timerid < 0) {
11008 ret = timerid;
11009 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011010 ret = -TARGET_EINVAL;
11011 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011012 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011013 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
11014
11015 target_to_host_itimerspec(&hspec_new, arg3);
11016 ret = get_errno(
11017 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
11018 host_to_target_itimerspec(arg2, &hspec_old);
11019 }
11020 break;
11021 }
11022#endif
11023
11024#ifdef TARGET_NR_timer_gettime
11025 case TARGET_NR_timer_gettime:
11026 {
11027 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +010011028 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011029
Alexander Grafaecc8862014-11-10 21:33:03 +010011030 if (timerid < 0) {
11031 ret = timerid;
11032 } else if (!arg2) {
11033 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011034 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011035 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011036 struct itimerspec hspec;
11037 ret = get_errno(timer_gettime(htimer, &hspec));
11038
11039 if (host_to_target_itimerspec(arg2, &hspec)) {
11040 ret = -TARGET_EFAULT;
11041 }
11042 }
11043 break;
11044 }
11045#endif
11046
11047#ifdef TARGET_NR_timer_getoverrun
11048 case TARGET_NR_timer_getoverrun:
11049 {
11050 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011051 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011052
Alexander Grafaecc8862014-11-10 21:33:03 +010011053 if (timerid < 0) {
11054 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011055 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011056 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011057 ret = get_errno(timer_getoverrun(htimer));
11058 }
Laurent Viviere36800c2015-10-02 14:48:09 +020011059 fd_trans_unregister(ret);
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011060 break;
11061 }
11062#endif
11063
11064#ifdef TARGET_NR_timer_delete
11065 case TARGET_NR_timer_delete:
11066 {
11067 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +010011068 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +020011069
Alexander Grafaecc8862014-11-10 21:33:03 +010011070 if (timerid < 0) {
11071 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011072 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +020011073 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011074 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +020011075 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +110011076 }
11077 break;
11078 }
11079#endif
11080
Riku Voipio51834342014-06-22 11:25:42 +010011081#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
11082 case TARGET_NR_timerfd_create:
11083 ret = get_errno(timerfd_create(arg1,
11084 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
11085 break;
11086#endif
11087
11088#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
11089 case TARGET_NR_timerfd_gettime:
11090 {
11091 struct itimerspec its_curr;
11092
11093 ret = get_errno(timerfd_gettime(arg1, &its_curr));
11094
11095 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
11096 goto efault;
11097 }
11098 }
11099 break;
11100#endif
11101
11102#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
11103 case TARGET_NR_timerfd_settime:
11104 {
11105 struct itimerspec its_new, its_old, *p_new;
11106
11107 if (arg3) {
11108 if (target_to_host_itimerspec(&its_new, arg3)) {
11109 goto efault;
11110 }
11111 p_new = &its_new;
11112 } else {
11113 p_new = NULL;
11114 }
11115
11116 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
11117
11118 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
11119 goto efault;
11120 }
11121 }
11122 break;
11123#endif
11124
Paul Burtonab31cda2014-06-22 11:25:43 +010011125#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
11126 case TARGET_NR_ioprio_get:
11127 ret = get_errno(ioprio_get(arg1, arg2));
11128 break;
11129#endif
11130
11131#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
11132 case TARGET_NR_ioprio_set:
11133 ret = get_errno(ioprio_set(arg1, arg2, arg3));
11134 break;
11135#endif
11136
Riku Voipio9af5c902014-08-12 15:58:57 +030011137#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
11138 case TARGET_NR_setns:
11139 ret = get_errno(setns(arg1, arg2));
11140 break;
11141#endif
11142#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
11143 case TARGET_NR_unshare:
11144 ret = get_errno(unshare(arg1));
11145 break;
11146#endif
11147
bellard31e31b82003-02-18 22:55:36 +000011148 default:
11149 unimplemented:
bellard5cd43932003-03-29 16:54:36 +000011150 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +000011151#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 +000011152 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +000011153#endif
ths0da46a62007-10-20 20:23:07 +000011154 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +000011155 break;
11156 }
bellard579a97f2007-11-11 14:26:47 +000011157fail:
bellardc573ff62004-01-04 15:51:36 +000011158#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +000011159 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +000011160#endif
thsb92c47c2007-11-01 00:07:38 +000011161 if(do_strace)
11162 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +000011163 return ret;
bellard579a97f2007-11-11 14:26:47 +000011164efault:
11165 ret = -TARGET_EFAULT;
11166 goto fail;
bellard31e31b82003-02-18 22:55:36 +000011167}