blob: d4398b9c566949fdf231d5066a7e8de7af814f0d [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
John Spencerc56dc772012-12-10 07:59:46 +010031#include <grp.h>
bellard31e31b82003-02-18 22:55:36 +000032#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000033#include <sys/ipc.h>
34#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/stat.h>
38#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010039#include <sys/file.h>
40#include <sys/fsuid.h>
41#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000042#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/resource.h>
44#include <sys/mman.h>
45#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000046#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000047#include <signal.h>
48#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020049#ifdef __ia64__
50int __clone2(int (*fn)(void *), void *child_stack_base,
51 size_t stack_size, int flags, void *arg, ...);
52#endif
bellard31e31b82003-02-18 22:55:36 +000053#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000054#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000055#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000056#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000057#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000058#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000059#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000060#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000061#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000062#include <sys/sysinfo.h>
bellard72f03902003-02-18 23:33:18 +000063//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000064#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000065#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020066#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000067#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020068#include "qemu-common.h"
Riku Voipiod80a1902014-10-01 16:05:46 +030069#ifdef CONFIG_TIMERFD
70#include <sys/timerfd.h>
71#endif
Juan Quintela9788c9c2009-07-27 16:13:02 +020072#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000073#include <sys/gmon.h>
74#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030075#ifdef CONFIG_EVENTFD
76#include <sys/eventfd.h>
77#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000078#ifdef CONFIG_EPOLL
79#include <sys/epoll.h>
80#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070081#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010082#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070083#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000084#ifdef CONFIG_SENDFILE
85#include <sys/sendfile.h>
86#endif
bellard31e31b82003-02-18 22:55:36 +000087
88#define termios host_termios
89#define winsize host_winsize
90#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000091#define sgttyb host_sgttyb /* same as target */
92#define tchars host_tchars /* same as target */
93#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000094
95#include <linux/termios.h>
96#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000097#include <linux/cdrom.h>
98#include <linux/hdreg.h>
99#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +0000100#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +0000101#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300102#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000103#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000104#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000105#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200106#include <linux/fb.h>
107#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100108#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000109#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100110#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200111#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100112#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000113#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200114#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000115
bellard3ef693a2003-03-23 20:17:16 +0000116#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000117
pbrookd865bab2008-06-07 22:12:17 +0000118#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
119 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000120
bellard72f03902003-02-18 23:33:18 +0000121//#define DEBUG
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
bellard70a194b2003-08-11 22:20:16 +0000127
bellard70a194b2003-08-11 22:20:16 +0000128#undef _syscall0
129#undef _syscall1
130#undef _syscall2
131#undef _syscall3
132#undef _syscall4
133#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000134#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000135
bellard83fcb512006-06-14 13:37:16 +0000136#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000137static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000138{ \
139 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000140}
141
bellard83fcb512006-06-14 13:37:16 +0000142#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000143static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000144{ \
145 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000146}
147
bellard83fcb512006-06-14 13:37:16 +0000148#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000149static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000150{ \
151 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000152}
153
bellard83fcb512006-06-14 13:37:16 +0000154#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000155static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000156{ \
157 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000158}
159
bellard83fcb512006-06-14 13:37:16 +0000160#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000161static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000162{ \
163 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000164}
165
bellard83fcb512006-06-14 13:37:16 +0000166#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
167 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000168static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000169{ \
170 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000171}
bellard83fcb512006-06-14 13:37:16 +0000172
173
174#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
175 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000176static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
177 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000178{ \
179 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
180}
181
bellard70a194b2003-08-11 22:20:16 +0000182
bellard31e31b82003-02-18 22:55:36 +0000183#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000185#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000186#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000187#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000188#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000189#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000190#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000191#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000192#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000193#define __NR_sys_inotify_init __NR_inotify_init
194#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
195#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000196
Alexander Graf42a39fb2011-04-15 17:32:45 +0200197#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
198 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000199#define __NR__llseek __NR_lseek
200#endif
201
James Hogana29e5ba2014-03-25 21:51:08 +0000202/* Newer kernel ports have llseek() instead of _llseek() */
203#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
204#define TARGET_NR__llseek TARGET_NR_llseek
205#endif
206
bellard72f03902003-02-18 23:33:18 +0000207#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000208_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000209#else
ths0da46a62007-10-20 20:23:07 +0000210/* This is a replacement for the host gettid() and must return a host
211 errno. */
bellard72f03902003-02-18 23:33:18 +0000212static int gettid(void) {
213 return -ENOSYS;
214}
215#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100216#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000217_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100218#endif
219#if !defined(__NR_getdents) || \
220 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000221_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
222#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700223#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000224_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
225 loff_t *, res, uint, wh);
226#endif
227_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
228_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
229#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
230_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
231#endif
232#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
233_syscall2(int,sys_tkill,int,tid,int,sig)
234#endif
235#ifdef __NR_exit_group
236_syscall1(int,exit_group,int,error_code)
237#endif
238#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
239_syscall1(int,set_tid_address,int *,tidptr)
240#endif
aurel323b3f24a2009-04-15 16:12:13 +0000241#if defined(TARGET_NR_futex) && defined(__NR_futex)
242_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
243 const struct timespec *,timeout,int *,uaddr2,int,val3)
244#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500245#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
246_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
247 unsigned long *, user_mask_ptr);
248#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
249_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
250 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200251_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
252 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000253_syscall2(int, capget, struct __user_cap_header_struct *, header,
254 struct __user_cap_data_struct *, data);
255_syscall2(int, capset, struct __user_cap_header_struct *, header,
256 struct __user_cap_data_struct *, data);
Paul Burtonab31cda2014-06-22 11:25:43 +0100257#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
258_syscall2(int, ioprio_get, int, which, int, who)
259#endif
260#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
261_syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
262#endif
aurel323b3f24a2009-04-15 16:12:13 +0000263
264static bitmask_transtbl fcntl_flags_tbl[] = {
265 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
266 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
267 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
268 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
269 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
270 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
271 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
272 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700273 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000274 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
275 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
276 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
277 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000278#if defined(O_DIRECT)
279 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
280#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700281#if defined(O_NOATIME)
282 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
283#endif
284#if defined(O_CLOEXEC)
285 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
286#endif
287#if defined(O_PATH)
288 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
289#endif
290 /* Don't terminate the list prematurely on 64-bit host+guest. */
291#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
292 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
293#endif
aurel323b3f24a2009-04-15 16:12:13 +0000294 { 0, 0, 0, 0 }
295};
296
aurel323b3f24a2009-04-15 16:12:13 +0000297static int sys_getcwd1(char *buf, size_t size)
298{
299 if (getcwd(buf, size) == NULL) {
300 /* getcwd() sets errno */
301 return (-1);
302 }
aurel32aaf4ad32009-04-16 14:17:14 +0000303 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000304}
305
Alexander Graff4c69012011-09-25 06:25:35 +0200306static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000307{
308 /*
309 * open(2) has extra parameter 'mode' when called with
310 * flag O_CREAT.
311 */
312 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000313 return (openat(dirfd, pathname, flags, mode));
314 }
315 return (openat(dirfd, pathname, flags));
316}
Riku Voipioebc996f2009-04-21 15:01:51 +0300317
Peter Maydell1acae9f2013-07-02 14:04:12 +0100318#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300319#ifdef CONFIG_UTIMENSAT
320static int sys_utimensat(int dirfd, const char *pathname,
321 const struct timespec times[2], int flags)
322{
323 if (pathname == NULL)
324 return futimens(dirfd, times);
325 else
326 return utimensat(dirfd, pathname, times, flags);
327}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100328#elif defined(__NR_utimensat)
329#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000330_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
331 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100332#else
333static int sys_utimensat(int dirfd, const char *pathname,
334 const struct timespec times[2], int flags)
335{
336 errno = ENOSYS;
337 return -1;
338}
ths9007f0e2007-09-25 17:50:37 +0000339#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100340#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000341
342#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000343#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000344
aurel3239b59762008-10-01 21:46:50 +0000345#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000346static int sys_inotify_init(void)
347{
348 return (inotify_init());
349}
aurel3239b59762008-10-01 21:46:50 +0000350#endif
351#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000352static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
353{
354 return (inotify_add_watch(fd, pathname, mask));
355}
aurel3239b59762008-10-01 21:46:50 +0000356#endif
357#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000358static int sys_inotify_rm_watch(int fd, int32_t wd)
359{
aurel328690e422009-04-17 13:50:32 +0000360 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000361}
aurel3239b59762008-10-01 21:46:50 +0000362#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000363#ifdef CONFIG_INOTIFY1
364#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
365static int sys_inotify_init1(int flags)
366{
367 return (inotify_init1(flags));
368}
369#endif
370#endif
aurel323b3f24a2009-04-15 16:12:13 +0000371#else
372/* Userspace can usually survive runtime without inotify */
373#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000374#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000375#undef TARGET_NR_inotify_add_watch
376#undef TARGET_NR_inotify_rm_watch
377#endif /* CONFIG_INOTIFY */
378
Mike Frysingerd8035d42011-02-07 01:05:51 -0500379#if defined(TARGET_NR_ppoll)
380#ifndef __NR_ppoll
381# define __NR_ppoll -1
382#endif
383#define __NR_sys_ppoll __NR_ppoll
384_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200385 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500386 size_t, sigsetsize)
387#endif
bellard66fb9762003-03-23 01:06:05 +0000388
Mike Frysinger055e0902011-06-03 17:01:49 -0400389#if defined(TARGET_NR_pselect6)
390#ifndef __NR_pselect6
391# define __NR_pselect6 -1
392#endif
393#define __NR_sys_pselect6 __NR_pselect6
394_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
395 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
396#endif
397
Peter Maydell163a05a2011-06-27 17:44:52 +0100398#if defined(TARGET_NR_prlimit64)
399#ifndef __NR_prlimit64
400# define __NR_prlimit64 -1
401#endif
402#define __NR_sys_prlimit64 __NR_prlimit64
403/* The glibc rlimit structure may not be that used by the underlying syscall */
404struct host_rlimit64 {
405 uint64_t rlim_cur;
406 uint64_t rlim_max;
407};
408_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
409 const struct host_rlimit64 *, new_limit,
410 struct host_rlimit64 *, old_limit)
411#endif
412
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100413
414#if defined(TARGET_NR_timer_create)
415/* Maxiumum of 32 active POSIX timers allowed at any one time. */
416static timer_t g_posix_timers[32] = { 0, } ;
417
418static inline int next_free_host_timer(void)
419{
420 int k ;
421 /* FIXME: Does finding the next free slot require a lock? */
422 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
423 if (g_posix_timers[k] == 0) {
424 g_posix_timers[k] = (timer_t) 1;
425 return k;
426 }
427 }
428 return -1;
429}
430#endif
431
Riku Voipio48e515d2011-07-12 15:40:51 +0300432/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000433#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300434static inline int regpairs_aligned(void *cpu_env) {
435 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
436}
437#elif defined(TARGET_MIPS)
438static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000439#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
440/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
441 * of registers which translates to the same as ARM/MIPS, because we start with
442 * r3 as arg1 */
443static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300444#else
445static inline int regpairs_aligned(void *cpu_env) { return 0; }
446#endif
447
thsb92c47c2007-11-01 00:07:38 +0000448#define ERRNO_TABLE_SIZE 1200
449
450/* target_to_host_errno_table[] is initialized from
451 * host_to_target_errno_table[] in syscall_init(). */
452static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
453};
454
ths637947f2007-06-01 12:09:19 +0000455/*
thsfe8f0962007-07-12 10:59:21 +0000456 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000457 * minus the errnos that are not actually generic to all archs.
458 */
thsb92c47c2007-11-01 00:07:38 +0000459static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000460 [EIDRM] = TARGET_EIDRM,
461 [ECHRNG] = TARGET_ECHRNG,
462 [EL2NSYNC] = TARGET_EL2NSYNC,
463 [EL3HLT] = TARGET_EL3HLT,
464 [EL3RST] = TARGET_EL3RST,
465 [ELNRNG] = TARGET_ELNRNG,
466 [EUNATCH] = TARGET_EUNATCH,
467 [ENOCSI] = TARGET_ENOCSI,
468 [EL2HLT] = TARGET_EL2HLT,
469 [EDEADLK] = TARGET_EDEADLK,
470 [ENOLCK] = TARGET_ENOLCK,
471 [EBADE] = TARGET_EBADE,
472 [EBADR] = TARGET_EBADR,
473 [EXFULL] = TARGET_EXFULL,
474 [ENOANO] = TARGET_ENOANO,
475 [EBADRQC] = TARGET_EBADRQC,
476 [EBADSLT] = TARGET_EBADSLT,
477 [EBFONT] = TARGET_EBFONT,
478 [ENOSTR] = TARGET_ENOSTR,
479 [ENODATA] = TARGET_ENODATA,
480 [ETIME] = TARGET_ETIME,
481 [ENOSR] = TARGET_ENOSR,
482 [ENONET] = TARGET_ENONET,
483 [ENOPKG] = TARGET_ENOPKG,
484 [EREMOTE] = TARGET_EREMOTE,
485 [ENOLINK] = TARGET_ENOLINK,
486 [EADV] = TARGET_EADV,
487 [ESRMNT] = TARGET_ESRMNT,
488 [ECOMM] = TARGET_ECOMM,
489 [EPROTO] = TARGET_EPROTO,
490 [EDOTDOT] = TARGET_EDOTDOT,
491 [EMULTIHOP] = TARGET_EMULTIHOP,
492 [EBADMSG] = TARGET_EBADMSG,
493 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
494 [EOVERFLOW] = TARGET_EOVERFLOW,
495 [ENOTUNIQ] = TARGET_ENOTUNIQ,
496 [EBADFD] = TARGET_EBADFD,
497 [EREMCHG] = TARGET_EREMCHG,
498 [ELIBACC] = TARGET_ELIBACC,
499 [ELIBBAD] = TARGET_ELIBBAD,
500 [ELIBSCN] = TARGET_ELIBSCN,
501 [ELIBMAX] = TARGET_ELIBMAX,
502 [ELIBEXEC] = TARGET_ELIBEXEC,
503 [EILSEQ] = TARGET_EILSEQ,
504 [ENOSYS] = TARGET_ENOSYS,
505 [ELOOP] = TARGET_ELOOP,
506 [ERESTART] = TARGET_ERESTART,
507 [ESTRPIPE] = TARGET_ESTRPIPE,
508 [ENOTEMPTY] = TARGET_ENOTEMPTY,
509 [EUSERS] = TARGET_EUSERS,
510 [ENOTSOCK] = TARGET_ENOTSOCK,
511 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
512 [EMSGSIZE] = TARGET_EMSGSIZE,
513 [EPROTOTYPE] = TARGET_EPROTOTYPE,
514 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
515 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
516 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
517 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
518 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
519 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
520 [EADDRINUSE] = TARGET_EADDRINUSE,
521 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
522 [ENETDOWN] = TARGET_ENETDOWN,
523 [ENETUNREACH] = TARGET_ENETUNREACH,
524 [ENETRESET] = TARGET_ENETRESET,
525 [ECONNABORTED] = TARGET_ECONNABORTED,
526 [ECONNRESET] = TARGET_ECONNRESET,
527 [ENOBUFS] = TARGET_ENOBUFS,
528 [EISCONN] = TARGET_EISCONN,
529 [ENOTCONN] = TARGET_ENOTCONN,
530 [EUCLEAN] = TARGET_EUCLEAN,
531 [ENOTNAM] = TARGET_ENOTNAM,
532 [ENAVAIL] = TARGET_ENAVAIL,
533 [EISNAM] = TARGET_EISNAM,
534 [EREMOTEIO] = TARGET_EREMOTEIO,
535 [ESHUTDOWN] = TARGET_ESHUTDOWN,
536 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
537 [ETIMEDOUT] = TARGET_ETIMEDOUT,
538 [ECONNREFUSED] = TARGET_ECONNREFUSED,
539 [EHOSTDOWN] = TARGET_EHOSTDOWN,
540 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
541 [EALREADY] = TARGET_EALREADY,
542 [EINPROGRESS] = TARGET_EINPROGRESS,
543 [ESTALE] = TARGET_ESTALE,
544 [ECANCELED] = TARGET_ECANCELED,
545 [ENOMEDIUM] = TARGET_ENOMEDIUM,
546 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000547#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000548 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000549#endif
550#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000551 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000552#endif
553#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000554 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000555#endif
556#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000557 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000558#endif
559#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000560 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000561#endif
562#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000563 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000564#endif
thsb92c47c2007-11-01 00:07:38 +0000565};
ths637947f2007-06-01 12:09:19 +0000566
567static inline int host_to_target_errno(int err)
568{
569 if(host_to_target_errno_table[err])
570 return host_to_target_errno_table[err];
571 return err;
572}
573
thsb92c47c2007-11-01 00:07:38 +0000574static inline int target_to_host_errno(int err)
575{
576 if (target_to_host_errno_table[err])
577 return target_to_host_errno_table[err];
578 return err;
579}
580
blueswir1992f48a2007-10-14 16:27:31 +0000581static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000582{
583 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000584 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000585 else
586 return ret;
587}
588
blueswir1992f48a2007-10-14 16:27:31 +0000589static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000590{
blueswir1992f48a2007-10-14 16:27:31 +0000591 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000592}
593
thsb92c47c2007-11-01 00:07:38 +0000594char *target_strerror(int err)
595{
Alexander Graf962b2892011-11-21 12:04:07 +0100596 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
597 return NULL;
598 }
thsb92c47c2007-11-01 00:07:38 +0000599 return strerror(target_to_host_errno(err));
600}
601
Paul Burton8289d112014-06-22 11:25:33 +0100602static inline int host_to_target_sock_type(int host_type)
603{
604 int target_type;
605
606 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
607 case SOCK_DGRAM:
608 target_type = TARGET_SOCK_DGRAM;
609 break;
610 case SOCK_STREAM:
611 target_type = TARGET_SOCK_STREAM;
612 break;
613 default:
614 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
615 break;
616 }
617
618#if defined(SOCK_CLOEXEC)
619 if (host_type & SOCK_CLOEXEC) {
620 target_type |= TARGET_SOCK_CLOEXEC;
621 }
622#endif
623
624#if defined(SOCK_NONBLOCK)
625 if (host_type & SOCK_NONBLOCK) {
626 target_type |= TARGET_SOCK_NONBLOCK;
627 }
628#endif
629
630 return target_type;
631}
632
blueswir1992f48a2007-10-14 16:27:31 +0000633static abi_ulong target_brk;
634static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000635static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000636
blueswir1992f48a2007-10-14 16:27:31 +0000637void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000638{
blueswir14c1de732007-07-07 20:45:44 +0000639 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000640 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000641}
642
vincent4d1de872011-06-14 21:56:33 +0000643//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
644#define DEBUGF_BRK(message, args...)
645
ths0da46a62007-10-20 20:23:07 +0000646/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000647abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000648{
blueswir1992f48a2007-10-14 16:27:31 +0000649 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000650 int new_alloc_size;
651
Paul Brook3a0c6c42012-02-09 19:04:27 +0000652 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000653
vincent4d1de872011-06-14 21:56:33 +0000654 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000655 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000656 return target_brk;
657 }
658 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000659 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
660 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000661 return target_brk;
662 }
bellard31e31b82003-02-18 22:55:36 +0000663
vincent4d1de872011-06-14 21:56:33 +0000664 /* If the new brk is less than the highest page reserved to the
665 * target heap allocation, set it and we're almost done... */
666 if (new_brk <= brk_page) {
667 /* Heap contents are initialized to zero, as for anonymous
668 * mapped pages. */
669 if (new_brk > target_brk) {
670 memset(g2h(target_brk), 0, new_brk - target_brk);
671 }
bellard31e31b82003-02-18 22:55:36 +0000672 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000673 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000674 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000675 }
676
Peter Maydell00faf082011-04-18 16:34:24 +0100677 /* We need to allocate more memory after the brk... Note that
678 * we don't use MAP_FIXED because that will map over the top of
679 * any existing mapping (like the one with the host libc or qemu
680 * itself); instead we treat "mapped but at wrong address" as
681 * a failure and unmap again.
682 */
vincent4d1de872011-06-14 21:56:33 +0000683 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000684 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000685 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100686 MAP_ANON|MAP_PRIVATE, 0, 0));
687
688 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200689 /* Heap contents are initialized to zero, as for anonymous
690 * mapped pages. Technically the new pages are already
691 * initialized to zero since they *are* anonymous mapped
692 * pages, however we have to take care with the contents that
693 * come from the remaining part of the previous page: it may
694 * contains garbage data due to a previous heap usage (grown
695 * then shrunken). */
696 memset(g2h(target_brk), 0, brk_page - target_brk);
697
Peter Maydell00faf082011-04-18 16:34:24 +0100698 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000699 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000700 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
701 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100702 return target_brk;
703 } else if (mapped_addr != -1) {
704 /* Mapped but at wrong address, meaning there wasn't actually
705 * enough space for this brk.
706 */
707 target_munmap(mapped_addr, new_alloc_size);
708 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000709 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000710 }
711 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000712 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100713 }
balrog7ab240a2008-04-26 12:17:34 +0000714
Richard Henderson7dd46c02010-05-03 10:07:49 -0700715#if defined(TARGET_ALPHA)
716 /* We (partially) emulate OSF/1 on Alpha, which requires we
717 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100718 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700719#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100720 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000721 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000722}
723
ths26edcf42007-12-09 02:25:24 +0000724static inline abi_long copy_from_user_fdset(fd_set *fds,
725 abi_ulong target_fds_addr,
726 int n)
bellard31e31b82003-02-18 22:55:36 +0000727{
ths26edcf42007-12-09 02:25:24 +0000728 int i, nw, j, k;
729 abi_ulong b, *target_fds;
730
731 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
732 if (!(target_fds = lock_user(VERIFY_READ,
733 target_fds_addr,
734 sizeof(abi_ulong) * nw,
735 1)))
736 return -TARGET_EFAULT;
737
738 FD_ZERO(fds);
739 k = 0;
740 for (i = 0; i < nw; i++) {
741 /* grab the abi_ulong */
742 __get_user(b, &target_fds[i]);
743 for (j = 0; j < TARGET_ABI_BITS; j++) {
744 /* check the bit inside the abi_ulong */
745 if ((b >> j) & 1)
746 FD_SET(k, fds);
747 k++;
bellard31e31b82003-02-18 22:55:36 +0000748 }
bellard31e31b82003-02-18 22:55:36 +0000749 }
ths26edcf42007-12-09 02:25:24 +0000750
751 unlock_user(target_fds, target_fds_addr, 0);
752
753 return 0;
bellard31e31b82003-02-18 22:55:36 +0000754}
755
Mike Frysinger055e0902011-06-03 17:01:49 -0400756static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
757 abi_ulong target_fds_addr,
758 int n)
759{
760 if (target_fds_addr) {
761 if (copy_from_user_fdset(fds, target_fds_addr, n))
762 return -TARGET_EFAULT;
763 *fds_ptr = fds;
764 } else {
765 *fds_ptr = NULL;
766 }
767 return 0;
768}
769
ths26edcf42007-12-09 02:25:24 +0000770static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
771 const fd_set *fds,
772 int n)
bellard31e31b82003-02-18 22:55:36 +0000773{
bellard31e31b82003-02-18 22:55:36 +0000774 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000776 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000777
ths26edcf42007-12-09 02:25:24 +0000778 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
779 if (!(target_fds = lock_user(VERIFY_WRITE,
780 target_fds_addr,
781 sizeof(abi_ulong) * nw,
782 0)))
783 return -TARGET_EFAULT;
784
785 k = 0;
786 for (i = 0; i < nw; i++) {
787 v = 0;
788 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000789 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000790 k++;
bellard31e31b82003-02-18 22:55:36 +0000791 }
ths26edcf42007-12-09 02:25:24 +0000792 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000793 }
ths26edcf42007-12-09 02:25:24 +0000794
795 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
796
797 return 0;
bellard31e31b82003-02-18 22:55:36 +0000798}
799
bellardc596ed12003-07-13 17:32:31 +0000800#if defined(__alpha__)
801#define HOST_HZ 1024
802#else
803#define HOST_HZ 100
804#endif
805
blueswir1992f48a2007-10-14 16:27:31 +0000806static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000807{
808#if HOST_HZ == TARGET_HZ
809 return ticks;
810#else
811 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
812#endif
813}
814
bellard579a97f2007-11-11 14:26:47 +0000815static inline abi_long host_to_target_rusage(abi_ulong target_addr,
816 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000817{
pbrook53a59602006-03-25 19:31:22 +0000818 struct target_rusage *target_rusage;
819
bellard579a97f2007-11-11 14:26:47 +0000820 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
821 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200822 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
823 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
824 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
825 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
826 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
827 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
828 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
829 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
830 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
831 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
832 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
833 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
834 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
835 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
836 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
837 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
838 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
839 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000840 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000841
842 return 0;
bellardb4091862003-05-16 15:39:34 +0000843}
844
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200845static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900846{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200847 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300848 rlim_t result;
849
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200850 target_rlim_swap = tswapal(target_rlim);
851 if (target_rlim_swap == TARGET_RLIM_INFINITY)
852 return RLIM_INFINITY;
853
854 result = target_rlim_swap;
855 if (target_rlim_swap != (rlim_t)result)
856 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300857
858 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900859}
860
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200861static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900862{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200863 abi_ulong target_rlim_swap;
864 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300865
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200866 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300867 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900868 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300869 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200870 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300871
872 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900873}
874
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300875static inline int target_to_host_resource(int code)
876{
877 switch (code) {
878 case TARGET_RLIMIT_AS:
879 return RLIMIT_AS;
880 case TARGET_RLIMIT_CORE:
881 return RLIMIT_CORE;
882 case TARGET_RLIMIT_CPU:
883 return RLIMIT_CPU;
884 case TARGET_RLIMIT_DATA:
885 return RLIMIT_DATA;
886 case TARGET_RLIMIT_FSIZE:
887 return RLIMIT_FSIZE;
888 case TARGET_RLIMIT_LOCKS:
889 return RLIMIT_LOCKS;
890 case TARGET_RLIMIT_MEMLOCK:
891 return RLIMIT_MEMLOCK;
892 case TARGET_RLIMIT_MSGQUEUE:
893 return RLIMIT_MSGQUEUE;
894 case TARGET_RLIMIT_NICE:
895 return RLIMIT_NICE;
896 case TARGET_RLIMIT_NOFILE:
897 return RLIMIT_NOFILE;
898 case TARGET_RLIMIT_NPROC:
899 return RLIMIT_NPROC;
900 case TARGET_RLIMIT_RSS:
901 return RLIMIT_RSS;
902 case TARGET_RLIMIT_RTPRIO:
903 return RLIMIT_RTPRIO;
904 case TARGET_RLIMIT_SIGPENDING:
905 return RLIMIT_SIGPENDING;
906 case TARGET_RLIMIT_STACK:
907 return RLIMIT_STACK;
908 default:
909 return code;
910 }
911}
912
ths788f5ec2007-12-09 02:37:05 +0000913static inline abi_long copy_from_user_timeval(struct timeval *tv,
914 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000915{
pbrook53a59602006-03-25 19:31:22 +0000916 struct target_timeval *target_tv;
917
ths788f5ec2007-12-09 02:37:05 +0000918 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000919 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000920
921 __get_user(tv->tv_sec, &target_tv->tv_sec);
922 __get_user(tv->tv_usec, &target_tv->tv_usec);
923
924 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000925
926 return 0;
bellard31e31b82003-02-18 22:55:36 +0000927}
928
ths788f5ec2007-12-09 02:37:05 +0000929static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
930 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000931{
pbrook53a59602006-03-25 19:31:22 +0000932 struct target_timeval *target_tv;
933
ths788f5ec2007-12-09 02:37:05 +0000934 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000935 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000936
937 __put_user(tv->tv_sec, &target_tv->tv_sec);
938 __put_user(tv->tv_usec, &target_tv->tv_usec);
939
940 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000941
942 return 0;
bellard31e31b82003-02-18 22:55:36 +0000943}
944
Paul Burtonef4467e2014-06-22 11:25:40 +0100945static inline abi_long copy_from_user_timezone(struct timezone *tz,
946 abi_ulong target_tz_addr)
947{
948 struct target_timezone *target_tz;
949
950 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
951 return -TARGET_EFAULT;
952 }
953
954 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
955 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
956
957 unlock_user_struct(target_tz, target_tz_addr, 0);
958
959 return 0;
960}
961
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700962#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
963#include <mqueue.h>
964
aurel3224e10032009-04-15 16:11:43 +0000965static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
966 abi_ulong target_mq_attr_addr)
967{
968 struct target_mq_attr *target_mq_attr;
969
970 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
971 target_mq_attr_addr, 1))
972 return -TARGET_EFAULT;
973
974 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
975 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
976 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
977 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
978
979 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
980
981 return 0;
982}
983
984static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
985 const struct mq_attr *attr)
986{
987 struct target_mq_attr *target_mq_attr;
988
989 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
990 target_mq_attr_addr, 0))
991 return -TARGET_EFAULT;
992
993 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
994 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
995 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
996 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
997
998 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
999
1000 return 0;
1001}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07001002#endif
bellard31e31b82003-02-18 22:55:36 +00001003
Mike Frysinger055e0902011-06-03 17:01:49 -04001004#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +00001005/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001006static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001007 abi_ulong rfd_addr, abi_ulong wfd_addr,
1008 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001009{
1010 fd_set rfds, wfds, efds;
1011 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1012 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001013 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001014
Mike Frysinger055e0902011-06-03 17:01:49 -04001015 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1016 if (ret) {
1017 return ret;
pbrook53a59602006-03-25 19:31:22 +00001018 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001019 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1020 if (ret) {
1021 return ret;
pbrook53a59602006-03-25 19:31:22 +00001022 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001023 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1024 if (ret) {
1025 return ret;
pbrook53a59602006-03-25 19:31:22 +00001026 }
ths3b46e622007-09-17 08:09:54 +00001027
ths26edcf42007-12-09 02:25:24 +00001028 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001029 if (copy_from_user_timeval(&tv, target_tv_addr))
1030 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001031 tv_ptr = &tv;
1032 } else {
1033 tv_ptr = NULL;
1034 }
ths26edcf42007-12-09 02:25:24 +00001035
bellard31e31b82003-02-18 22:55:36 +00001036 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001037
ths26edcf42007-12-09 02:25:24 +00001038 if (!is_error(ret)) {
1039 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1040 return -TARGET_EFAULT;
1041 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1042 return -TARGET_EFAULT;
1043 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1044 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001045
ths788f5ec2007-12-09 02:37:05 +00001046 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1047 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001048 }
bellard579a97f2007-11-11 14:26:47 +00001049
bellard31e31b82003-02-18 22:55:36 +00001050 return ret;
1051}
Mike Frysinger055e0902011-06-03 17:01:49 -04001052#endif
bellard31e31b82003-02-18 22:55:36 +00001053
Riku Voipio099d6b02009-05-05 12:10:04 +03001054static abi_long do_pipe2(int host_pipe[], int flags)
1055{
1056#ifdef CONFIG_PIPE2
1057 return pipe2(host_pipe, flags);
1058#else
1059 return -ENOSYS;
1060#endif
1061}
1062
Richard Hendersonfb41a662010-05-03 10:07:52 -07001063static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1064 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001065{
1066 int host_pipe[2];
1067 abi_long ret;
1068 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1069
1070 if (is_error(ret))
1071 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001072
1073 /* Several targets have special calling conventions for the original
1074 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1075 if (!is_pipe2) {
1076#if defined(TARGET_ALPHA)
1077 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1078 return host_pipe[0];
1079#elif defined(TARGET_MIPS)
1080 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1081 return host_pipe[0];
1082#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001083 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001084 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001085#elif defined(TARGET_SPARC)
1086 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1087 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001088#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001089 }
1090
Riku Voipio099d6b02009-05-05 12:10:04 +03001091 if (put_user_s32(host_pipe[0], pipedes)
1092 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1093 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001094 return get_errno(ret);
1095}
1096
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001097static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1098 abi_ulong target_addr,
1099 socklen_t len)
1100{
1101 struct target_ip_mreqn *target_smreqn;
1102
1103 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1104 if (!target_smreqn)
1105 return -TARGET_EFAULT;
1106 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1107 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1108 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001109 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001110 unlock_user(target_smreqn, target_addr, 0);
1111
1112 return 0;
1113}
1114
bellard579a97f2007-11-11 14:26:47 +00001115static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1116 abi_ulong target_addr,
1117 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001118{
aurel32607175e2009-04-15 16:11:59 +00001119 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1120 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001121 struct target_sockaddr *target_saddr;
1122
bellard579a97f2007-11-11 14:26:47 +00001123 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1124 if (!target_saddr)
1125 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001126
1127 sa_family = tswap16(target_saddr->sa_family);
1128
1129 /* Oops. The caller might send a incomplete sun_path; sun_path
1130 * must be terminated by \0 (see the manual page), but
1131 * unfortunately it is quite common to specify sockaddr_un
1132 * length as "strlen(x->sun_path)" while it should be
1133 * "strlen(...) + 1". We'll fix that here if needed.
1134 * Linux kernel has a similar feature.
1135 */
1136
1137 if (sa_family == AF_UNIX) {
1138 if (len < unix_maxlen && len > 0) {
1139 char *cp = (char*)target_saddr;
1140
1141 if ( cp[len-1] && !cp[len] )
1142 len++;
1143 }
1144 if (len > unix_maxlen)
1145 len = unix_maxlen;
1146 }
1147
pbrook53a59602006-03-25 19:31:22 +00001148 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001149 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001150 if (sa_family == AF_PACKET) {
1151 struct target_sockaddr_ll *lladdr;
1152
1153 lladdr = (struct target_sockaddr_ll *)addr;
1154 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1155 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1156 }
pbrook53a59602006-03-25 19:31:22 +00001157 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001158
1159 return 0;
bellard7854b052003-03-29 17:22:23 +00001160}
1161
bellard579a97f2007-11-11 14:26:47 +00001162static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1163 struct sockaddr *addr,
1164 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001165{
pbrook53a59602006-03-25 19:31:22 +00001166 struct target_sockaddr *target_saddr;
1167
bellard579a97f2007-11-11 14:26:47 +00001168 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1169 if (!target_saddr)
1170 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001171 memcpy(target_saddr, addr, len);
1172 target_saddr->sa_family = tswap16(addr->sa_family);
1173 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001174
1175 return 0;
bellard7854b052003-03-29 17:22:23 +00001176}
1177
bellard5a4a8982007-11-11 17:39:18 +00001178static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1179 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001180{
1181 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001182 abi_long msg_controllen;
1183 abi_ulong target_cmsg_addr;
1184 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001185 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001186
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001187 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001188 if (msg_controllen < sizeof (struct target_cmsghdr))
1189 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001190 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001191 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1192 if (!target_cmsg)
1193 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001194
1195 while (cmsg && target_cmsg) {
1196 void *data = CMSG_DATA(cmsg);
1197 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1198
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001199 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001200 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1201
1202 space += CMSG_SPACE(len);
1203 if (space > msgh->msg_controllen) {
1204 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001205 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001206 break;
1207 }
1208
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001209 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1210 cmsg->cmsg_level = SOL_SOCKET;
1211 } else {
1212 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1213 }
bellard7854b052003-03-29 17:22:23 +00001214 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1215 cmsg->cmsg_len = CMSG_LEN(len);
1216
Alex Suykov30b8b682014-12-23 07:52:58 +02001217 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001218 int *fd = (int *)data;
1219 int *target_fd = (int *)target_data;
1220 int i, numfds = len / sizeof(int);
1221
1222 for (i = 0; i < numfds; i++)
1223 fd[i] = tswap32(target_fd[i]);
Alex Suykov30b8b682014-12-23 07:52:58 +02001224 } else if (cmsg->cmsg_level == SOL_SOCKET
1225 && cmsg->cmsg_type == SCM_CREDENTIALS) {
1226 struct ucred *cred = (struct ucred *)data;
1227 struct target_ucred *target_cred =
1228 (struct target_ucred *)target_data;
1229
1230 __put_user(target_cred->pid, &cred->pid);
1231 __put_user(target_cred->uid, &cred->uid);
1232 __put_user(target_cred->gid, &cred->gid);
1233 } else {
1234 gemu_log("Unsupported ancillary data: %d/%d\n",
1235 cmsg->cmsg_level, cmsg->cmsg_type);
1236 memcpy(data, target_data, len);
bellard7854b052003-03-29 17:22:23 +00001237 }
1238
1239 cmsg = CMSG_NXTHDR(msgh, cmsg);
1240 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1241 }
bellard5a4a8982007-11-11 17:39:18 +00001242 unlock_user(target_cmsg, target_cmsg_addr, 0);
1243 the_end:
bellard7854b052003-03-29 17:22:23 +00001244 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001245 return 0;
bellard7854b052003-03-29 17:22:23 +00001246}
1247
bellard5a4a8982007-11-11 17:39:18 +00001248static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1249 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001250{
1251 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001252 abi_long msg_controllen;
1253 abi_ulong target_cmsg_addr;
1254 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001255 socklen_t space = 0;
1256
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001257 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001258 if (msg_controllen < sizeof (struct target_cmsghdr))
1259 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001260 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001261 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1262 if (!target_cmsg)
1263 return -TARGET_EFAULT;
1264
bellard7854b052003-03-29 17:22:23 +00001265 while (cmsg && target_cmsg) {
1266 void *data = CMSG_DATA(cmsg);
1267 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1268
1269 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1270
1271 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001272 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001273 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001274 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001275 break;
1276 }
1277
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001278 if (cmsg->cmsg_level == SOL_SOCKET) {
1279 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1280 } else {
1281 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1282 }
bellard7854b052003-03-29 17:22:23 +00001283 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001284 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001285
Huw Davies52b65492014-04-17 14:02:47 +01001286 switch (cmsg->cmsg_level) {
1287 case SOL_SOCKET:
1288 switch (cmsg->cmsg_type) {
1289 case SCM_RIGHTS:
1290 {
1291 int *fd = (int *)data;
1292 int *target_fd = (int *)target_data;
1293 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001294
Huw Davies52b65492014-04-17 14:02:47 +01001295 for (i = 0; i < numfds; i++)
1296 target_fd[i] = tswap32(fd[i]);
1297 break;
1298 }
1299 case SO_TIMESTAMP:
1300 {
1301 struct timeval *tv = (struct timeval *)data;
1302 struct target_timeval *target_tv =
1303 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001304
Huw Davies52b65492014-04-17 14:02:47 +01001305 if (len != sizeof(struct timeval))
1306 goto unimplemented;
1307
1308 /* copy struct timeval to target */
1309 target_tv->tv_sec = tswapal(tv->tv_sec);
1310 target_tv->tv_usec = tswapal(tv->tv_usec);
1311 break;
1312 }
Huw Davies4bc29752014-04-17 14:02:48 +01001313 case SCM_CREDENTIALS:
1314 {
1315 struct ucred *cred = (struct ucred *)data;
1316 struct target_ucred *target_cred =
1317 (struct target_ucred *)target_data;
1318
1319 __put_user(cred->pid, &target_cred->pid);
1320 __put_user(cred->uid, &target_cred->uid);
1321 __put_user(cred->gid, &target_cred->gid);
1322 break;
1323 }
Huw Davies52b65492014-04-17 14:02:47 +01001324 default:
1325 goto unimplemented;
1326 }
1327 break;
1328
1329 default:
1330 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001331 gemu_log("Unsupported ancillary data: %d/%d\n",
1332 cmsg->cmsg_level, cmsg->cmsg_type);
1333 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001334 }
1335
1336 cmsg = CMSG_NXTHDR(msgh, cmsg);
1337 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1338 }
bellard5a4a8982007-11-11 17:39:18 +00001339 unlock_user(target_cmsg, target_cmsg_addr, space);
1340 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001341 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001342 return 0;
bellard7854b052003-03-29 17:22:23 +00001343}
1344
ths0da46a62007-10-20 20:23:07 +00001345/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001346static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001347 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001348{
blueswir1992f48a2007-10-14 16:27:31 +00001349 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001350 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001351 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001352 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001353
bellard8853f862004-02-22 14:57:26 +00001354 switch(level) {
1355 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001356 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001357 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001358 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001359
bellard2f619692007-11-16 10:46:05 +00001360 if (get_user_u32(val, optval_addr))
1361 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001362 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1363 break;
1364 case SOL_IP:
1365 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001366 case IP_TOS:
1367 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001368 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001369 case IP_ROUTER_ALERT:
1370 case IP_RECVOPTS:
1371 case IP_RETOPTS:
1372 case IP_PKTINFO:
1373 case IP_MTU_DISCOVER:
1374 case IP_RECVERR:
1375 case IP_RECVTOS:
1376#ifdef IP_FREEBIND
1377 case IP_FREEBIND:
1378#endif
1379 case IP_MULTICAST_TTL:
1380 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001381 val = 0;
1382 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001383 if (get_user_u32(val, optval_addr))
1384 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001385 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001386 if (get_user_u8(val, optval_addr))
1387 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001388 }
1389 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1390 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001391 case IP_ADD_MEMBERSHIP:
1392 case IP_DROP_MEMBERSHIP:
1393 if (optlen < sizeof (struct target_ip_mreq) ||
1394 optlen > sizeof (struct target_ip_mreqn))
1395 return -TARGET_EINVAL;
1396
1397 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1398 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1399 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1400 break;
1401
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001402 case IP_BLOCK_SOURCE:
1403 case IP_UNBLOCK_SOURCE:
1404 case IP_ADD_SOURCE_MEMBERSHIP:
1405 case IP_DROP_SOURCE_MEMBERSHIP:
1406 if (optlen != sizeof (struct target_ip_mreq_source))
1407 return -TARGET_EINVAL;
1408
1409 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1410 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1411 unlock_user (ip_mreq_source, optval_addr, 0);
1412 break;
1413
bellard8853f862004-02-22 14:57:26 +00001414 default:
1415 goto unimplemented;
1416 }
1417 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001418 case SOL_IPV6:
1419 switch (optname) {
1420 case IPV6_MTU_DISCOVER:
1421 case IPV6_MTU:
1422 case IPV6_V6ONLY:
1423 case IPV6_RECVPKTINFO:
1424 val = 0;
1425 if (optlen < sizeof(uint32_t)) {
1426 return -TARGET_EINVAL;
1427 }
1428 if (get_user_u32(val, optval_addr)) {
1429 return -TARGET_EFAULT;
1430 }
1431 ret = get_errno(setsockopt(sockfd, level, optname,
1432 &val, sizeof(val)));
1433 break;
1434 default:
1435 goto unimplemented;
1436 }
1437 break;
Jing Huang920394d2012-07-24 13:59:23 +00001438 case SOL_RAW:
1439 switch (optname) {
1440 case ICMP_FILTER:
1441 /* struct icmp_filter takes an u32 value */
1442 if (optlen < sizeof(uint32_t)) {
1443 return -TARGET_EINVAL;
1444 }
1445
1446 if (get_user_u32(val, optval_addr)) {
1447 return -TARGET_EFAULT;
1448 }
1449 ret = get_errno(setsockopt(sockfd, level, optname,
1450 &val, sizeof(val)));
1451 break;
1452
1453 default:
1454 goto unimplemented;
1455 }
1456 break;
bellard3532fa72006-06-24 15:06:03 +00001457 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001458 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001459 case TARGET_SO_RCVTIMEO:
1460 {
1461 struct timeval tv;
1462
1463 optname = SO_RCVTIMEO;
1464
1465set_timeout:
1466 if (optlen != sizeof(struct target_timeval)) {
1467 return -TARGET_EINVAL;
1468 }
1469
1470 if (copy_from_user_timeval(&tv, optval_addr)) {
1471 return -TARGET_EFAULT;
1472 }
1473
1474 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1475 &tv, sizeof(tv)));
1476 return ret;
1477 }
1478 case TARGET_SO_SNDTIMEO:
1479 optname = SO_SNDTIMEO;
1480 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001481 case TARGET_SO_ATTACH_FILTER:
1482 {
1483 struct target_sock_fprog *tfprog;
1484 struct target_sock_filter *tfilter;
1485 struct sock_fprog fprog;
1486 struct sock_filter *filter;
1487 int i;
1488
1489 if (optlen != sizeof(*tfprog)) {
1490 return -TARGET_EINVAL;
1491 }
1492 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1493 return -TARGET_EFAULT;
1494 }
1495 if (!lock_user_struct(VERIFY_READ, tfilter,
1496 tswapal(tfprog->filter), 0)) {
1497 unlock_user_struct(tfprog, optval_addr, 1);
1498 return -TARGET_EFAULT;
1499 }
1500
1501 fprog.len = tswap16(tfprog->len);
1502 filter = malloc(fprog.len * sizeof(*filter));
1503 if (filter == NULL) {
1504 unlock_user_struct(tfilter, tfprog->filter, 1);
1505 unlock_user_struct(tfprog, optval_addr, 1);
1506 return -TARGET_ENOMEM;
1507 }
1508 for (i = 0; i < fprog.len; i++) {
1509 filter[i].code = tswap16(tfilter[i].code);
1510 filter[i].jt = tfilter[i].jt;
1511 filter[i].jf = tfilter[i].jf;
1512 filter[i].k = tswap32(tfilter[i].k);
1513 }
1514 fprog.filter = filter;
1515
1516 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1517 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1518 free(filter);
1519
1520 unlock_user_struct(tfilter, tfprog->filter, 1);
1521 unlock_user_struct(tfprog, optval_addr, 1);
1522 return ret;
1523 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001524 case TARGET_SO_BINDTODEVICE:
1525 {
1526 char *dev_ifname, *addr_ifname;
1527
1528 if (optlen > IFNAMSIZ - 1) {
1529 optlen = IFNAMSIZ - 1;
1530 }
1531 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1532 if (!dev_ifname) {
1533 return -TARGET_EFAULT;
1534 }
1535 optname = SO_BINDTODEVICE;
1536 addr_ifname = alloca(IFNAMSIZ);
1537 memcpy(addr_ifname, dev_ifname, optlen);
1538 addr_ifname[optlen] = 0;
1539 ret = get_errno(setsockopt(sockfd, level, optname, addr_ifname, optlen));
1540 unlock_user (dev_ifname, optval_addr, 0);
1541 return ret;
1542 }
bellard8853f862004-02-22 14:57:26 +00001543 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001544 case TARGET_SO_DEBUG:
1545 optname = SO_DEBUG;
1546 break;
1547 case TARGET_SO_REUSEADDR:
1548 optname = SO_REUSEADDR;
1549 break;
1550 case TARGET_SO_TYPE:
1551 optname = SO_TYPE;
1552 break;
1553 case TARGET_SO_ERROR:
1554 optname = SO_ERROR;
1555 break;
1556 case TARGET_SO_DONTROUTE:
1557 optname = SO_DONTROUTE;
1558 break;
1559 case TARGET_SO_BROADCAST:
1560 optname = SO_BROADCAST;
1561 break;
1562 case TARGET_SO_SNDBUF:
1563 optname = SO_SNDBUF;
1564 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001565 case TARGET_SO_SNDBUFFORCE:
1566 optname = SO_SNDBUFFORCE;
1567 break;
bellard3532fa72006-06-24 15:06:03 +00001568 case TARGET_SO_RCVBUF:
1569 optname = SO_RCVBUF;
1570 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001571 case TARGET_SO_RCVBUFFORCE:
1572 optname = SO_RCVBUFFORCE;
1573 break;
bellard3532fa72006-06-24 15:06:03 +00001574 case TARGET_SO_KEEPALIVE:
1575 optname = SO_KEEPALIVE;
1576 break;
1577 case TARGET_SO_OOBINLINE:
1578 optname = SO_OOBINLINE;
1579 break;
1580 case TARGET_SO_NO_CHECK:
1581 optname = SO_NO_CHECK;
1582 break;
1583 case TARGET_SO_PRIORITY:
1584 optname = SO_PRIORITY;
1585 break;
bellard5e83e8e2005-03-01 22:32:06 +00001586#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001587 case TARGET_SO_BSDCOMPAT:
1588 optname = SO_BSDCOMPAT;
1589 break;
bellard5e83e8e2005-03-01 22:32:06 +00001590#endif
bellard3532fa72006-06-24 15:06:03 +00001591 case TARGET_SO_PASSCRED:
1592 optname = SO_PASSCRED;
1593 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001594 case TARGET_SO_PASSSEC:
1595 optname = SO_PASSSEC;
1596 break;
bellard3532fa72006-06-24 15:06:03 +00001597 case TARGET_SO_TIMESTAMP:
1598 optname = SO_TIMESTAMP;
1599 break;
1600 case TARGET_SO_RCVLOWAT:
1601 optname = SO_RCVLOWAT;
1602 break;
bellard8853f862004-02-22 14:57:26 +00001603 break;
1604 default:
1605 goto unimplemented;
1606 }
bellard3532fa72006-06-24 15:06:03 +00001607 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001608 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001609
bellard2f619692007-11-16 10:46:05 +00001610 if (get_user_u32(val, optval_addr))
1611 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001612 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001613 break;
bellard7854b052003-03-29 17:22:23 +00001614 default:
bellard8853f862004-02-22 14:57:26 +00001615 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001616 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001617 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001618 }
bellard8853f862004-02-22 14:57:26 +00001619 return ret;
bellard7854b052003-03-29 17:22:23 +00001620}
1621
ths0da46a62007-10-20 20:23:07 +00001622/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001623static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001624 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001625{
blueswir1992f48a2007-10-14 16:27:31 +00001626 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001627 int len, val;
1628 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001629
1630 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001631 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001632 level = SOL_SOCKET;
1633 switch (optname) {
1634 /* These don't just return a single integer */
1635 case TARGET_SO_LINGER:
1636 case TARGET_SO_RCVTIMEO:
1637 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001638 case TARGET_SO_PEERNAME:
1639 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001640 case TARGET_SO_PEERCRED: {
1641 struct ucred cr;
1642 socklen_t crlen;
1643 struct target_ucred *tcr;
1644
1645 if (get_user_u32(len, optlen)) {
1646 return -TARGET_EFAULT;
1647 }
1648 if (len < 0) {
1649 return -TARGET_EINVAL;
1650 }
1651
1652 crlen = sizeof(cr);
1653 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1654 &cr, &crlen));
1655 if (ret < 0) {
1656 return ret;
1657 }
1658 if (len > crlen) {
1659 len = crlen;
1660 }
1661 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1662 return -TARGET_EFAULT;
1663 }
1664 __put_user(cr.pid, &tcr->pid);
1665 __put_user(cr.uid, &tcr->uid);
1666 __put_user(cr.gid, &tcr->gid);
1667 unlock_user_struct(tcr, optval_addr, 1);
1668 if (put_user_u32(len, optlen)) {
1669 return -TARGET_EFAULT;
1670 }
1671 break;
1672 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001673 /* Options with 'int' argument. */
1674 case TARGET_SO_DEBUG:
1675 optname = SO_DEBUG;
1676 goto int_case;
1677 case TARGET_SO_REUSEADDR:
1678 optname = SO_REUSEADDR;
1679 goto int_case;
1680 case TARGET_SO_TYPE:
1681 optname = SO_TYPE;
1682 goto int_case;
1683 case TARGET_SO_ERROR:
1684 optname = SO_ERROR;
1685 goto int_case;
1686 case TARGET_SO_DONTROUTE:
1687 optname = SO_DONTROUTE;
1688 goto int_case;
1689 case TARGET_SO_BROADCAST:
1690 optname = SO_BROADCAST;
1691 goto int_case;
1692 case TARGET_SO_SNDBUF:
1693 optname = SO_SNDBUF;
1694 goto int_case;
1695 case TARGET_SO_RCVBUF:
1696 optname = SO_RCVBUF;
1697 goto int_case;
1698 case TARGET_SO_KEEPALIVE:
1699 optname = SO_KEEPALIVE;
1700 goto int_case;
1701 case TARGET_SO_OOBINLINE:
1702 optname = SO_OOBINLINE;
1703 goto int_case;
1704 case TARGET_SO_NO_CHECK:
1705 optname = SO_NO_CHECK;
1706 goto int_case;
1707 case TARGET_SO_PRIORITY:
1708 optname = SO_PRIORITY;
1709 goto int_case;
1710#ifdef SO_BSDCOMPAT
1711 case TARGET_SO_BSDCOMPAT:
1712 optname = SO_BSDCOMPAT;
1713 goto int_case;
1714#endif
1715 case TARGET_SO_PASSCRED:
1716 optname = SO_PASSCRED;
1717 goto int_case;
1718 case TARGET_SO_TIMESTAMP:
1719 optname = SO_TIMESTAMP;
1720 goto int_case;
1721 case TARGET_SO_RCVLOWAT:
1722 optname = SO_RCVLOWAT;
1723 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001724 case TARGET_SO_ACCEPTCONN:
1725 optname = SO_ACCEPTCONN;
1726 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001727 default:
bellard2efbe912005-07-23 15:10:20 +00001728 goto int_case;
1729 }
1730 break;
1731 case SOL_TCP:
1732 /* TCP options all take an 'int' value. */
1733 int_case:
bellard2f619692007-11-16 10:46:05 +00001734 if (get_user_u32(len, optlen))
1735 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001736 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001737 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001738 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001739 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1740 if (ret < 0)
1741 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001742 if (optname == SO_TYPE) {
1743 val = host_to_target_sock_type(val);
1744 }
bellard2efbe912005-07-23 15:10:20 +00001745 if (len > lv)
1746 len = lv;
bellard2f619692007-11-16 10:46:05 +00001747 if (len == 4) {
1748 if (put_user_u32(val, optval_addr))
1749 return -TARGET_EFAULT;
1750 } else {
1751 if (put_user_u8(val, optval_addr))
1752 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001753 }
bellard2f619692007-11-16 10:46:05 +00001754 if (put_user_u32(len, optlen))
1755 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001756 break;
1757 case SOL_IP:
1758 switch(optname) {
1759 case IP_TOS:
1760 case IP_TTL:
1761 case IP_HDRINCL:
1762 case IP_ROUTER_ALERT:
1763 case IP_RECVOPTS:
1764 case IP_RETOPTS:
1765 case IP_PKTINFO:
1766 case IP_MTU_DISCOVER:
1767 case IP_RECVERR:
1768 case IP_RECVTOS:
1769#ifdef IP_FREEBIND
1770 case IP_FREEBIND:
1771#endif
1772 case IP_MULTICAST_TTL:
1773 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001774 if (get_user_u32(len, optlen))
1775 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001776 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001777 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001778 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001779 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1780 if (ret < 0)
1781 return ret;
bellard2efbe912005-07-23 15:10:20 +00001782 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001783 len = 1;
bellard2f619692007-11-16 10:46:05 +00001784 if (put_user_u32(len, optlen)
1785 || put_user_u8(val, optval_addr))
1786 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001787 } else {
bellard2efbe912005-07-23 15:10:20 +00001788 if (len > sizeof(int))
1789 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001790 if (put_user_u32(len, optlen)
1791 || put_user_u32(val, optval_addr))
1792 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001793 }
bellard8853f862004-02-22 14:57:26 +00001794 break;
bellard2efbe912005-07-23 15:10:20 +00001795 default:
thsc02f4992007-12-18 02:39:59 +00001796 ret = -TARGET_ENOPROTOOPT;
1797 break;
bellard8853f862004-02-22 14:57:26 +00001798 }
1799 break;
1800 default:
1801 unimplemented:
1802 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1803 level, optname);
thsc02f4992007-12-18 02:39:59 +00001804 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001805 break;
1806 }
1807 return ret;
bellard7854b052003-03-29 17:22:23 +00001808}
1809
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001810static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1811 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001812{
1813 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001814 struct iovec *vec;
1815 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001816 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001817 int err = 0;
Tom Musta29560a62014-08-12 13:53:43 -05001818 bool bad_address = false;
pbrook53a59602006-03-25 19:31:22 +00001819
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001820 if (count == 0) {
1821 errno = 0;
1822 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001823 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001824 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001825 errno = EINVAL;
1826 return NULL;
1827 }
1828
1829 vec = calloc(count, sizeof(struct iovec));
1830 if (vec == NULL) {
1831 errno = ENOMEM;
1832 return NULL;
1833 }
1834
1835 target_vec = lock_user(VERIFY_READ, target_addr,
1836 count * sizeof(struct target_iovec), 1);
1837 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001838 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001839 goto fail2;
1840 }
1841
1842 /* ??? If host page size > target page size, this will result in a
1843 value larger than what we can actually support. */
1844 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1845 total_len = 0;
1846
1847 for (i = 0; i < count; i++) {
1848 abi_ulong base = tswapal(target_vec[i].iov_base);
1849 abi_long len = tswapal(target_vec[i].iov_len);
1850
1851 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001852 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001853 goto fail;
1854 } else if (len == 0) {
1855 /* Zero length pointer is ignored. */
1856 vec[i].iov_base = 0;
1857 } else {
1858 vec[i].iov_base = lock_user(type, base, len, copy);
Tom Musta29560a62014-08-12 13:53:43 -05001859 /* If the first buffer pointer is bad, this is a fault. But
1860 * subsequent bad buffers will result in a partial write; this
1861 * is realized by filling the vector with null pointers and
1862 * zero lengths. */
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001863 if (!vec[i].iov_base) {
Tom Musta29560a62014-08-12 13:53:43 -05001864 if (i == 0) {
1865 err = EFAULT;
1866 goto fail;
1867 } else {
1868 bad_address = true;
1869 }
1870 }
1871 if (bad_address) {
1872 len = 0;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001873 }
1874 if (len > max_len - total_len) {
1875 len = max_len - total_len;
1876 }
1877 }
1878 vec[i].iov_len = len;
1879 total_len += len;
1880 }
1881
1882 unlock_user(target_vec, target_addr, 0);
1883 return vec;
1884
1885 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001886 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001887 fail2:
1888 free(vec);
1889 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001890 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001891}
1892
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001893static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1894 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001895{
1896 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001897 int i;
1898
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001899 target_vec = lock_user(VERIFY_READ, target_addr,
1900 count * sizeof(struct target_iovec), 1);
1901 if (target_vec) {
1902 for (i = 0; i < count; i++) {
1903 abi_ulong base = tswapal(target_vec[i].iov_base);
1904 abi_long len = tswapal(target_vec[i].iov_base);
1905 if (len < 0) {
1906 break;
1907 }
balrogd732dcb2008-10-28 10:21:03 +00001908 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1909 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001910 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001911 }
bellard579a97f2007-11-11 14:26:47 +00001912
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001913 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001914}
1915
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001916static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001917{
1918 int host_type = 0;
1919 int target_type = *type;
1920
1921 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1922 case TARGET_SOCK_DGRAM:
1923 host_type = SOCK_DGRAM;
1924 break;
1925 case TARGET_SOCK_STREAM:
1926 host_type = SOCK_STREAM;
1927 break;
1928 default:
1929 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1930 break;
1931 }
1932 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001933#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001934 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001935#else
1936 return -TARGET_EINVAL;
1937#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001938 }
1939 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001940#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001941 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001942#elif !defined(O_NONBLOCK)
1943 return -TARGET_EINVAL;
1944#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001945 }
1946 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001947 return 0;
1948}
1949
1950/* Try to emulate socket type flags after socket creation. */
1951static int sock_flags_fixup(int fd, int target_type)
1952{
1953#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1954 if (target_type & TARGET_SOCK_NONBLOCK) {
1955 int flags = fcntl(fd, F_GETFL);
1956 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1957 close(fd);
1958 return -TARGET_EINVAL;
1959 }
1960 }
1961#endif
1962 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001963}
1964
ths0da46a62007-10-20 20:23:07 +00001965/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001966static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001967{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001968 int target_type = type;
1969 int ret;
1970
1971 ret = target_to_host_sock_type(&type);
1972 if (ret) {
1973 return ret;
1974 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001975
balrog12bc92a2007-10-30 21:06:14 +00001976 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07001977 return -TARGET_EAFNOSUPPORT;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001978 ret = get_errno(socket(domain, type, protocol));
1979 if (ret >= 0) {
1980 ret = sock_flags_fixup(ret, target_type);
1981 }
1982 return ret;
bellard3532fa72006-06-24 15:06:03 +00001983}
1984
ths0da46a62007-10-20 20:23:07 +00001985/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001986static abi_long do_bind(int sockfd, abi_ulong target_addr,
1987 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001988{
aurel328f7aeaf2009-01-30 19:47:57 +00001989 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001990 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001991
Blue Swirl38724252010-09-18 05:53:14 +00001992 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001993 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001994 }
aurel328f7aeaf2009-01-30 19:47:57 +00001995
aurel32607175e2009-04-15 16:11:59 +00001996 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001997
Arnaud Patard917507b2009-06-19 10:44:45 +03001998 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1999 if (ret)
2000 return ret;
2001
bellard3532fa72006-06-24 15:06:03 +00002002 return get_errno(bind(sockfd, addr, addrlen));
2003}
2004
ths0da46a62007-10-20 20:23:07 +00002005/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002006static abi_long do_connect(int sockfd, abi_ulong target_addr,
2007 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00002008{
aurel328f7aeaf2009-01-30 19:47:57 +00002009 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03002010 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00002011
Blue Swirl38724252010-09-18 05:53:14 +00002012 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002013 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002014 }
aurel328f7aeaf2009-01-30 19:47:57 +00002015
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002016 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00002017
Arnaud Patard917507b2009-06-19 10:44:45 +03002018 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2019 if (ret)
2020 return ret;
2021
bellard3532fa72006-06-24 15:06:03 +00002022 return get_errno(connect(sockfd, addr, addrlen));
2023}
2024
Alexander Graff19e00d2014-03-02 19:36:42 +00002025/* do_sendrecvmsg_locked() Must return target values and target errnos. */
2026static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
2027 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00002028{
balrog6de645c2008-10-28 10:26:29 +00002029 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002030 struct msghdr msg;
2031 int count;
2032 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002033 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002034
bellard3532fa72006-06-24 15:06:03 +00002035 if (msgp->msg_name) {
2036 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002037 msg.msg_name = alloca(msg.msg_namelen+1);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002038 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00002039 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002040 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002041 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002042 }
bellard3532fa72006-06-24 15:06:03 +00002043 } else {
2044 msg.msg_name = NULL;
2045 msg.msg_namelen = 0;
2046 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002047 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002048 msg.msg_control = alloca(msg.msg_controllen);
2049 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002050
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002051 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002052 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002053 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2054 target_vec, count, send);
2055 if (vec == NULL) {
2056 ret = -host_to_target_errno(errno);
2057 goto out2;
2058 }
bellard3532fa72006-06-24 15:06:03 +00002059 msg.msg_iovlen = count;
2060 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002061
bellard3532fa72006-06-24 15:06:03 +00002062 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002063 ret = target_to_host_cmsg(&msg, msgp);
2064 if (ret == 0)
2065 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002066 } else {
2067 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002068 if (!is_error(ret)) {
2069 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002070 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002071 if (!is_error(ret)) {
2072 msgp->msg_namelen = tswap32(msg.msg_namelen);
2073 if (msg.msg_name != NULL) {
2074 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2075 msg.msg_name, msg.msg_namelen);
2076 if (ret) {
2077 goto out;
2078 }
2079 }
2080
balrog6de645c2008-10-28 10:26:29 +00002081 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002082 }
balrog6de645c2008-10-28 10:26:29 +00002083 }
bellard3532fa72006-06-24 15:06:03 +00002084 }
Jing Huangca619062012-07-24 13:58:02 +00002085
2086out:
bellard3532fa72006-06-24 15:06:03 +00002087 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002088out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002089 return ret;
2090}
2091
2092static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2093 int flags, int send)
2094{
2095 abi_long ret;
2096 struct target_msghdr *msgp;
2097
2098 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2099 msgp,
2100 target_msg,
2101 send ? 1 : 0)) {
2102 return -TARGET_EFAULT;
2103 }
2104 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002105 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002106 return ret;
2107}
2108
Alexander Graff19e00d2014-03-02 19:36:42 +00002109#ifdef TARGET_NR_sendmmsg
2110/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2111 * so it might not have this *mmsg-specific flag either.
2112 */
2113#ifndef MSG_WAITFORONE
2114#define MSG_WAITFORONE 0x10000
2115#endif
2116
2117static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2118 unsigned int vlen, unsigned int flags,
2119 int send)
2120{
2121 struct target_mmsghdr *mmsgp;
2122 abi_long ret = 0;
2123 int i;
2124
2125 if (vlen > UIO_MAXIOV) {
2126 vlen = UIO_MAXIOV;
2127 }
2128
2129 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2130 if (!mmsgp) {
2131 return -TARGET_EFAULT;
2132 }
2133
2134 for (i = 0; i < vlen; i++) {
2135 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2136 if (is_error(ret)) {
2137 break;
2138 }
2139 mmsgp[i].msg_len = tswap32(ret);
2140 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2141 if (flags & MSG_WAITFORONE) {
2142 flags |= MSG_DONTWAIT;
2143 }
2144 }
2145
2146 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2147
2148 /* Return number of datagrams sent if we sent any at all;
2149 * otherwise return the error.
2150 */
2151 if (i) {
2152 return i;
2153 }
2154 return ret;
2155}
2156#endif
2157
Peter Maydella94b4982013-02-08 04:35:04 +00002158/* If we don't have a system accept4() then just call accept.
2159 * The callsites to do_accept4() will ensure that they don't
2160 * pass a non-zero flags argument in this config.
2161 */
2162#ifndef CONFIG_ACCEPT4
2163static inline int accept4(int sockfd, struct sockaddr *addr,
2164 socklen_t *addrlen, int flags)
2165{
2166 assert(flags == 0);
2167 return accept(sockfd, addr, addrlen);
2168}
2169#endif
2170
2171/* do_accept4() Must return target values and target errnos. */
2172static abi_long do_accept4(int fd, abi_ulong target_addr,
2173 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002174{
bellard2f619692007-11-16 10:46:05 +00002175 socklen_t addrlen;
2176 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002177 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002178 int host_flags;
2179
2180 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002181
Peter Maydella94b4982013-02-08 04:35:04 +00002182 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002183 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002184 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002185
2186 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002187 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002188 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002189
Blue Swirl38724252010-09-18 05:53:14 +00002190 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002191 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002192 }
aurel328f7aeaf2009-01-30 19:47:57 +00002193
Arnaud Patard917507b2009-06-19 10:44:45 +03002194 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2195 return -TARGET_EINVAL;
2196
bellard2f619692007-11-16 10:46:05 +00002197 addr = alloca(addrlen);
2198
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002199 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002200 if (!is_error(ret)) {
2201 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002202 if (put_user_u32(addrlen, target_addrlen_addr))
2203 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002204 }
2205 return ret;
2206}
2207
ths0da46a62007-10-20 20:23:07 +00002208/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002209static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002210 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002211{
bellard2f619692007-11-16 10:46:05 +00002212 socklen_t addrlen;
2213 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002214 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002215
bellard2f619692007-11-16 10:46:05 +00002216 if (get_user_u32(addrlen, target_addrlen_addr))
2217 return -TARGET_EFAULT;
2218
Blue Swirl38724252010-09-18 05:53:14 +00002219 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002220 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002221 }
aurel328f7aeaf2009-01-30 19:47:57 +00002222
Arnaud Patard917507b2009-06-19 10:44:45 +03002223 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2224 return -TARGET_EFAULT;
2225
bellard2f619692007-11-16 10:46:05 +00002226 addr = alloca(addrlen);
2227
pbrook1be9e1d2006-11-19 15:26:04 +00002228 ret = get_errno(getpeername(fd, addr, &addrlen));
2229 if (!is_error(ret)) {
2230 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002231 if (put_user_u32(addrlen, target_addrlen_addr))
2232 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002233 }
2234 return ret;
2235}
2236
ths0da46a62007-10-20 20:23:07 +00002237/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002238static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002239 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002240{
bellard2f619692007-11-16 10:46:05 +00002241 socklen_t addrlen;
2242 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002243 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002244
bellard2f619692007-11-16 10:46:05 +00002245 if (get_user_u32(addrlen, target_addrlen_addr))
2246 return -TARGET_EFAULT;
2247
Blue Swirl38724252010-09-18 05:53:14 +00002248 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002249 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002250 }
aurel328f7aeaf2009-01-30 19:47:57 +00002251
Arnaud Patard917507b2009-06-19 10:44:45 +03002252 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2253 return -TARGET_EFAULT;
2254
bellard2f619692007-11-16 10:46:05 +00002255 addr = alloca(addrlen);
2256
pbrook1be9e1d2006-11-19 15:26:04 +00002257 ret = get_errno(getsockname(fd, addr, &addrlen));
2258 if (!is_error(ret)) {
2259 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002260 if (put_user_u32(addrlen, target_addrlen_addr))
2261 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002262 }
2263 return ret;
2264}
2265
ths0da46a62007-10-20 20:23:07 +00002266/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002267static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002268 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002269{
2270 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002271 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002272
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002273 target_to_host_sock_type(&type);
2274
pbrook1be9e1d2006-11-19 15:26:04 +00002275 ret = get_errno(socketpair(domain, type, protocol, tab));
2276 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002277 if (put_user_s32(tab[0], target_tab_addr)
2278 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2279 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002280 }
2281 return ret;
2282}
2283
ths0da46a62007-10-20 20:23:07 +00002284/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002285static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2286 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002287{
2288 void *addr;
2289 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002290 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002291
Blue Swirl38724252010-09-18 05:53:14 +00002292 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002293 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002294 }
aurel328f7aeaf2009-01-30 19:47:57 +00002295
bellard579a97f2007-11-11 14:26:47 +00002296 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2297 if (!host_msg)
2298 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002299 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002300 addr = alloca(addrlen+1);
Arnaud Patard917507b2009-06-19 10:44:45 +03002301 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2302 if (ret) {
2303 unlock_user(host_msg, msg, 0);
2304 return ret;
2305 }
pbrook1be9e1d2006-11-19 15:26:04 +00002306 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2307 } else {
2308 ret = get_errno(send(fd, host_msg, len, flags));
2309 }
2310 unlock_user(host_msg, msg, 0);
2311 return ret;
2312}
2313
ths0da46a62007-10-20 20:23:07 +00002314/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002315static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2316 abi_ulong target_addr,
2317 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002318{
2319 socklen_t addrlen;
2320 void *addr;
2321 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002322 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002323
bellard579a97f2007-11-11 14:26:47 +00002324 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2325 if (!host_msg)
2326 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002327 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002328 if (get_user_u32(addrlen, target_addrlen)) {
2329 ret = -TARGET_EFAULT;
2330 goto fail;
2331 }
Blue Swirl38724252010-09-18 05:53:14 +00002332 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002333 ret = -TARGET_EINVAL;
2334 goto fail;
2335 }
pbrook1be9e1d2006-11-19 15:26:04 +00002336 addr = alloca(addrlen);
2337 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2338 } else {
2339 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002340 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002341 }
2342 if (!is_error(ret)) {
2343 if (target_addr) {
2344 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002345 if (put_user_u32(addrlen, target_addrlen)) {
2346 ret = -TARGET_EFAULT;
2347 goto fail;
2348 }
pbrook1be9e1d2006-11-19 15:26:04 +00002349 }
2350 unlock_user(host_msg, msg, len);
2351 } else {
bellard2f619692007-11-16 10:46:05 +00002352fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002353 unlock_user(host_msg, msg, 0);
2354 }
2355 return ret;
2356}
2357
j_mayer32407102007-09-26 23:01:49 +00002358#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002359/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002360static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002361{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002362 static const unsigned ac[] = { /* number of arguments per call */
2363 [SOCKOP_socket] = 3, /* domain, type, protocol */
2364 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2365 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2366 [SOCKOP_listen] = 2, /* sockfd, backlog */
2367 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2368 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2369 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2370 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2371 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2372 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2373 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2374 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2375 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2376 [SOCKOP_shutdown] = 2, /* sockfd, how */
2377 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2378 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2379 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2380 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2381 };
2382 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002383
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002384 /* first, collect the arguments in a[] according to ac[] */
2385 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2386 unsigned i;
2387 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2388 for (i = 0; i < ac[num]; ++i) {
2389 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002390 return -TARGET_EFAULT;
2391 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002392 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002393 }
bellard2f619692007-11-16 10:46:05 +00002394
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002395 /* now when we have the args, actually handle the call */
2396 switch (num) {
2397 case SOCKOP_socket: /* domain, type, protocol */
2398 return do_socket(a[0], a[1], a[2]);
2399 case SOCKOP_bind: /* sockfd, addr, addrlen */
2400 return do_bind(a[0], a[1], a[2]);
2401 case SOCKOP_connect: /* sockfd, addr, addrlen */
2402 return do_connect(a[0], a[1], a[2]);
2403 case SOCKOP_listen: /* sockfd, backlog */
2404 return get_errno(listen(a[0], a[1]));
2405 case SOCKOP_accept: /* sockfd, addr, addrlen */
2406 return do_accept4(a[0], a[1], a[2], 0);
2407 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2408 return do_accept4(a[0], a[1], a[2], a[3]);
2409 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2410 return do_getsockname(a[0], a[1], a[2]);
2411 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2412 return do_getpeername(a[0], a[1], a[2]);
2413 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2414 return do_socketpair(a[0], a[1], a[2], a[3]);
2415 case SOCKOP_send: /* sockfd, msg, len, flags */
2416 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2417 case SOCKOP_recv: /* sockfd, msg, len, flags */
2418 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2419 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2420 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2421 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2422 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2423 case SOCKOP_shutdown: /* sockfd, how */
2424 return get_errno(shutdown(a[0], a[1]));
2425 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2426 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2427 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2428 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2429 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2430 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2431 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2432 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002433 default:
2434 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002435 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002436 }
bellard31e31b82003-02-18 22:55:36 +00002437}
j_mayer32407102007-09-26 23:01:49 +00002438#endif
bellard31e31b82003-02-18 22:55:36 +00002439
bellard8853f862004-02-22 14:57:26 +00002440#define N_SHM_REGIONS 32
2441
2442static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002443 abi_ulong start;
2444 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002445} shm_regions[N_SHM_REGIONS];
2446
ths3eb6b042007-06-03 14:26:27 +00002447struct target_semid_ds
2448{
2449 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002450 abi_ulong sem_otime;
Tom Musta03527342014-08-12 13:53:32 -05002451#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002452 abi_ulong __unused1;
Tom Musta03527342014-08-12 13:53:32 -05002453#endif
blueswir1992f48a2007-10-14 16:27:31 +00002454 abi_ulong sem_ctime;
Tom Musta03527342014-08-12 13:53:32 -05002455#if !defined(TARGET_PPC64)
blueswir1992f48a2007-10-14 16:27:31 +00002456 abi_ulong __unused2;
Tom Musta03527342014-08-12 13:53:32 -05002457#endif
blueswir1992f48a2007-10-14 16:27:31 +00002458 abi_ulong sem_nsems;
2459 abi_ulong __unused3;
2460 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002461};
2462
bellard579a97f2007-11-11 14:26:47 +00002463static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2464 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002465{
2466 struct target_ipc_perm *target_ip;
2467 struct target_semid_ds *target_sd;
2468
bellard579a97f2007-11-11 14:26:47 +00002469 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2470 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002471 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002472 host_ip->__key = tswap32(target_ip->__key);
2473 host_ip->uid = tswap32(target_ip->uid);
2474 host_ip->gid = tswap32(target_ip->gid);
2475 host_ip->cuid = tswap32(target_ip->cuid);
2476 host_ip->cgid = tswap32(target_ip->cgid);
2477#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2478 host_ip->mode = tswap32(target_ip->mode);
2479#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002480 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002481#endif
2482#if defined(TARGET_PPC)
2483 host_ip->__seq = tswap32(target_ip->__seq);
2484#else
2485 host_ip->__seq = tswap16(target_ip->__seq);
2486#endif
ths3eb6b042007-06-03 14:26:27 +00002487 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002488 return 0;
ths3eb6b042007-06-03 14:26:27 +00002489}
2490
bellard579a97f2007-11-11 14:26:47 +00002491static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2492 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002493{
2494 struct target_ipc_perm *target_ip;
2495 struct target_semid_ds *target_sd;
2496
bellard579a97f2007-11-11 14:26:47 +00002497 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2498 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002499 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002500 target_ip->__key = tswap32(host_ip->__key);
2501 target_ip->uid = tswap32(host_ip->uid);
2502 target_ip->gid = tswap32(host_ip->gid);
2503 target_ip->cuid = tswap32(host_ip->cuid);
2504 target_ip->cgid = tswap32(host_ip->cgid);
2505#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2506 target_ip->mode = tswap32(host_ip->mode);
2507#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002508 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002509#endif
2510#if defined(TARGET_PPC)
2511 target_ip->__seq = tswap32(host_ip->__seq);
2512#else
2513 target_ip->__seq = tswap16(host_ip->__seq);
2514#endif
ths3eb6b042007-06-03 14:26:27 +00002515 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002516 return 0;
ths3eb6b042007-06-03 14:26:27 +00002517}
2518
bellard579a97f2007-11-11 14:26:47 +00002519static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2520 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002521{
2522 struct target_semid_ds *target_sd;
2523
bellard579a97f2007-11-11 14:26:47 +00002524 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2525 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002526 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2527 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002528 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2529 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2530 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002531 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002532 return 0;
ths3eb6b042007-06-03 14:26:27 +00002533}
2534
bellard579a97f2007-11-11 14:26:47 +00002535static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2536 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002537{
2538 struct target_semid_ds *target_sd;
2539
bellard579a97f2007-11-11 14:26:47 +00002540 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2541 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002542 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002543 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002544 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2545 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2546 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002547 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002548 return 0;
ths3eb6b042007-06-03 14:26:27 +00002549}
2550
aurel32e5289082009-04-18 16:16:12 +00002551struct target_seminfo {
2552 int semmap;
2553 int semmni;
2554 int semmns;
2555 int semmnu;
2556 int semmsl;
2557 int semopm;
2558 int semume;
2559 int semusz;
2560 int semvmx;
2561 int semaem;
2562};
2563
2564static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2565 struct seminfo *host_seminfo)
2566{
2567 struct target_seminfo *target_seminfo;
2568 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2569 return -TARGET_EFAULT;
2570 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2571 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2572 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2573 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2574 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2575 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2576 __put_user(host_seminfo->semume, &target_seminfo->semume);
2577 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2578 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2579 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2580 unlock_user_struct(target_seminfo, target_addr, 1);
2581 return 0;
2582}
2583
thsfa294812007-02-02 22:05:00 +00002584union semun {
2585 int val;
ths3eb6b042007-06-03 14:26:27 +00002586 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002587 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002588 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002589};
2590
ths3eb6b042007-06-03 14:26:27 +00002591union target_semun {
2592 int val;
aurel32e5289082009-04-18 16:16:12 +00002593 abi_ulong buf;
2594 abi_ulong array;
2595 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002596};
2597
aurel32e5289082009-04-18 16:16:12 +00002598static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2599 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002600{
aurel32e5289082009-04-18 16:16:12 +00002601 int nsems;
2602 unsigned short *array;
2603 union semun semun;
2604 struct semid_ds semid_ds;
2605 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002606
aurel32e5289082009-04-18 16:16:12 +00002607 semun.buf = &semid_ds;
2608
2609 ret = semctl(semid, 0, IPC_STAT, semun);
2610 if (ret == -1)
2611 return get_errno(ret);
2612
2613 nsems = semid_ds.sem_nsems;
2614
2615 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002616 if (!*host_array) {
2617 return -TARGET_ENOMEM;
2618 }
aurel32e5289082009-04-18 16:16:12 +00002619 array = lock_user(VERIFY_READ, target_addr,
2620 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002621 if (!array) {
2622 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002623 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002624 }
aurel32e5289082009-04-18 16:16:12 +00002625
2626 for(i=0; i<nsems; i++) {
2627 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002628 }
aurel32e5289082009-04-18 16:16:12 +00002629 unlock_user(array, target_addr, 0);
2630
bellard579a97f2007-11-11 14:26:47 +00002631 return 0;
ths3eb6b042007-06-03 14:26:27 +00002632}
2633
aurel32e5289082009-04-18 16:16:12 +00002634static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2635 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002636{
aurel32e5289082009-04-18 16:16:12 +00002637 int nsems;
2638 unsigned short *array;
2639 union semun semun;
2640 struct semid_ds semid_ds;
2641 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002642
aurel32e5289082009-04-18 16:16:12 +00002643 semun.buf = &semid_ds;
2644
2645 ret = semctl(semid, 0, IPC_STAT, semun);
2646 if (ret == -1)
2647 return get_errno(ret);
2648
2649 nsems = semid_ds.sem_nsems;
2650
2651 array = lock_user(VERIFY_WRITE, target_addr,
2652 nsems*sizeof(unsigned short), 0);
2653 if (!array)
2654 return -TARGET_EFAULT;
2655
2656 for(i=0; i<nsems; i++) {
2657 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002658 }
aurel32e5289082009-04-18 16:16:12 +00002659 free(*host_array);
2660 unlock_user(array, target_addr, 1);
2661
bellard579a97f2007-11-11 14:26:47 +00002662 return 0;
ths3eb6b042007-06-03 14:26:27 +00002663}
2664
aurel32e5289082009-04-18 16:16:12 +00002665static inline abi_long do_semctl(int semid, int semnum, int cmd,
2666 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002667{
2668 union semun arg;
2669 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302670 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002671 struct seminfo seminfo;
2672 abi_long ret = -TARGET_EINVAL;
2673 abi_long err;
2674 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002675
2676 switch( cmd ) {
2677 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002678 case SETVAL:
Tom Musta5464bae2014-08-12 13:53:34 -05002679 /* In 64 bit cross-endian situations, we will erroneously pick up
2680 * the wrong half of the union for the "val" element. To rectify
2681 * this, the entire 8-byte structure is byteswapped, followed by
2682 * a swap of the 4 byte val field. In other cases, the data is
2683 * already in proper host byte order. */
2684 if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
2685 target_su.buf = tswapal(target_su.buf);
2686 arg.val = tswap32(target_su.val);
2687 } else {
2688 arg.val = target_su.val;
2689 }
aurel32e5289082009-04-18 16:16:12 +00002690 ret = get_errno(semctl(semid, semnum, cmd, arg));
ths3eb6b042007-06-03 14:26:27 +00002691 break;
2692 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002693 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002694 err = target_to_host_semarray(semid, &array, target_su.array);
2695 if (err)
2696 return err;
2697 arg.array = array;
2698 ret = get_errno(semctl(semid, semnum, cmd, arg));
2699 err = host_to_target_semarray(semid, target_su.array, &array);
2700 if (err)
2701 return err;
ths3eb6b042007-06-03 14:26:27 +00002702 break;
2703 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002704 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002705 case SEM_STAT:
2706 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2707 if (err)
2708 return err;
2709 arg.buf = &dsarg;
2710 ret = get_errno(semctl(semid, semnum, cmd, arg));
2711 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2712 if (err)
2713 return err;
ths3eb6b042007-06-03 14:26:27 +00002714 break;
aurel32e5289082009-04-18 16:16:12 +00002715 case IPC_INFO:
2716 case SEM_INFO:
2717 arg.__buf = &seminfo;
2718 ret = get_errno(semctl(semid, semnum, cmd, arg));
2719 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2720 if (err)
2721 return err;
2722 break;
2723 case IPC_RMID:
2724 case GETPID:
2725 case GETNCNT:
2726 case GETZCNT:
2727 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2728 break;
ths3eb6b042007-06-03 14:26:27 +00002729 }
2730
2731 return ret;
2732}
2733
aurel32e5289082009-04-18 16:16:12 +00002734struct target_sembuf {
2735 unsigned short sem_num;
2736 short sem_op;
2737 short sem_flg;
2738};
2739
2740static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2741 abi_ulong target_addr,
2742 unsigned nsops)
2743{
2744 struct target_sembuf *target_sembuf;
2745 int i;
2746
2747 target_sembuf = lock_user(VERIFY_READ, target_addr,
2748 nsops*sizeof(struct target_sembuf), 1);
2749 if (!target_sembuf)
2750 return -TARGET_EFAULT;
2751
2752 for(i=0; i<nsops; i++) {
2753 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2754 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2755 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2756 }
2757
2758 unlock_user(target_sembuf, target_addr, 0);
2759
2760 return 0;
2761}
2762
2763static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2764{
2765 struct sembuf sops[nsops];
2766
2767 if (target_to_host_sembuf(sops, ptr, nsops))
2768 return -TARGET_EFAULT;
2769
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002770 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002771}
2772
ths1bc012f2007-06-03 14:27:49 +00002773struct target_msqid_ds
2774{
aurel321c54ff92008-10-13 21:08:44 +00002775 struct target_ipc_perm msg_perm;
2776 abi_ulong msg_stime;
2777#if TARGET_ABI_BITS == 32
2778 abi_ulong __unused1;
2779#endif
2780 abi_ulong msg_rtime;
2781#if TARGET_ABI_BITS == 32
2782 abi_ulong __unused2;
2783#endif
2784 abi_ulong msg_ctime;
2785#if TARGET_ABI_BITS == 32
2786 abi_ulong __unused3;
2787#endif
2788 abi_ulong __msg_cbytes;
2789 abi_ulong msg_qnum;
2790 abi_ulong msg_qbytes;
2791 abi_ulong msg_lspid;
2792 abi_ulong msg_lrpid;
2793 abi_ulong __unused4;
2794 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002795};
2796
bellard579a97f2007-11-11 14:26:47 +00002797static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2798 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002799{
2800 struct target_msqid_ds *target_md;
2801
bellard579a97f2007-11-11 14:26:47 +00002802 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2803 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002804 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2805 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002806 host_md->msg_stime = tswapal(target_md->msg_stime);
2807 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2808 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2809 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2810 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2811 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2812 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2813 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002814 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002815 return 0;
ths1bc012f2007-06-03 14:27:49 +00002816}
2817
bellard579a97f2007-11-11 14:26:47 +00002818static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2819 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002820{
2821 struct target_msqid_ds *target_md;
2822
bellard579a97f2007-11-11 14:26:47 +00002823 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2824 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002825 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2826 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002827 target_md->msg_stime = tswapal(host_md->msg_stime);
2828 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2829 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2830 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2831 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2832 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2833 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2834 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002835 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002836 return 0;
ths1bc012f2007-06-03 14:27:49 +00002837}
2838
aurel321c54ff92008-10-13 21:08:44 +00002839struct target_msginfo {
2840 int msgpool;
2841 int msgmap;
2842 int msgmax;
2843 int msgmnb;
2844 int msgmni;
2845 int msgssz;
2846 int msgtql;
2847 unsigned short int msgseg;
2848};
2849
2850static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2851 struct msginfo *host_msginfo)
2852{
2853 struct target_msginfo *target_msginfo;
2854 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2855 return -TARGET_EFAULT;
2856 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2857 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2858 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2859 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2860 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2861 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2862 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2863 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2864 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002865 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002866}
2867
2868static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002869{
2870 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002871 struct msginfo msginfo;
2872 abi_long ret = -TARGET_EINVAL;
2873
2874 cmd &= 0xff;
2875
2876 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002877 case IPC_STAT:
2878 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002879 case MSG_STAT:
2880 if (target_to_host_msqid_ds(&dsarg,ptr))
2881 return -TARGET_EFAULT;
2882 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2883 if (host_to_target_msqid_ds(ptr,&dsarg))
2884 return -TARGET_EFAULT;
2885 break;
2886 case IPC_RMID:
2887 ret = get_errno(msgctl(msgid, cmd, NULL));
2888 break;
2889 case IPC_INFO:
2890 case MSG_INFO:
2891 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2892 if (host_to_target_msginfo(ptr, &msginfo))
2893 return -TARGET_EFAULT;
2894 break;
ths1bc012f2007-06-03 14:27:49 +00002895 }
aurel321c54ff92008-10-13 21:08:44 +00002896
ths1bc012f2007-06-03 14:27:49 +00002897 return ret;
2898}
2899
2900struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002901 abi_long mtype;
2902 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002903};
2904
blueswir1992f48a2007-10-14 16:27:31 +00002905static inline abi_long do_msgsnd(int msqid, abi_long msgp,
Tom Mustaedcc5f92014-08-12 13:53:37 -05002906 ssize_t msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002907{
2908 struct target_msgbuf *target_mb;
2909 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002910 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002911
Tom Mustaedcc5f92014-08-12 13:53:37 -05002912 if (msgsz < 0) {
2913 return -TARGET_EINVAL;
2914 }
2915
bellard579a97f2007-11-11 14:26:47 +00002916 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2917 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002918 host_mb = malloc(msgsz+sizeof(long));
zhanghailiang29e03fc2014-08-14 15:29:18 +08002919 if (!host_mb) {
2920 unlock_user_struct(target_mb, msgp, 0);
2921 return -TARGET_ENOMEM;
2922 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002923 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002924 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002925 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2926 free(host_mb);
2927 unlock_user_struct(target_mb, msgp, 0);
2928
2929 return ret;
2930}
2931
blueswir1992f48a2007-10-14 16:27:31 +00002932static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002933 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002934 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002935{
2936 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002937 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002938 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002939 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002940
bellard579a97f2007-11-11 14:26:47 +00002941 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2942 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002943
Jim Meyering0d07fe42012-08-22 13:55:53 +02002944 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002945 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002946
bellard579a97f2007-11-11 14:26:47 +00002947 if (ret > 0) {
2948 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2949 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2950 if (!target_mtext) {
2951 ret = -TARGET_EFAULT;
2952 goto end;
2953 }
aurel321c54ff92008-10-13 21:08:44 +00002954 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002955 unlock_user(target_mtext, target_mtext_addr, ret);
2956 }
aurel321c54ff92008-10-13 21:08:44 +00002957
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002958 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002959
bellard579a97f2007-11-11 14:26:47 +00002960end:
2961 if (target_mb)
2962 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002963 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002964 return ret;
2965}
2966
Riku Voipio88a8c982009-04-03 10:42:00 +03002967static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2968 abi_ulong target_addr)
2969{
2970 struct target_shmid_ds *target_sd;
2971
2972 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2973 return -TARGET_EFAULT;
2974 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2975 return -TARGET_EFAULT;
2976 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2977 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2978 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2979 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2980 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2981 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2982 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2983 unlock_user_struct(target_sd, target_addr, 0);
2984 return 0;
2985}
2986
2987static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2988 struct shmid_ds *host_sd)
2989{
2990 struct target_shmid_ds *target_sd;
2991
2992 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2993 return -TARGET_EFAULT;
2994 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2995 return -TARGET_EFAULT;
2996 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2997 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2998 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2999 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
3000 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
3001 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
3002 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
3003 unlock_user_struct(target_sd, target_addr, 1);
3004 return 0;
3005}
3006
3007struct target_shminfo {
3008 abi_ulong shmmax;
3009 abi_ulong shmmin;
3010 abi_ulong shmmni;
3011 abi_ulong shmseg;
3012 abi_ulong shmall;
3013};
3014
3015static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
3016 struct shminfo *host_shminfo)
3017{
3018 struct target_shminfo *target_shminfo;
3019 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
3020 return -TARGET_EFAULT;
3021 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
3022 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
3023 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
3024 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
3025 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
3026 unlock_user_struct(target_shminfo, target_addr, 1);
3027 return 0;
3028}
3029
3030struct target_shm_info {
3031 int used_ids;
3032 abi_ulong shm_tot;
3033 abi_ulong shm_rss;
3034 abi_ulong shm_swp;
3035 abi_ulong swap_attempts;
3036 abi_ulong swap_successes;
3037};
3038
3039static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
3040 struct shm_info *host_shm_info)
3041{
3042 struct target_shm_info *target_shm_info;
3043 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
3044 return -TARGET_EFAULT;
3045 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
3046 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
3047 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
3048 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
3049 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3050 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3051 unlock_user_struct(target_shm_info, target_addr, 1);
3052 return 0;
3053}
3054
3055static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3056{
3057 struct shmid_ds dsarg;
3058 struct shminfo shminfo;
3059 struct shm_info shm_info;
3060 abi_long ret = -TARGET_EINVAL;
3061
3062 cmd &= 0xff;
3063
3064 switch(cmd) {
3065 case IPC_STAT:
3066 case IPC_SET:
3067 case SHM_STAT:
3068 if (target_to_host_shmid_ds(&dsarg, buf))
3069 return -TARGET_EFAULT;
3070 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3071 if (host_to_target_shmid_ds(buf, &dsarg))
3072 return -TARGET_EFAULT;
3073 break;
3074 case IPC_INFO:
3075 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3076 if (host_to_target_shminfo(buf, &shminfo))
3077 return -TARGET_EFAULT;
3078 break;
3079 case SHM_INFO:
3080 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3081 if (host_to_target_shm_info(buf, &shm_info))
3082 return -TARGET_EFAULT;
3083 break;
3084 case IPC_RMID:
3085 case SHM_LOCK:
3086 case SHM_UNLOCK:
3087 ret = get_errno(shmctl(shmid, cmd, NULL));
3088 break;
3089 }
3090
3091 return ret;
3092}
3093
3094static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3095{
3096 abi_long raddr;
3097 void *host_raddr;
3098 struct shmid_ds shm_info;
3099 int i,ret;
3100
3101 /* find out the length of the shared memory segment */
3102 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3103 if (is_error(ret)) {
3104 /* can't get length, bail out */
3105 return ret;
3106 }
3107
3108 mmap_lock();
3109
3110 if (shmaddr)
3111 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3112 else {
3113 abi_ulong mmap_start;
3114
3115 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3116
3117 if (mmap_start == -1) {
3118 errno = ENOMEM;
3119 host_raddr = (void *)-1;
3120 } else
3121 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3122 }
3123
3124 if (host_raddr == (void *)-1) {
3125 mmap_unlock();
3126 return get_errno((long)host_raddr);
3127 }
3128 raddr=h2g((unsigned long)host_raddr);
3129
3130 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3131 PAGE_VALID | PAGE_READ |
3132 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3133
3134 for (i = 0; i < N_SHM_REGIONS; i++) {
3135 if (shm_regions[i].start == 0) {
3136 shm_regions[i].start = raddr;
3137 shm_regions[i].size = shm_info.shm_segsz;
3138 break;
3139 }
3140 }
3141
3142 mmap_unlock();
3143 return raddr;
3144
3145}
3146
3147static inline abi_long do_shmdt(abi_ulong shmaddr)
3148{
3149 int i;
3150
3151 for (i = 0; i < N_SHM_REGIONS; ++i) {
3152 if (shm_regions[i].start == shmaddr) {
3153 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003154 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003155 break;
3156 }
3157 }
3158
3159 return get_errno(shmdt(g2h(shmaddr)));
3160}
3161
aurel321c54ff92008-10-13 21:08:44 +00003162#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003163/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003164/* do_ipc() must return target values and target errnos. */
Tom Musta37ed0952014-08-12 13:53:35 -05003165static abi_long do_ipc(unsigned int call, abi_long first,
3166 abi_long second, abi_long third,
blueswir1992f48a2007-10-14 16:27:31 +00003167 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003168{
3169 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003170 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003171
3172 version = call >> 16;
3173 call &= 0xffff;
3174
3175 switch (call) {
thsfa294812007-02-02 22:05:00 +00003176 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003177 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003178 break;
3179
3180 case IPCOP_semget:
3181 ret = get_errno(semget(first, second, third));
3182 break;
3183
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003184 case IPCOP_semctl: {
3185 /* The semun argument to semctl is passed by value, so dereference the
3186 * ptr argument. */
3187 abi_ulong atptr;
Tom Musta37ed0952014-08-12 13:53:35 -05003188 get_user_ual(atptr, ptr);
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003189 ret = do_semctl(first, second, third,
Tom Musta37ed0952014-08-12 13:53:35 -05003190 (union target_semun) atptr);
thsfa294812007-02-02 22:05:00 +00003191 break;
Tom Musta5d2fa8e2014-08-12 13:53:33 -05003192 }
thsd96372e2007-02-02 22:05:44 +00003193
aurel321c54ff92008-10-13 21:08:44 +00003194 case IPCOP_msgget:
3195 ret = get_errno(msgget(first, second));
3196 break;
thsd96372e2007-02-02 22:05:44 +00003197
aurel321c54ff92008-10-13 21:08:44 +00003198 case IPCOP_msgsnd:
3199 ret = do_msgsnd(first, ptr, second, third);
3200 break;
thsd96372e2007-02-02 22:05:44 +00003201
aurel321c54ff92008-10-13 21:08:44 +00003202 case IPCOP_msgctl:
3203 ret = do_msgctl(first, second, ptr);
3204 break;
thsd96372e2007-02-02 22:05:44 +00003205
aurel321c54ff92008-10-13 21:08:44 +00003206 case IPCOP_msgrcv:
3207 switch (version) {
3208 case 0:
3209 {
3210 struct target_ipc_kludge {
3211 abi_long msgp;
3212 abi_long msgtyp;
3213 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003214
aurel321c54ff92008-10-13 21:08:44 +00003215 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3216 ret = -TARGET_EFAULT;
3217 break;
ths1bc012f2007-06-03 14:27:49 +00003218 }
aurel321c54ff92008-10-13 21:08:44 +00003219
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003220 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003221
3222 unlock_user_struct(tmp, ptr, 0);
3223 break;
3224 }
3225 default:
3226 ret = do_msgrcv(first, ptr, second, fifth, third);
3227 }
3228 break;
thsd96372e2007-02-02 22:05:44 +00003229
bellard8853f862004-02-22 14:57:26 +00003230 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003231 switch (version) {
3232 default:
bellard5a4a8982007-11-11 17:39:18 +00003233 {
3234 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003235 raddr = do_shmat(first, ptr, second);
3236 if (is_error(raddr))
3237 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003238 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003239 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003240 break;
3241 }
3242 case 1:
3243 ret = -TARGET_EINVAL;
3244 break;
bellard5a4a8982007-11-11 17:39:18 +00003245 }
bellard8853f862004-02-22 14:57:26 +00003246 break;
3247 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003248 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003249 break;
3250
3251 case IPCOP_shmget:
3252 /* IPC_* flag values are the same on all linux platforms */
3253 ret = get_errno(shmget(first, second, third));
3254 break;
3255
3256 /* IPC_* and SHM_* command values are the same on all linux platforms */
3257 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003258 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003259 break;
3260 default:
j_mayer32407102007-09-26 23:01:49 +00003261 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003262 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003263 break;
3264 }
3265 return ret;
3266}
j_mayer32407102007-09-26 23:01:49 +00003267#endif
bellard8853f862004-02-22 14:57:26 +00003268
bellard31e31b82003-02-18 22:55:36 +00003269/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003270
Blue Swirl001faf32009-05-13 17:53:17 +00003271#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003272#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3273enum {
3274#include "syscall_types.h"
3275};
3276#undef STRUCT
3277#undef STRUCT_SPECIAL
3278
Blue Swirl001faf32009-05-13 17:53:17 +00003279#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003280#define STRUCT_SPECIAL(name)
3281#include "syscall_types.h"
3282#undef STRUCT
3283#undef STRUCT_SPECIAL
3284
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003285typedef struct IOCTLEntry IOCTLEntry;
3286
3287typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3288 int fd, abi_long cmd, abi_long arg);
3289
3290struct IOCTLEntry {
Ed Swierk9c6bf9c2014-12-16 12:55:31 -08003291 int target_cmd;
bellard2ab83ea2003-06-15 19:56:46 +00003292 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003293 const char *name;
3294 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003295 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003296 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003297};
bellard31e31b82003-02-18 22:55:36 +00003298
3299#define IOC_R 0x0001
3300#define IOC_W 0x0002
3301#define IOC_RW (IOC_R | IOC_W)
3302
3303#define MAX_STRUCT_SIZE 4096
3304
Peter Maydelldace20d2011-01-10 13:11:24 +00003305#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003306/* So fiemap access checks don't overflow on 32 bit systems.
3307 * This is very slightly smaller than the limit imposed by
3308 * the underlying kernel.
3309 */
3310#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3311 / sizeof(struct fiemap_extent))
3312
3313static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3314 int fd, abi_long cmd, abi_long arg)
3315{
3316 /* The parameter for this ioctl is a struct fiemap followed
3317 * by an array of struct fiemap_extent whose size is set
3318 * in fiemap->fm_extent_count. The array is filled in by the
3319 * ioctl.
3320 */
3321 int target_size_in, target_size_out;
3322 struct fiemap *fm;
3323 const argtype *arg_type = ie->arg_type;
3324 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3325 void *argptr, *p;
3326 abi_long ret;
3327 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3328 uint32_t outbufsz;
3329 int free_fm = 0;
3330
3331 assert(arg_type[0] == TYPE_PTR);
3332 assert(ie->access == IOC_RW);
3333 arg_type++;
3334 target_size_in = thunk_type_size(arg_type, 0);
3335 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3336 if (!argptr) {
3337 return -TARGET_EFAULT;
3338 }
3339 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3340 unlock_user(argptr, arg, 0);
3341 fm = (struct fiemap *)buf_temp;
3342 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3343 return -TARGET_EINVAL;
3344 }
3345
3346 outbufsz = sizeof (*fm) +
3347 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3348
3349 if (outbufsz > MAX_STRUCT_SIZE) {
3350 /* We can't fit all the extents into the fixed size buffer.
3351 * Allocate one that is large enough and use it instead.
3352 */
3353 fm = malloc(outbufsz);
3354 if (!fm) {
3355 return -TARGET_ENOMEM;
3356 }
3357 memcpy(fm, buf_temp, sizeof(struct fiemap));
3358 free_fm = 1;
3359 }
3360 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3361 if (!is_error(ret)) {
3362 target_size_out = target_size_in;
3363 /* An extent_count of 0 means we were only counting the extents
3364 * so there are no structs to copy
3365 */
3366 if (fm->fm_extent_count != 0) {
3367 target_size_out += fm->fm_mapped_extents * extent_size;
3368 }
3369 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3370 if (!argptr) {
3371 ret = -TARGET_EFAULT;
3372 } else {
3373 /* Convert the struct fiemap */
3374 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3375 if (fm->fm_extent_count != 0) {
3376 p = argptr + target_size_in;
3377 /* ...and then all the struct fiemap_extents */
3378 for (i = 0; i < fm->fm_mapped_extents; i++) {
3379 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3380 THUNK_TARGET);
3381 p += extent_size;
3382 }
3383 }
3384 unlock_user(argptr, arg, target_size_out);
3385 }
3386 }
3387 if (free_fm) {
3388 free(fm);
3389 }
3390 return ret;
3391}
Peter Maydelldace20d2011-01-10 13:11:24 +00003392#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003393
Laurent Vivier059c2f22011-03-30 00:12:12 +02003394static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3395 int fd, abi_long cmd, abi_long arg)
3396{
3397 const argtype *arg_type = ie->arg_type;
3398 int target_size;
3399 void *argptr;
3400 int ret;
3401 struct ifconf *host_ifconf;
3402 uint32_t outbufsz;
3403 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3404 int target_ifreq_size;
3405 int nb_ifreq;
3406 int free_buf = 0;
3407 int i;
3408 int target_ifc_len;
3409 abi_long target_ifc_buf;
3410 int host_ifc_len;
3411 char *host_ifc_buf;
3412
3413 assert(arg_type[0] == TYPE_PTR);
3414 assert(ie->access == IOC_RW);
3415
3416 arg_type++;
3417 target_size = thunk_type_size(arg_type, 0);
3418
3419 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3420 if (!argptr)
3421 return -TARGET_EFAULT;
3422 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3423 unlock_user(argptr, arg, 0);
3424
3425 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3426 target_ifc_len = host_ifconf->ifc_len;
3427 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3428
3429 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3430 nb_ifreq = target_ifc_len / target_ifreq_size;
3431 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3432
3433 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3434 if (outbufsz > MAX_STRUCT_SIZE) {
3435 /* We can't fit all the extents into the fixed size buffer.
3436 * Allocate one that is large enough and use it instead.
3437 */
3438 host_ifconf = malloc(outbufsz);
3439 if (!host_ifconf) {
3440 return -TARGET_ENOMEM;
3441 }
3442 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3443 free_buf = 1;
3444 }
3445 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3446
3447 host_ifconf->ifc_len = host_ifc_len;
3448 host_ifconf->ifc_buf = host_ifc_buf;
3449
3450 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3451 if (!is_error(ret)) {
3452 /* convert host ifc_len to target ifc_len */
3453
3454 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3455 target_ifc_len = nb_ifreq * target_ifreq_size;
3456 host_ifconf->ifc_len = target_ifc_len;
3457
3458 /* restore target ifc_buf */
3459
3460 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3461
3462 /* copy struct ifconf to target user */
3463
3464 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3465 if (!argptr)
3466 return -TARGET_EFAULT;
3467 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3468 unlock_user(argptr, arg, target_size);
3469
3470 /* copy ifreq[] to target user */
3471
3472 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3473 for (i = 0; i < nb_ifreq ; i++) {
3474 thunk_convert(argptr + i * target_ifreq_size,
3475 host_ifc_buf + i * sizeof(struct ifreq),
3476 ifreq_arg_type, THUNK_TARGET);
3477 }
3478 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3479 }
3480
3481 if (free_buf) {
3482 free(host_ifconf);
3483 }
3484
3485 return ret;
3486}
3487
Alexander Graf56e904e2012-01-31 18:42:06 +01003488static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3489 abi_long cmd, abi_long arg)
3490{
3491 void *argptr;
3492 struct dm_ioctl *host_dm;
3493 abi_long guest_data;
3494 uint32_t guest_data_size;
3495 int target_size;
3496 const argtype *arg_type = ie->arg_type;
3497 abi_long ret;
3498 void *big_buf = NULL;
3499 char *host_data;
3500
3501 arg_type++;
3502 target_size = thunk_type_size(arg_type, 0);
3503 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3504 if (!argptr) {
3505 ret = -TARGET_EFAULT;
3506 goto out;
3507 }
3508 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3509 unlock_user(argptr, arg, 0);
3510
3511 /* buf_temp is too small, so fetch things into a bigger buffer */
3512 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3513 memcpy(big_buf, buf_temp, target_size);
3514 buf_temp = big_buf;
3515 host_dm = big_buf;
3516
3517 guest_data = arg + host_dm->data_start;
3518 if ((guest_data - arg) < 0) {
3519 ret = -EINVAL;
3520 goto out;
3521 }
3522 guest_data_size = host_dm->data_size - host_dm->data_start;
3523 host_data = (char*)host_dm + host_dm->data_start;
3524
3525 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3526 switch (ie->host_cmd) {
3527 case DM_REMOVE_ALL:
3528 case DM_LIST_DEVICES:
3529 case DM_DEV_CREATE:
3530 case DM_DEV_REMOVE:
3531 case DM_DEV_SUSPEND:
3532 case DM_DEV_STATUS:
3533 case DM_DEV_WAIT:
3534 case DM_TABLE_STATUS:
3535 case DM_TABLE_CLEAR:
3536 case DM_TABLE_DEPS:
3537 case DM_LIST_VERSIONS:
3538 /* no input data */
3539 break;
3540 case DM_DEV_RENAME:
3541 case DM_DEV_SET_GEOMETRY:
3542 /* data contains only strings */
3543 memcpy(host_data, argptr, guest_data_size);
3544 break;
3545 case DM_TARGET_MSG:
3546 memcpy(host_data, argptr, guest_data_size);
3547 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3548 break;
3549 case DM_TABLE_LOAD:
3550 {
3551 void *gspec = argptr;
3552 void *cur_data = host_data;
3553 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3554 int spec_size = thunk_type_size(arg_type, 0);
3555 int i;
3556
3557 for (i = 0; i < host_dm->target_count; i++) {
3558 struct dm_target_spec *spec = cur_data;
3559 uint32_t next;
3560 int slen;
3561
3562 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3563 slen = strlen((char*)gspec + spec_size) + 1;
3564 next = spec->next;
3565 spec->next = sizeof(*spec) + slen;
3566 strcpy((char*)&spec[1], gspec + spec_size);
3567 gspec += next;
3568 cur_data += spec->next;
3569 }
3570 break;
3571 }
3572 default:
3573 ret = -TARGET_EINVAL;
3574 goto out;
3575 }
3576 unlock_user(argptr, guest_data, 0);
3577
3578 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3579 if (!is_error(ret)) {
3580 guest_data = arg + host_dm->data_start;
3581 guest_data_size = host_dm->data_size - host_dm->data_start;
3582 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3583 switch (ie->host_cmd) {
3584 case DM_REMOVE_ALL:
3585 case DM_DEV_CREATE:
3586 case DM_DEV_REMOVE:
3587 case DM_DEV_RENAME:
3588 case DM_DEV_SUSPEND:
3589 case DM_DEV_STATUS:
3590 case DM_TABLE_LOAD:
3591 case DM_TABLE_CLEAR:
3592 case DM_TARGET_MSG:
3593 case DM_DEV_SET_GEOMETRY:
3594 /* no return data */
3595 break;
3596 case DM_LIST_DEVICES:
3597 {
3598 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3599 uint32_t remaining_data = guest_data_size;
3600 void *cur_data = argptr;
3601 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3602 int nl_size = 12; /* can't use thunk_size due to alignment */
3603
3604 while (1) {
3605 uint32_t next = nl->next;
3606 if (next) {
3607 nl->next = nl_size + (strlen(nl->name) + 1);
3608 }
3609 if (remaining_data < nl->next) {
3610 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3611 break;
3612 }
3613 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3614 strcpy(cur_data + nl_size, nl->name);
3615 cur_data += nl->next;
3616 remaining_data -= nl->next;
3617 if (!next) {
3618 break;
3619 }
3620 nl = (void*)nl + next;
3621 }
3622 break;
3623 }
3624 case DM_DEV_WAIT:
3625 case DM_TABLE_STATUS:
3626 {
3627 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3628 void *cur_data = argptr;
3629 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3630 int spec_size = thunk_type_size(arg_type, 0);
3631 int i;
3632
3633 for (i = 0; i < host_dm->target_count; i++) {
3634 uint32_t next = spec->next;
3635 int slen = strlen((char*)&spec[1]) + 1;
3636 spec->next = (cur_data - argptr) + spec_size + slen;
3637 if (guest_data_size < spec->next) {
3638 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3639 break;
3640 }
3641 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3642 strcpy(cur_data + spec_size, (char*)&spec[1]);
3643 cur_data = argptr + spec->next;
3644 spec = (void*)host_dm + host_dm->data_start + next;
3645 }
3646 break;
3647 }
3648 case DM_TABLE_DEPS:
3649 {
3650 void *hdata = (void*)host_dm + host_dm->data_start;
3651 int count = *(uint32_t*)hdata;
3652 uint64_t *hdev = hdata + 8;
3653 uint64_t *gdev = argptr + 8;
3654 int i;
3655
3656 *(uint32_t*)argptr = tswap32(count);
3657 for (i = 0; i < count; i++) {
3658 *gdev = tswap64(*hdev);
3659 gdev++;
3660 hdev++;
3661 }
3662 break;
3663 }
3664 case DM_LIST_VERSIONS:
3665 {
3666 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3667 uint32_t remaining_data = guest_data_size;
3668 void *cur_data = argptr;
3669 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3670 int vers_size = thunk_type_size(arg_type, 0);
3671
3672 while (1) {
3673 uint32_t next = vers->next;
3674 if (next) {
3675 vers->next = vers_size + (strlen(vers->name) + 1);
3676 }
3677 if (remaining_data < vers->next) {
3678 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3679 break;
3680 }
3681 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3682 strcpy(cur_data + vers_size, vers->name);
3683 cur_data += vers->next;
3684 remaining_data -= vers->next;
3685 if (!next) {
3686 break;
3687 }
3688 vers = (void*)vers + next;
3689 }
3690 break;
3691 }
3692 default:
3693 ret = -TARGET_EINVAL;
3694 goto out;
3695 }
3696 unlock_user(argptr, guest_data, guest_data_size);
3697
3698 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3699 if (!argptr) {
3700 ret = -TARGET_EFAULT;
3701 goto out;
3702 }
3703 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3704 unlock_user(argptr, arg, target_size);
3705 }
3706out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003707 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003708 return ret;
3709}
3710
Alexander Grafa59b5e32014-08-22 13:15:50 +02003711static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3712 abi_long cmd, abi_long arg)
3713{
3714 void *argptr;
3715 int target_size;
3716 const argtype *arg_type = ie->arg_type;
3717 const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
3718 abi_long ret;
3719
3720 struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
3721 struct blkpg_partition host_part;
3722
3723 /* Read and convert blkpg */
3724 arg_type++;
3725 target_size = thunk_type_size(arg_type, 0);
3726 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3727 if (!argptr) {
3728 ret = -TARGET_EFAULT;
3729 goto out;
3730 }
3731 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3732 unlock_user(argptr, arg, 0);
3733
3734 switch (host_blkpg->op) {
3735 case BLKPG_ADD_PARTITION:
3736 case BLKPG_DEL_PARTITION:
3737 /* payload is struct blkpg_partition */
3738 break;
3739 default:
3740 /* Unknown opcode */
3741 ret = -TARGET_EINVAL;
3742 goto out;
3743 }
3744
3745 /* Read and convert blkpg->data */
3746 arg = (abi_long)(uintptr_t)host_blkpg->data;
3747 target_size = thunk_type_size(part_arg_type, 0);
3748 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3749 if (!argptr) {
3750 ret = -TARGET_EFAULT;
3751 goto out;
3752 }
3753 thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
3754 unlock_user(argptr, arg, 0);
3755
3756 /* Swizzle the data pointer to our local copy and call! */
3757 host_blkpg->data = &host_part;
3758 ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg));
3759
3760out:
3761 return ret;
3762}
3763
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003764static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3765 int fd, abi_long cmd, abi_long arg)
3766{
3767 const argtype *arg_type = ie->arg_type;
3768 const StructEntry *se;
3769 const argtype *field_types;
3770 const int *dst_offsets, *src_offsets;
3771 int target_size;
3772 void *argptr;
3773 abi_ulong *target_rt_dev_ptr;
3774 unsigned long *host_rt_dev_ptr;
3775 abi_long ret;
3776 int i;
3777
3778 assert(ie->access == IOC_W);
3779 assert(*arg_type == TYPE_PTR);
3780 arg_type++;
3781 assert(*arg_type == TYPE_STRUCT);
3782 target_size = thunk_type_size(arg_type, 0);
3783 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3784 if (!argptr) {
3785 return -TARGET_EFAULT;
3786 }
3787 arg_type++;
3788 assert(*arg_type == (int)STRUCT_rtentry);
3789 se = struct_entries + *arg_type++;
3790 assert(se->convert[0] == NULL);
3791 /* convert struct here to be able to catch rt_dev string */
3792 field_types = se->field_types;
3793 dst_offsets = se->field_offsets[THUNK_HOST];
3794 src_offsets = se->field_offsets[THUNK_TARGET];
3795 for (i = 0; i < se->nb_fields; i++) {
3796 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3797 assert(*field_types == TYPE_PTRVOID);
3798 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3799 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3800 if (*target_rt_dev_ptr != 0) {
3801 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3802 tswapal(*target_rt_dev_ptr));
3803 if (!*host_rt_dev_ptr) {
3804 unlock_user(argptr, arg, 0);
3805 return -TARGET_EFAULT;
3806 }
3807 } else {
3808 *host_rt_dev_ptr = 0;
3809 }
3810 field_types++;
3811 continue;
3812 }
3813 field_types = thunk_convert(buf_temp + dst_offsets[i],
3814 argptr + src_offsets[i],
3815 field_types, THUNK_HOST);
3816 }
3817 unlock_user(argptr, arg, 0);
3818
3819 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3820 if (*host_rt_dev_ptr != 0) {
3821 unlock_user((void *)*host_rt_dev_ptr,
3822 *target_rt_dev_ptr, 0);
3823 }
3824 return ret;
3825}
3826
Paul Burtonca56f5b2014-06-22 11:25:47 +01003827static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
3828 int fd, abi_long cmd, abi_long arg)
3829{
3830 int sig = target_to_host_signal(arg);
3831 return get_errno(ioctl(fd, ie->host_cmd, sig));
3832}
3833
blueswir19f106a72008-10-05 10:52:52 +00003834static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003835#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003836 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3837#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3838 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003839#include "ioctls.h"
3840 { 0, 0, },
3841};
3842
pbrook53a59602006-03-25 19:31:22 +00003843/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003844/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003845static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003846{
3847 const IOCTLEntry *ie;
3848 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003849 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003850 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003851 int target_size;
3852 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003853
3854 ie = ioctl_entries;
3855 for(;;) {
3856 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003857 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003858 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003859 }
3860 if (ie->target_cmd == cmd)
3861 break;
3862 ie++;
3863 }
3864 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003865#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003866 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003867#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003868 if (ie->do_ioctl) {
3869 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3870 }
3871
bellard31e31b82003-02-18 22:55:36 +00003872 switch(arg_type[0]) {
3873 case TYPE_NULL:
3874 /* no argument */
3875 ret = get_errno(ioctl(fd, ie->host_cmd));
3876 break;
3877 case TYPE_PTRVOID:
3878 case TYPE_INT:
3879 /* int argment */
3880 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3881 break;
3882 case TYPE_PTR:
3883 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003884 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003885 switch(ie->access) {
3886 case IOC_R:
3887 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3888 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003889 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3890 if (!argptr)
3891 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003892 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3893 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003894 }
3895 break;
3896 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003897 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3898 if (!argptr)
3899 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003900 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3901 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003902 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3903 break;
3904 default:
3905 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003906 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3907 if (!argptr)
3908 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003909 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3910 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003911 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3912 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003913 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3914 if (!argptr)
3915 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003916 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3917 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003918 }
3919 break;
3920 }
3921 break;
3922 default:
j_mayer32407102007-09-26 23:01:49 +00003923 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3924 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003925 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003926 break;
3927 }
3928 return ret;
3929}
3930
blueswir1b39bc502008-10-05 10:51:10 +00003931static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003932 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3933 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3934 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3935 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3936 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3937 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3938 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3939 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3940 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3941 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3942 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3943 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3944 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3945 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3946 { 0, 0, 0, 0 }
3947};
3948
blueswir1b39bc502008-10-05 10:51:10 +00003949static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003950 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3951 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3952 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3953 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3954 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3955 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3956 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3957 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3958 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3959 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3960 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3961 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3962 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3963 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3964 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3965 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3966 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3967 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3968 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3969 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3970 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3971 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3972 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3973 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3974 { 0, 0, 0, 0 }
3975};
3976
blueswir1b39bc502008-10-05 10:51:10 +00003977static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003978 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3979 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3980 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3981 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3982 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3983 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3984 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3985 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3986 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3987 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3988 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3989 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3990 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3991 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3992 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3993 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3994 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3995 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3996 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3997 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3998 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3999 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
4000 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
4001 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
4002 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
4003 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
4004 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
4005 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
4006 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
4007 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
4008 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
4009 { 0, 0, 0, 0 }
4010};
4011
blueswir1b39bc502008-10-05 10:51:10 +00004012static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00004013 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
4014 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
4015 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
4016 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
4017 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
4018 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
4019 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
4020 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
4021 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
4022 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
4023 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
4024 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
4025 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
4026 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
4027 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
4028 { 0, 0, 0, 0 }
4029};
4030
4031static void target_to_host_termios (void *dst, const void *src)
4032{
4033 struct host_termios *host = dst;
4034 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00004035
ths5fafdf22007-09-16 21:08:06 +00004036 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004037 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004038 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004039 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004040 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004041 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00004042 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004043 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
4044 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00004045
Arnaud Patard44607122009-04-21 17:39:08 +03004046 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00004047 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
4048 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00004049 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00004050 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00004051 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00004052 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00004053 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00004054 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00004055 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00004056 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
4057 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00004058 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
4059 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
4060 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
4061 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
4062 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00004063 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00004064}
ths3b46e622007-09-17 08:09:54 +00004065
bellard31e31b82003-02-18 22:55:36 +00004066static void host_to_target_termios (void *dst, const void *src)
4067{
4068 struct target_termios *target = dst;
4069 const struct host_termios *host = src;
4070
ths5fafdf22007-09-16 21:08:06 +00004071 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00004072 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004073 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00004074 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004075 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00004076 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00004077 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00004078 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
4079 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00004080
Arnaud Patard44607122009-04-21 17:39:08 +03004081 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00004082 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
4083 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
4084 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
4085 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
4086 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
4087 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
4088 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
4089 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
4090 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
4091 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
4092 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
4093 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
4094 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
4095 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
4096 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
4097 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
4098 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
4099}
4100
blueswir18e853dc2008-10-05 10:49:32 +00004101static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00004102 .convert = { host_to_target_termios, target_to_host_termios },
4103 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
4104 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
4105};
4106
bellard5286db72003-06-05 00:57:30 +00004107static bitmask_transtbl mmap_flags_tbl[] = {
4108 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4109 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4110 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4111 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4112 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4113 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4114 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4115 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004116 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4117 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004118 { 0, 0, 0, 0 }
4119};
4120
bellard2ab83ea2003-06-15 19:56:46 +00004121#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004122
4123/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004124static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004125
bellard03acab62007-11-11 14:57:14 +00004126static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004127{
4128 int size;
pbrook53a59602006-03-25 19:31:22 +00004129 void *p;
bellard6dbad632003-03-16 18:05:05 +00004130
4131 if (!ldt_table)
4132 return 0;
4133 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4134 if (size > bytecount)
4135 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004136 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4137 if (!p)
bellard03acab62007-11-11 14:57:14 +00004138 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004139 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004140 memcpy(p, ldt_table, size);
4141 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004142 return size;
4143}
4144
4145/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004146static abi_long write_ldt(CPUX86State *env,
4147 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004148{
4149 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004150 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004151 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004152 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004153 uint32_t *lp, entry_1, entry_2;
4154
4155 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004156 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004157 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004158 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004159 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004160 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004161 ldt_info.limit = tswap32(target_ldt_info->limit);
4162 ldt_info.flags = tswap32(target_ldt_info->flags);
4163 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004164
bellard6dbad632003-03-16 18:05:05 +00004165 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004166 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004167 seg_32bit = ldt_info.flags & 1;
4168 contents = (ldt_info.flags >> 1) & 3;
4169 read_exec_only = (ldt_info.flags >> 3) & 1;
4170 limit_in_pages = (ldt_info.flags >> 4) & 1;
4171 seg_not_present = (ldt_info.flags >> 5) & 1;
4172 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004173#ifdef TARGET_ABI32
4174 lm = 0;
4175#else
4176 lm = (ldt_info.flags >> 7) & 1;
4177#endif
bellard6dbad632003-03-16 18:05:05 +00004178 if (contents == 3) {
4179 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004180 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004181 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004182 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004183 }
4184 /* allocate the LDT */
4185 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004186 env->ldt.base = target_mmap(0,
4187 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4188 PROT_READ|PROT_WRITE,
4189 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4190 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004191 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004192 memset(g2h(env->ldt.base), 0,
4193 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004194 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004195 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004196 }
4197
4198 /* NOTE: same code as Linux kernel */
4199 /* Allow LDTs to be cleared by the user. */
4200 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4201 if (oldmode ||
4202 (contents == 0 &&
4203 read_exec_only == 1 &&
4204 seg_32bit == 0 &&
4205 limit_in_pages == 0 &&
4206 seg_not_present == 1 &&
4207 useable == 0 )) {
4208 entry_1 = 0;
4209 entry_2 = 0;
4210 goto install;
4211 }
4212 }
ths3b46e622007-09-17 08:09:54 +00004213
bellard6dbad632003-03-16 18:05:05 +00004214 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4215 (ldt_info.limit & 0x0ffff);
4216 entry_2 = (ldt_info.base_addr & 0xff000000) |
4217 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4218 (ldt_info.limit & 0xf0000) |
4219 ((read_exec_only ^ 1) << 9) |
4220 (contents << 10) |
4221 ((seg_not_present ^ 1) << 15) |
4222 (seg_32bit << 22) |
4223 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004224 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004225 0x7000;
4226 if (!oldmode)
4227 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004228
bellard6dbad632003-03-16 18:05:05 +00004229 /* Install the new entry ... */
4230install:
4231 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4232 lp[0] = tswap32(entry_1);
4233 lp[1] = tswap32(entry_2);
4234 return 0;
4235}
4236
4237/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004238static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4239 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004240{
bellard03acab62007-11-11 14:57:14 +00004241 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004242
bellard6dbad632003-03-16 18:05:05 +00004243 switch (func) {
4244 case 0:
4245 ret = read_ldt(ptr, bytecount);
4246 break;
4247 case 1:
4248 ret = write_ldt(env, ptr, bytecount, 1);
4249 break;
4250 case 0x11:
4251 ret = write_ldt(env, ptr, bytecount, 0);
4252 break;
bellard03acab62007-11-11 14:57:14 +00004253 default:
4254 ret = -TARGET_ENOSYS;
4255 break;
bellard6dbad632003-03-16 18:05:05 +00004256 }
4257 return ret;
4258}
bellard1b6b0292003-03-22 17:31:38 +00004259
blueswir14583f582008-08-24 10:35:55 +00004260#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004261abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004262{
4263 uint64_t *gdt_table = g2h(env->gdt.base);
4264 struct target_modify_ldt_ldt_s ldt_info;
4265 struct target_modify_ldt_ldt_s *target_ldt_info;
4266 int seg_32bit, contents, read_exec_only, limit_in_pages;
4267 int seg_not_present, useable, lm;
4268 uint32_t *lp, entry_1, entry_2;
4269 int i;
4270
4271 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4272 if (!target_ldt_info)
4273 return -TARGET_EFAULT;
4274 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004275 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004276 ldt_info.limit = tswap32(target_ldt_info->limit);
4277 ldt_info.flags = tswap32(target_ldt_info->flags);
4278 if (ldt_info.entry_number == -1) {
4279 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4280 if (gdt_table[i] == 0) {
4281 ldt_info.entry_number = i;
4282 target_ldt_info->entry_number = tswap32(i);
4283 break;
4284 }
4285 }
4286 }
4287 unlock_user_struct(target_ldt_info, ptr, 1);
4288
4289 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4290 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4291 return -TARGET_EINVAL;
4292 seg_32bit = ldt_info.flags & 1;
4293 contents = (ldt_info.flags >> 1) & 3;
4294 read_exec_only = (ldt_info.flags >> 3) & 1;
4295 limit_in_pages = (ldt_info.flags >> 4) & 1;
4296 seg_not_present = (ldt_info.flags >> 5) & 1;
4297 useable = (ldt_info.flags >> 6) & 1;
4298#ifdef TARGET_ABI32
4299 lm = 0;
4300#else
4301 lm = (ldt_info.flags >> 7) & 1;
4302#endif
4303
4304 if (contents == 3) {
4305 if (seg_not_present == 0)
4306 return -TARGET_EINVAL;
4307 }
4308
4309 /* NOTE: same code as Linux kernel */
4310 /* Allow LDTs to be cleared by the user. */
4311 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4312 if ((contents == 0 &&
4313 read_exec_only == 1 &&
4314 seg_32bit == 0 &&
4315 limit_in_pages == 0 &&
4316 seg_not_present == 1 &&
4317 useable == 0 )) {
4318 entry_1 = 0;
4319 entry_2 = 0;
4320 goto install;
4321 }
4322 }
4323
4324 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4325 (ldt_info.limit & 0x0ffff);
4326 entry_2 = (ldt_info.base_addr & 0xff000000) |
4327 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4328 (ldt_info.limit & 0xf0000) |
4329 ((read_exec_only ^ 1) << 9) |
4330 (contents << 10) |
4331 ((seg_not_present ^ 1) << 15) |
4332 (seg_32bit << 22) |
4333 (limit_in_pages << 23) |
4334 (useable << 20) |
4335 (lm << 21) |
4336 0x7000;
4337
4338 /* Install the new entry ... */
4339install:
4340 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4341 lp[0] = tswap32(entry_1);
4342 lp[1] = tswap32(entry_2);
4343 return 0;
4344}
4345
blueswir18fcd3692008-08-17 20:26:25 +00004346static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004347{
4348 struct target_modify_ldt_ldt_s *target_ldt_info;
4349 uint64_t *gdt_table = g2h(env->gdt.base);
4350 uint32_t base_addr, limit, flags;
4351 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4352 int seg_not_present, useable, lm;
4353 uint32_t *lp, entry_1, entry_2;
4354
4355 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4356 if (!target_ldt_info)
4357 return -TARGET_EFAULT;
4358 idx = tswap32(target_ldt_info->entry_number);
4359 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4360 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4361 unlock_user_struct(target_ldt_info, ptr, 1);
4362 return -TARGET_EINVAL;
4363 }
4364 lp = (uint32_t *)(gdt_table + idx);
4365 entry_1 = tswap32(lp[0]);
4366 entry_2 = tswap32(lp[1]);
4367
4368 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4369 contents = (entry_2 >> 10) & 3;
4370 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4371 seg_32bit = (entry_2 >> 22) & 1;
4372 limit_in_pages = (entry_2 >> 23) & 1;
4373 useable = (entry_2 >> 20) & 1;
4374#ifdef TARGET_ABI32
4375 lm = 0;
4376#else
4377 lm = (entry_2 >> 21) & 1;
4378#endif
4379 flags = (seg_32bit << 0) | (contents << 1) |
4380 (read_exec_only << 3) | (limit_in_pages << 4) |
4381 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4382 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4383 base_addr = (entry_1 >> 16) |
4384 (entry_2 & 0xff000000) |
4385 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004386 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004387 target_ldt_info->limit = tswap32(limit);
4388 target_ldt_info->flags = tswap32(flags);
4389 unlock_user_struct(target_ldt_info, ptr, 1);
4390 return 0;
4391}
blueswir14583f582008-08-24 10:35:55 +00004392#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004393
bellardd2fd1af2007-11-14 18:08:56 +00004394#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004395abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004396{
Juan Quintela1add8692011-06-16 17:37:09 +01004397 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004398 abi_ulong val;
4399 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004400
bellardd2fd1af2007-11-14 18:08:56 +00004401 switch(code) {
4402 case TARGET_ARCH_SET_GS:
4403 case TARGET_ARCH_SET_FS:
4404 if (code == TARGET_ARCH_SET_GS)
4405 idx = R_GS;
4406 else
4407 idx = R_FS;
4408 cpu_x86_load_seg(env, idx, 0);
4409 env->segs[idx].base = addr;
4410 break;
4411 case TARGET_ARCH_GET_GS:
4412 case TARGET_ARCH_GET_FS:
4413 if (code == TARGET_ARCH_GET_GS)
4414 idx = R_GS;
4415 else
4416 idx = R_FS;
4417 val = env->segs[idx].base;
4418 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004419 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004420 break;
4421 default:
4422 ret = -TARGET_EINVAL;
4423 break;
4424 }
Juan Quintela1add8692011-06-16 17:37:09 +01004425 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004426}
4427#endif
4428
bellard2ab83ea2003-06-15 19:56:46 +00004429#endif /* defined(TARGET_I386) */
4430
Riku Voipio05098a92011-03-04 15:27:29 +02004431#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004432
pbrookd865bab2008-06-07 22:12:17 +00004433
4434static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4435typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004436 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004437 pthread_mutex_t mutex;
4438 pthread_cond_t cond;
4439 pthread_t thread;
4440 uint32_t tid;
4441 abi_ulong child_tidptr;
4442 abi_ulong parent_tidptr;
4443 sigset_t sigmask;
4444} new_thread_info;
4445
4446static void *clone_func(void *arg)
4447{
4448 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004449 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004450 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004451 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004452
4453 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004454 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004455 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004456 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004457 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004458 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004459 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004460 if (info->child_tidptr)
4461 put_user_u32(info->tid, info->child_tidptr);
4462 if (info->parent_tidptr)
4463 put_user_u32(info->tid, info->parent_tidptr);
4464 /* Enable signals. */
4465 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4466 /* Signal to the parent that we're ready. */
4467 pthread_mutex_lock(&info->mutex);
4468 pthread_cond_broadcast(&info->cond);
4469 pthread_mutex_unlock(&info->mutex);
4470 /* Wait until the parent has finshed initializing the tls state. */
4471 pthread_mutex_lock(&clone_lock);
4472 pthread_mutex_unlock(&clone_lock);
4473 cpu_loop(env);
4474 /* never exits */
4475 return NULL;
4476}
bellard1b6b0292003-03-22 17:31:38 +00004477
ths0da46a62007-10-20 20:23:07 +00004478/* do_fork() Must return host values and target errnos (unlike most
4479 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004480static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004481 abi_ulong parent_tidptr, target_ulong newtls,
4482 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004483{
Andreas Färber0429a972013-08-26 18:14:44 +02004484 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004485 int ret;
bellard5cd43932003-03-29 16:54:36 +00004486 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004487 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004488 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004489 unsigned int nptl_flags;
4490 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004491
balrog436d1242008-09-21 02:39:45 +00004492 /* Emulate vfork() with fork() */
4493 if (flags & CLONE_VFORK)
4494 flags &= ~(CLONE_VFORK | CLONE_VM);
4495
bellard1b6b0292003-03-22 17:31:38 +00004496 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004497 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004498 new_thread_info info;
4499 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004500
Anthony Liguori7267c092011-08-20 22:09:37 -05004501 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004502 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004503 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004504 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004505 /* Init regs that differ from the parent. */
4506 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004507 new_cpu = ENV_GET_CPU(new_env);
4508 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004509 ts->bprm = parent_ts->bprm;
4510 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004511 nptl_flags = flags;
4512 flags &= ~CLONE_NPTL_FLAGS2;
4513
pbrookc2764712009-03-07 15:24:59 +00004514 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4515 ts->child_tidptr = child_tidptr;
4516 }
4517
pbrookd865bab2008-06-07 22:12:17 +00004518 if (nptl_flags & CLONE_SETTLS)
4519 cpu_set_tls (new_env, newtls);
4520
4521 /* Grab a mutex so that thread setup appears atomic. */
4522 pthread_mutex_lock(&clone_lock);
4523
4524 memset(&info, 0, sizeof(info));
4525 pthread_mutex_init(&info.mutex, NULL);
4526 pthread_mutex_lock(&info.mutex);
4527 pthread_cond_init(&info.cond, NULL);
4528 info.env = new_env;
4529 if (nptl_flags & CLONE_CHILD_SETTID)
4530 info.child_tidptr = child_tidptr;
4531 if (nptl_flags & CLONE_PARENT_SETTID)
4532 info.parent_tidptr = parent_tidptr;
4533
4534 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004535 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4536 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004537 /* It is not safe to deliver signals until the child has finished
4538 initializing, so temporarily block all signals. */
4539 sigfillset(&sigmask);
4540 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4541
4542 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004543 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004544
4545 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4546 pthread_attr_destroy(&attr);
4547 if (ret == 0) {
4548 /* Wait for the child to initialize. */
4549 pthread_cond_wait(&info.cond, &info.mutex);
4550 ret = info.tid;
4551 if (flags & CLONE_PARENT_SETTID)
4552 put_user_u32(ret, parent_tidptr);
4553 } else {
4554 ret = -1;
4555 }
4556 pthread_mutex_unlock(&info.mutex);
4557 pthread_cond_destroy(&info.cond);
4558 pthread_mutex_destroy(&info.mutex);
4559 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004560 } else {
4561 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004562 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004563 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004564 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004565 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004566 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004567 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004568 cpu_clone_regs(env, newsp);
4569 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004570 /* There is a race condition here. The parent process could
4571 theoretically read the TID in the child process before the child
4572 tid is set. This would require using either ptrace
4573 (not implemented) or having *_tidptr to point at a shared memory
4574 mapping. We can't repeat the spinlock hack used above because
4575 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004576 if (flags & CLONE_CHILD_SETTID)
4577 put_user_u32(gettid(), child_tidptr);
4578 if (flags & CLONE_PARENT_SETTID)
4579 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004580 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004581 if (flags & CLONE_SETTLS)
4582 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004583 if (flags & CLONE_CHILD_CLEARTID)
4584 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004585 } else {
4586 fork_end(0);
4587 }
bellard1b6b0292003-03-22 17:31:38 +00004588 }
4589 return ret;
4590}
4591
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004592/* warning : doesn't handle linux specific flags... */
4593static int target_to_host_fcntl_cmd(int cmd)
4594{
4595 switch(cmd) {
4596 case TARGET_F_DUPFD:
4597 case TARGET_F_GETFD:
4598 case TARGET_F_SETFD:
4599 case TARGET_F_GETFL:
4600 case TARGET_F_SETFL:
4601 return cmd;
4602 case TARGET_F_GETLK:
4603 return F_GETLK;
4604 case TARGET_F_SETLK:
4605 return F_SETLK;
4606 case TARGET_F_SETLKW:
4607 return F_SETLKW;
4608 case TARGET_F_GETOWN:
4609 return F_GETOWN;
4610 case TARGET_F_SETOWN:
4611 return F_SETOWN;
4612 case TARGET_F_GETSIG:
4613 return F_GETSIG;
4614 case TARGET_F_SETSIG:
4615 return F_SETSIG;
4616#if TARGET_ABI_BITS == 32
4617 case TARGET_F_GETLK64:
4618 return F_GETLK64;
4619 case TARGET_F_SETLK64:
4620 return F_SETLK64;
4621 case TARGET_F_SETLKW64:
4622 return F_SETLKW64;
4623#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004624 case TARGET_F_SETLEASE:
4625 return F_SETLEASE;
4626 case TARGET_F_GETLEASE:
4627 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004628#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004629 case TARGET_F_DUPFD_CLOEXEC:
4630 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004631#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004632 case TARGET_F_NOTIFY:
4633 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004634#ifdef F_GETOWN_EX
4635 case TARGET_F_GETOWN_EX:
4636 return F_GETOWN_EX;
4637#endif
4638#ifdef F_SETOWN_EX
4639 case TARGET_F_SETOWN_EX:
4640 return F_SETOWN_EX;
4641#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004642 default:
4643 return -TARGET_EINVAL;
4644 }
4645 return -TARGET_EINVAL;
4646}
4647
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004648#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4649static const bitmask_transtbl flock_tbl[] = {
4650 TRANSTBL_CONVERT(F_RDLCK),
4651 TRANSTBL_CONVERT(F_WRLCK),
4652 TRANSTBL_CONVERT(F_UNLCK),
4653 TRANSTBL_CONVERT(F_EXLCK),
4654 TRANSTBL_CONVERT(F_SHLCK),
4655 { 0, 0, 0, 0 }
4656};
4657
blueswir1992f48a2007-10-14 16:27:31 +00004658static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004659{
4660 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004661 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004662 struct flock64 fl64;
4663 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004664#ifdef F_GETOWN_EX
4665 struct f_owner_ex fox;
4666 struct target_f_owner_ex *target_fox;
4667#endif
blueswir1992f48a2007-10-14 16:27:31 +00004668 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004669 int host_cmd = target_to_host_fcntl_cmd(cmd);
4670
4671 if (host_cmd == -TARGET_EINVAL)
4672 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004673
bellard7775e9e2003-05-14 22:46:48 +00004674 switch(cmd) {
4675 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004676 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4677 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004678 fl.l_type =
4679 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004680 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004681 fl.l_start = tswapal(target_fl->l_start);
4682 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004683 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004684 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004685 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004686 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004687 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4688 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004689 target_fl->l_type =
4690 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004691 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004692 target_fl->l_start = tswapal(fl.l_start);
4693 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004694 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004695 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004696 }
4697 break;
ths3b46e622007-09-17 08:09:54 +00004698
bellard7775e9e2003-05-14 22:46:48 +00004699 case TARGET_F_SETLK:
4700 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004701 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4702 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004703 fl.l_type =
4704 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004705 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004706 fl.l_start = tswapal(target_fl->l_start);
4707 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004708 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004709 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004710 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004711 break;
ths3b46e622007-09-17 08:09:54 +00004712
bellard7775e9e2003-05-14 22:46:48 +00004713 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004714 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4715 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004716 fl64.l_type =
4717 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004718 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004719 fl64.l_start = tswap64(target_fl64->l_start);
4720 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004721 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004722 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004723 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004724 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004725 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4726 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004727 target_fl64->l_type =
4728 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004729 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004730 target_fl64->l_start = tswap64(fl64.l_start);
4731 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004732 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004733 unlock_user_struct(target_fl64, arg, 1);
4734 }
bellard9ee1fa22007-11-11 15:11:19 +00004735 break;
bellard7775e9e2003-05-14 22:46:48 +00004736 case TARGET_F_SETLK64:
4737 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004738 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4739 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004740 fl64.l_type =
4741 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004742 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004743 fl64.l_start = tswap64(target_fl64->l_start);
4744 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004745 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004746 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004747 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004748 break;
4749
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004750 case TARGET_F_GETFL:
4751 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004752 if (ret >= 0) {
4753 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4754 }
bellardffa65c32004-01-04 23:57:22 +00004755 break;
4756
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004757 case TARGET_F_SETFL:
4758 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4759 break;
4760
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004761#ifdef F_GETOWN_EX
4762 case TARGET_F_GETOWN_EX:
4763 ret = get_errno(fcntl(fd, host_cmd, &fox));
4764 if (ret >= 0) {
4765 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4766 return -TARGET_EFAULT;
4767 target_fox->type = tswap32(fox.type);
4768 target_fox->pid = tswap32(fox.pid);
4769 unlock_user_struct(target_fox, arg, 1);
4770 }
4771 break;
4772#endif
4773
4774#ifdef F_SETOWN_EX
4775 case TARGET_F_SETOWN_EX:
4776 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4777 return -TARGET_EFAULT;
4778 fox.type = tswap32(target_fox->type);
4779 fox.pid = tswap32(target_fox->pid);
4780 unlock_user_struct(target_fox, arg, 0);
4781 ret = get_errno(fcntl(fd, host_cmd, &fox));
4782 break;
4783#endif
4784
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004785 case TARGET_F_SETOWN:
4786 case TARGET_F_GETOWN:
4787 case TARGET_F_SETSIG:
4788 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004789 case TARGET_F_SETLEASE:
4790 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004791 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004792 break;
4793
bellard7775e9e2003-05-14 22:46:48 +00004794 default:
bellard9ee1fa22007-11-11 15:11:19 +00004795 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004796 break;
4797 }
4798 return ret;
4799}
4800
bellard67867302003-11-23 17:05:30 +00004801#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004802
bellard67867302003-11-23 17:05:30 +00004803static inline int high2lowuid(int uid)
4804{
4805 if (uid > 65535)
4806 return 65534;
4807 else
4808 return uid;
4809}
4810
4811static inline int high2lowgid(int gid)
4812{
4813 if (gid > 65535)
4814 return 65534;
4815 else
4816 return gid;
4817}
4818
4819static inline int low2highuid(int uid)
4820{
4821 if ((int16_t)uid == -1)
4822 return -1;
4823 else
4824 return uid;
4825}
4826
4827static inline int low2highgid(int gid)
4828{
4829 if ((int16_t)gid == -1)
4830 return -1;
4831 else
4832 return gid;
4833}
Riku Voipio0c866a72011-04-18 15:23:06 +03004834static inline int tswapid(int id)
4835{
4836 return tswap16(id);
4837}
Peter Maydell76ca3102014-03-02 19:36:41 +00004838
4839#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4840
Riku Voipio0c866a72011-04-18 15:23:06 +03004841#else /* !USE_UID16 */
4842static inline int high2lowuid(int uid)
4843{
4844 return uid;
4845}
4846static inline int high2lowgid(int gid)
4847{
4848 return gid;
4849}
4850static inline int low2highuid(int uid)
4851{
4852 return uid;
4853}
4854static inline int low2highgid(int gid)
4855{
4856 return gid;
4857}
4858static inline int tswapid(int id)
4859{
4860 return tswap32(id);
4861}
Peter Maydell76ca3102014-03-02 19:36:41 +00004862
4863#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4864
bellard67867302003-11-23 17:05:30 +00004865#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004866
bellard31e31b82003-02-18 22:55:36 +00004867void syscall_init(void)
4868{
bellard2ab83ea2003-06-15 19:56:46 +00004869 IOCTLEntry *ie;
4870 const argtype *arg_type;
4871 int size;
thsb92c47c2007-11-01 00:07:38 +00004872 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004873
Blue Swirl001faf32009-05-13 17:53:17 +00004874#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004875#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004876#include "syscall_types.h"
4877#undef STRUCT
4878#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004879
Peter Maydelldd6e9572012-07-23 08:07:22 +00004880 /* Build target_to_host_errno_table[] table from
4881 * host_to_target_errno_table[]. */
4882 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4883 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4884 }
4885
bellard2ab83ea2003-06-15 19:56:46 +00004886 /* we patch the ioctl size if necessary. We rely on the fact that
4887 no ioctl has all the bits at '1' in the size field */
4888 ie = ioctl_entries;
4889 while (ie->target_cmd != 0) {
4890 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4891 TARGET_IOC_SIZEMASK) {
4892 arg_type = ie->arg_type;
4893 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004894 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004895 ie->target_cmd);
4896 exit(1);
4897 }
4898 arg_type++;
4899 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004900 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004901 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4902 (size << TARGET_IOC_SIZESHIFT);
4903 }
thsb92c47c2007-11-01 00:07:38 +00004904
bellard2ab83ea2003-06-15 19:56:46 +00004905 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004906#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4907 (defined(__x86_64__) && defined(TARGET_X86_64))
4908 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4909 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4910 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004911 }
4912#endif
4913 ie++;
4914 }
bellard31e31b82003-02-18 22:55:36 +00004915}
bellardc573ff62004-01-04 15:51:36 +00004916
blueswir1992f48a2007-10-14 16:27:31 +00004917#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004918static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4919{
thsaf325d32008-06-10 15:29:15 +00004920#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004921 return ((uint64_t)word0 << 32) | word1;
4922#else
4923 return ((uint64_t)word1 << 32) | word0;
4924#endif
4925}
blueswir1992f48a2007-10-14 16:27:31 +00004926#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004927static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4928{
4929 return word0;
4930}
blueswir1992f48a2007-10-14 16:27:31 +00004931#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004932
4933#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004934static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4935 abi_long arg2,
4936 abi_long arg3,
4937 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004938{
Riku Voipio48e515d2011-07-12 15:40:51 +03004939 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004940 arg2 = arg3;
4941 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004942 }
pbrookce4defa2006-02-09 16:49:55 +00004943 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4944}
4945#endif
4946
4947#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004948static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4949 abi_long arg2,
4950 abi_long arg3,
4951 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004952{
Riku Voipio48e515d2011-07-12 15:40:51 +03004953 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004954 arg2 = arg3;
4955 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004956 }
pbrookce4defa2006-02-09 16:49:55 +00004957 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4958}
4959#endif
4960
bellard579a97f2007-11-11 14:26:47 +00004961static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4962 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004963{
4964 struct target_timespec *target_ts;
4965
bellard579a97f2007-11-11 14:26:47 +00004966 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4967 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004968 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4969 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004970 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004971 return 0;
pbrook53a59602006-03-25 19:31:22 +00004972}
4973
bellard579a97f2007-11-11 14:26:47 +00004974static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4975 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004976{
4977 struct target_timespec *target_ts;
4978
bellard579a97f2007-11-11 14:26:47 +00004979 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4980 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004981 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4982 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004983 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004984 return 0;
pbrook53a59602006-03-25 19:31:22 +00004985}
4986
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004987static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4988 abi_ulong target_addr)
4989{
4990 struct target_itimerspec *target_itspec;
4991
4992 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4993 return -TARGET_EFAULT;
4994 }
4995
4996 host_itspec->it_interval.tv_sec =
4997 tswapal(target_itspec->it_interval.tv_sec);
4998 host_itspec->it_interval.tv_nsec =
4999 tswapal(target_itspec->it_interval.tv_nsec);
5000 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
5001 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
5002
5003 unlock_user_struct(target_itspec, target_addr, 1);
5004 return 0;
5005}
5006
5007static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
5008 struct itimerspec *host_its)
5009{
5010 struct target_itimerspec *target_itspec;
5011
5012 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
5013 return -TARGET_EFAULT;
5014 }
5015
5016 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
5017 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
5018
5019 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
5020 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
5021
5022 unlock_user_struct(target_itspec, target_addr, 0);
5023 return 0;
5024}
5025
Peter Maydellc0659762014-08-09 15:42:32 +01005026static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
5027 abi_ulong target_addr)
5028{
5029 struct target_sigevent *target_sevp;
5030
5031 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
5032 return -TARGET_EFAULT;
5033 }
5034
5035 /* This union is awkward on 64 bit systems because it has a 32 bit
5036 * integer and a pointer in it; we follow the conversion approach
5037 * used for handling sigval types in signal.c so the guest should get
5038 * the correct value back even if we did a 64 bit byteswap and it's
5039 * using the 32 bit integer.
5040 */
5041 host_sevp->sigev_value.sival_ptr =
5042 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
5043 host_sevp->sigev_signo =
5044 target_to_host_signal(tswap32(target_sevp->sigev_signo));
5045 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
5046 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
5047
5048 unlock_user_struct(target_sevp, target_addr, 1);
5049 return 0;
5050}
5051
Tom Musta6f6a4032014-08-12 13:53:42 -05005052#if defined(TARGET_NR_mlockall)
5053static inline int target_to_host_mlockall_arg(int arg)
5054{
5055 int result = 0;
5056
5057 if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
5058 result |= MCL_CURRENT;
5059 }
5060 if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
5061 result |= MCL_FUTURE;
5062 }
5063 return result;
5064}
5065#endif
5066
aurel329d33b762009-04-08 23:07:05 +00005067#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00005068static inline abi_long host_to_target_stat64(void *cpu_env,
5069 abi_ulong target_addr,
5070 struct stat *host_st)
5071{
Alexander Graf09701192013-09-03 20:12:15 +01005072#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00005073 if (((CPUARMState *)cpu_env)->eabi) {
5074 struct target_eabi_stat64 *target_st;
5075
5076 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5077 return -TARGET_EFAULT;
5078 memset(target_st, 0, sizeof(struct target_eabi_stat64));
5079 __put_user(host_st->st_dev, &target_st->st_dev);
5080 __put_user(host_st->st_ino, &target_st->st_ino);
5081#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5082 __put_user(host_st->st_ino, &target_st->__st_ino);
5083#endif
5084 __put_user(host_st->st_mode, &target_st->st_mode);
5085 __put_user(host_st->st_nlink, &target_st->st_nlink);
5086 __put_user(host_st->st_uid, &target_st->st_uid);
5087 __put_user(host_st->st_gid, &target_st->st_gid);
5088 __put_user(host_st->st_rdev, &target_st->st_rdev);
5089 __put_user(host_st->st_size, &target_st->st_size);
5090 __put_user(host_st->st_blksize, &target_st->st_blksize);
5091 __put_user(host_st->st_blocks, &target_st->st_blocks);
5092 __put_user(host_st->st_atime, &target_st->target_st_atime);
5093 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5094 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5095 unlock_user_struct(target_st, target_addr, 1);
5096 } else
5097#endif
5098 {
Stefan Weil20d155b2013-10-30 22:52:24 +01005099#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00005100 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01005101#else
5102 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00005103#endif
balrog6a24a772008-09-20 02:23:36 +00005104
5105 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
5106 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00005107 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00005108 __put_user(host_st->st_dev, &target_st->st_dev);
5109 __put_user(host_st->st_ino, &target_st->st_ino);
5110#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
5111 __put_user(host_st->st_ino, &target_st->__st_ino);
5112#endif
5113 __put_user(host_st->st_mode, &target_st->st_mode);
5114 __put_user(host_st->st_nlink, &target_st->st_nlink);
5115 __put_user(host_st->st_uid, &target_st->st_uid);
5116 __put_user(host_st->st_gid, &target_st->st_gid);
5117 __put_user(host_st->st_rdev, &target_st->st_rdev);
5118 /* XXX: better use of kernel struct */
5119 __put_user(host_st->st_size, &target_st->st_size);
5120 __put_user(host_st->st_blksize, &target_st->st_blksize);
5121 __put_user(host_st->st_blocks, &target_st->st_blocks);
5122 __put_user(host_st->st_atime, &target_st->target_st_atime);
5123 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
5124 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5125 unlock_user_struct(target_st, target_addr, 1);
5126 }
5127
5128 return 0;
5129}
5130#endif
5131
pbrookbd0c5662008-05-29 14:34:11 +00005132/* ??? Using host futex calls even when target atomic operations
5133 are not really atomic probably breaks things. However implementing
5134 futexes locally would make futexes shared between multiple processes
5135 tricky. However they're probably useless because guest atomic
5136 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005137static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5138 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005139{
5140 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005141 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005142
5143 /* ??? We assume FUTEX_* constants are the same on both host
5144 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005145#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005146 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005147#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005148 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005149#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005150 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005151 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005152 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005153 if (timeout) {
5154 pts = &ts;
5155 target_to_host_timespec(pts, timeout);
5156 } else {
5157 pts = NULL;
5158 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005159 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005160 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005161 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005162 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005163 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005164 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005165 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005166 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005167 case FUTEX_WAKE_OP:
5168 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5169 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5170 But the prototype takes a `struct timespec *'; insert casts
5171 to satisfy the compiler. We do not need to tswap TIMEOUT
5172 since it's not compared to guest memory. */
5173 pts = (struct timespec *)(uintptr_t) timeout;
5174 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5175 g2h(uaddr2),
5176 (base_op == FUTEX_CMP_REQUEUE
5177 ? tswap32(val3)
5178 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005179 default:
5180 return -TARGET_ENOSYS;
5181 }
5182}
pbrookbd0c5662008-05-29 14:34:11 +00005183
pbrook1d9d8b52009-04-16 15:17:02 +00005184/* Map host to target signal numbers for the wait family of syscalls.
5185 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005186int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005187{
5188 if (WIFSIGNALED(status)) {
5189 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5190 }
5191 if (WIFSTOPPED(status)) {
5192 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5193 | (status & 0xff);
5194 }
5195 return status;
5196}
5197
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005198static int open_self_cmdline(void *cpu_env, int fd)
5199{
5200 int fd_orig = -1;
5201 bool word_skipped = false;
5202
5203 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5204 if (fd_orig < 0) {
5205 return fd_orig;
5206 }
5207
5208 while (true) {
5209 ssize_t nb_read;
5210 char buf[128];
5211 char *cp_buf = buf;
5212
5213 nb_read = read(fd_orig, buf, sizeof(buf));
5214 if (nb_read < 0) {
5215 fd_orig = close(fd_orig);
5216 return -1;
5217 } else if (nb_read == 0) {
5218 break;
5219 }
5220
5221 if (!word_skipped) {
5222 /* Skip the first string, which is the path to qemu-*-static
5223 instead of the actual command. */
5224 cp_buf = memchr(buf, 0, sizeof(buf));
5225 if (cp_buf) {
5226 /* Null byte found, skip one string */
5227 cp_buf++;
5228 nb_read -= cp_buf - buf;
5229 word_skipped = true;
5230 }
5231 }
5232
5233 if (word_skipped) {
5234 if (write(fd, cp_buf, nb_read) != nb_read) {
zhanghailiang680dfde2014-08-22 16:23:51 +08005235 close(fd_orig);
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005236 return -1;
5237 }
5238 }
5239 }
5240
5241 return close(fd_orig);
5242}
5243
Alexander Graf36c08d42011-11-02 20:23:24 +01005244static int open_self_maps(void *cpu_env, int fd)
5245{
Andreas Färber0429a972013-08-26 18:14:44 +02005246 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5247 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005248 FILE *fp;
5249 char *line = NULL;
5250 size_t len = 0;
5251 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005252
Alexander Graf1a49ef22012-05-01 16:30:28 +01005253 fp = fopen("/proc/self/maps", "r");
5254 if (fp == NULL) {
5255 return -EACCES;
5256 }
5257
5258 while ((read = getline(&line, &len, fp)) != -1) {
5259 int fields, dev_maj, dev_min, inode;
5260 uint64_t min, max, offset;
5261 char flag_r, flag_w, flag_x, flag_p;
5262 char path[512] = "";
5263 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5264 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5265 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5266
5267 if ((fields < 10) || (fields > 11)) {
5268 continue;
5269 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005270 if (h2g_valid(min)) {
5271 int flags = page_get_flags(h2g(min));
5272 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5273 if (page_check_range(h2g(min), max - min, flags) == -1) {
5274 continue;
5275 }
5276 if (h2g(min) == ts->info->stack_limit) {
5277 pstrcpy(path, sizeof(path), " [stack]");
5278 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005279 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005280 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005281 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005282 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005283 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005284 }
5285 }
5286
5287 free(line);
5288 fclose(fp);
5289
Alexander Graf36c08d42011-11-02 20:23:24 +01005290 return 0;
5291}
5292
Alexander Graf480b8e72011-11-02 20:23:25 +01005293static int open_self_stat(void *cpu_env, int fd)
5294{
Andreas Färber0429a972013-08-26 18:14:44 +02005295 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5296 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005297 abi_ulong start_stack = ts->info->start_stack;
5298 int i;
5299
5300 for (i = 0; i < 44; i++) {
5301 char buf[128];
5302 int len;
5303 uint64_t val = 0;
5304
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005305 if (i == 0) {
5306 /* pid */
5307 val = getpid();
5308 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5309 } else if (i == 1) {
5310 /* app name */
5311 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5312 } else if (i == 27) {
5313 /* stack bottom */
5314 val = start_stack;
5315 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5316 } else {
5317 /* for the rest, there is MasterCard */
5318 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005319 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005320
Alexander Graf480b8e72011-11-02 20:23:25 +01005321 len = strlen(buf);
5322 if (write(fd, buf, len) != len) {
5323 return -1;
5324 }
5325 }
5326
5327 return 0;
5328}
5329
Alexander Graf257450e2011-11-02 20:23:26 +01005330static int open_self_auxv(void *cpu_env, int fd)
5331{
Andreas Färber0429a972013-08-26 18:14:44 +02005332 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5333 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005334 abi_ulong auxv = ts->info->saved_auxv;
5335 abi_ulong len = ts->info->auxv_len;
5336 char *ptr;
5337
5338 /*
5339 * Auxiliary vector is stored in target process stack.
5340 * read in whole auxv vector and copy it to file
5341 */
5342 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5343 if (ptr != NULL) {
5344 while (len > 0) {
5345 ssize_t r;
5346 r = write(fd, ptr, len);
5347 if (r <= 0) {
5348 break;
5349 }
5350 len -= r;
5351 ptr += r;
5352 }
5353 lseek(fd, 0, SEEK_SET);
5354 unlock_user(ptr, auxv, len);
5355 }
5356
5357 return 0;
5358}
5359
Andreas Schwab463d8e72013-07-02 14:04:12 +01005360static int is_proc_myself(const char *filename, const char *entry)
5361{
5362 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5363 filename += strlen("/proc/");
5364 if (!strncmp(filename, "self/", strlen("self/"))) {
5365 filename += strlen("self/");
5366 } else if (*filename >= '1' && *filename <= '9') {
5367 char myself[80];
5368 snprintf(myself, sizeof(myself), "%d/", getpid());
5369 if (!strncmp(filename, myself, strlen(myself))) {
5370 filename += strlen(myself);
5371 } else {
5372 return 0;
5373 }
5374 } else {
5375 return 0;
5376 }
5377 if (!strcmp(filename, entry)) {
5378 return 1;
5379 }
5380 }
5381 return 0;
5382}
5383
Laurent Vivierde6b9932013-08-30 01:46:40 +02005384#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5385static int is_proc(const char *filename, const char *entry)
5386{
5387 return strcmp(filename, entry) == 0;
5388}
5389
5390static int open_net_route(void *cpu_env, int fd)
5391{
5392 FILE *fp;
5393 char *line = NULL;
5394 size_t len = 0;
5395 ssize_t read;
5396
5397 fp = fopen("/proc/net/route", "r");
5398 if (fp == NULL) {
5399 return -EACCES;
5400 }
5401
5402 /* read header */
5403
5404 read = getline(&line, &len, fp);
5405 dprintf(fd, "%s", line);
5406
5407 /* read routes */
5408
5409 while ((read = getline(&line, &len, fp)) != -1) {
5410 char iface[16];
5411 uint32_t dest, gw, mask;
5412 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5413 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5414 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5415 &mask, &mtu, &window, &irtt);
5416 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5417 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5418 metric, tswap32(mask), mtu, window, irtt);
5419 }
5420
5421 free(line);
5422 fclose(fp);
5423
5424 return 0;
5425}
5426#endif
5427
Riku Voipio0b2effd2014-08-06 10:36:37 +03005428static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005429{
5430 struct fake_open {
5431 const char *filename;
5432 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005433 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005434 };
5435 const struct fake_open *fake_open;
5436 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005437 { "maps", open_self_maps, is_proc_myself },
5438 { "stat", open_self_stat, is_proc_myself },
5439 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005440 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005441#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5442 { "/proc/net/route", open_net_route, is_proc },
5443#endif
5444 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005445 };
5446
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005447 if (is_proc_myself(pathname, "exe")) {
5448 int execfd = qemu_getauxval(AT_EXECFD);
Riku Voipio0b2effd2014-08-06 10:36:37 +03005449 return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005450 }
5451
Alexander Graf3be14d02011-11-02 20:23:23 +01005452 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005453 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005454 break;
5455 }
5456 }
5457
5458 if (fake_open->filename) {
5459 const char *tmpdir;
5460 char filename[PATH_MAX];
5461 int fd, r;
5462
5463 /* create temporary file to map stat to */
5464 tmpdir = getenv("TMPDIR");
5465 if (!tmpdir)
5466 tmpdir = "/tmp";
5467 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5468 fd = mkstemp(filename);
5469 if (fd < 0) {
5470 return fd;
5471 }
5472 unlink(filename);
5473
5474 if ((r = fake_open->fill(cpu_env, fd))) {
5475 close(fd);
5476 return r;
5477 }
5478 lseek(fd, 0, SEEK_SET);
5479
5480 return fd;
5481 }
5482
Riku Voipio0b2effd2014-08-06 10:36:37 +03005483 return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
Alexander Graf3be14d02011-11-02 20:23:23 +01005484}
5485
Alexander Grafaecc8862014-11-10 21:33:03 +01005486#define TIMER_MAGIC 0x0caf0000
5487#define TIMER_MAGIC_MASK 0xffff0000
5488
5489/* Convert QEMU provided timer ID back to internal 16bit index format */
5490static target_timer_t get_timer_id(abi_long arg)
5491{
5492 target_timer_t timerid = arg;
5493
5494 if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
5495 return -TARGET_EINVAL;
5496 }
5497
5498 timerid &= 0xffff;
5499
5500 if (timerid >= ARRAY_SIZE(g_posix_timers)) {
5501 return -TARGET_EINVAL;
5502 }
5503
5504 return timerid;
5505}
5506
ths0da46a62007-10-20 20:23:07 +00005507/* do_syscall() should always have a single exit point at the end so
5508 that actions, such as logging of syscall results, can be performed.
5509 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005510abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5511 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005512 abi_long arg5, abi_long arg6, abi_long arg7,
5513 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005514{
Andreas Färber182735e2013-05-29 22:29:20 +02005515 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005516 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005517 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005518 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005519 void *p;
ths3b46e622007-09-17 08:09:54 +00005520
bellard72f03902003-02-18 23:33:18 +00005521#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005522 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005523#endif
thsb92c47c2007-11-01 00:07:38 +00005524 if(do_strace)
5525 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5526
bellard31e31b82003-02-18 22:55:36 +00005527 switch(num) {
5528 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005529 /* In old applications this may be used to implement _exit(2).
5530 However in threaded applictions it is used for thread termination,
5531 and _exit_group is used for application termination.
5532 Do thread termination if we have more then one thread. */
5533 /* FIXME: This probably breaks if a signal arrives. We should probably
5534 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005535 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005536 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005537
Andreas Färber9b056fc2013-06-24 23:53:10 +02005538 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005539 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005540 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005541 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005542 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005543 if (ts->child_tidptr) {
5544 put_user_u32(0, ts->child_tidptr);
5545 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5546 NULL, NULL, 0);
5547 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005548 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005549 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005550 g_free(ts);
5551 pthread_exit(NULL);
5552 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005553#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005554 _mcleanup();
5555#endif
bellarde9009672005-04-26 20:42:36 +00005556 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005557 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005558 ret = 0; /* avoid warning */
5559 break;
5560 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005561 if (arg3 == 0)
5562 ret = 0;
5563 else {
5564 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5565 goto efault;
5566 ret = get_errno(read(arg1, p, arg3));
5567 unlock_user(p, arg2, ret);
5568 }
bellard31e31b82003-02-18 22:55:36 +00005569 break;
5570 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005571 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5572 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005573 ret = get_errno(write(arg1, p, arg3));
5574 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005575 break;
5576 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005577 if (!(p = lock_user_string(arg1)))
5578 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005579 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
5580 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5581 arg3));
pbrook53a59602006-03-25 19:31:22 +00005582 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005583 break;
ths82424832007-09-24 09:21:55 +00005584 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005585 if (!(p = lock_user_string(arg2)))
5586 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005587 ret = get_errno(do_openat(cpu_env, arg1, p,
5588 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5589 arg4));
bellard579a97f2007-11-11 14:26:47 +00005590 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005591 break;
bellard31e31b82003-02-18 22:55:36 +00005592 case TARGET_NR_close:
5593 ret = get_errno(close(arg1));
5594 break;
5595 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005596 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005597 break;
5598 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005599 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005600 break;
thse5febef2007-04-01 18:31:35 +00005601#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005602 case TARGET_NR_waitpid:
5603 {
pbrook53a59602006-03-25 19:31:22 +00005604 int status;
5605 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005606 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005607 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005608 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005609 }
5610 break;
thse5febef2007-04-01 18:31:35 +00005611#endif
pbrookf0cbb612008-05-30 18:20:05 +00005612#ifdef TARGET_NR_waitid
5613 case TARGET_NR_waitid:
5614 {
5615 siginfo_t info;
5616 info.si_pid = 0;
5617 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5618 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005619 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005620 goto efault;
5621 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005622 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005623 }
5624 }
5625 break;
5626#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005627#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005628 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005629 if (!(p = lock_user_string(arg1)))
5630 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005631 ret = get_errno(creat(p, arg2));
5632 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005633 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005634#endif
bellard31e31b82003-02-18 22:55:36 +00005635 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005636 {
5637 void * p2;
5638 p = lock_user_string(arg1);
5639 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005640 if (!p || !p2)
5641 ret = -TARGET_EFAULT;
5642 else
5643 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005644 unlock_user(p2, arg2, 0);
5645 unlock_user(p, arg1, 0);
5646 }
bellard31e31b82003-02-18 22:55:36 +00005647 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005648#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005649 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005650 {
5651 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005652 if (!arg2 || !arg4)
5653 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005654 p = lock_user_string(arg2);
5655 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005656 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005657 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005658 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005659 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005660 unlock_user(p, arg2, 0);
5661 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005662 }
5663 break;
5664#endif
bellard31e31b82003-02-18 22:55:36 +00005665 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005666 if (!(p = lock_user_string(arg1)))
5667 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005668 ret = get_errno(unlink(p));
5669 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005670 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005671#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005672 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005673 if (!(p = lock_user_string(arg2)))
5674 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005675 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005676 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005677 break;
balrogb7d35e62007-12-12 00:40:24 +00005678#endif
bellard31e31b82003-02-18 22:55:36 +00005679 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005680 {
5681 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005682 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005683 abi_ulong gp;
5684 abi_ulong guest_argp;
5685 abi_ulong guest_envp;
5686 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005687 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005688 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005689
bellardf7341ff2003-03-30 21:00:25 +00005690 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005691 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005692 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005693 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005694 goto efault;
ths03aa1972007-12-02 06:28:08 +00005695 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005696 break;
bellard7854b052003-03-29 17:22:23 +00005697 argc++;
bellard2f619692007-11-16 10:46:05 +00005698 }
bellardf7341ff2003-03-30 21:00:25 +00005699 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005700 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005701 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005702 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005703 goto efault;
ths03aa1972007-12-02 06:28:08 +00005704 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005705 break;
bellard7854b052003-03-29 17:22:23 +00005706 envc++;
bellard2f619692007-11-16 10:46:05 +00005707 }
bellard7854b052003-03-29 17:22:23 +00005708
bellardf7341ff2003-03-30 21:00:25 +00005709 argp = alloca((argc + 1) * sizeof(void *));
5710 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005711
pbrookda94d262008-05-30 18:24:00 +00005712 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005713 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005714 if (get_user_ual(addr, gp))
5715 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005716 if (!addr)
5717 break;
bellard2f619692007-11-16 10:46:05 +00005718 if (!(*q = lock_user_string(addr)))
5719 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005720 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005721 }
bellardf7341ff2003-03-30 21:00:25 +00005722 *q = NULL;
5723
pbrookda94d262008-05-30 18:24:00 +00005724 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005725 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005726 if (get_user_ual(addr, gp))
5727 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005728 if (!addr)
5729 break;
bellard2f619692007-11-16 10:46:05 +00005730 if (!(*q = lock_user_string(addr)))
5731 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005732 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005733 }
bellardf7341ff2003-03-30 21:00:25 +00005734 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005735
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005736 /* This case will not be caught by the host's execve() if its
5737 page size is bigger than the target's. */
5738 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5739 ret = -TARGET_E2BIG;
5740 goto execve_end;
5741 }
bellard2f619692007-11-16 10:46:05 +00005742 if (!(p = lock_user_string(arg1)))
5743 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005744 ret = get_errno(execve(p, argp, envp));
5745 unlock_user(p, arg1, 0);
5746
bellard2f619692007-11-16 10:46:05 +00005747 goto execve_end;
5748
5749 execve_efault:
5750 ret = -TARGET_EFAULT;
5751
5752 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005753 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005754 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005755 if (get_user_ual(addr, gp)
5756 || !addr)
5757 break;
pbrook53a59602006-03-25 19:31:22 +00005758 unlock_user(*q, addr, 0);
5759 }
5760 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005761 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005762 if (get_user_ual(addr, gp)
5763 || !addr)
5764 break;
pbrook53a59602006-03-25 19:31:22 +00005765 unlock_user(*q, addr, 0);
5766 }
bellard7854b052003-03-29 17:22:23 +00005767 }
bellard31e31b82003-02-18 22:55:36 +00005768 break;
5769 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005770 if (!(p = lock_user_string(arg1)))
5771 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005772 ret = get_errno(chdir(p));
5773 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005774 break;
bellarda315a142005-01-30 22:59:18 +00005775#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005776 case TARGET_NR_time:
5777 {
pbrook53a59602006-03-25 19:31:22 +00005778 time_t host_time;
5779 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005780 if (!is_error(ret)
5781 && arg1
5782 && put_user_sal(host_time, arg1))
5783 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005784 }
5785 break;
bellarda315a142005-01-30 22:59:18 +00005786#endif
bellard31e31b82003-02-18 22:55:36 +00005787 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005788 if (!(p = lock_user_string(arg1)))
5789 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005790 ret = get_errno(mknod(p, arg2, arg3));
5791 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005792 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005793#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005794 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005795 if (!(p = lock_user_string(arg2)))
5796 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005797 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005798 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005799 break;
5800#endif
bellard31e31b82003-02-18 22:55:36 +00005801 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005802 if (!(p = lock_user_string(arg1)))
5803 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005804 ret = get_errno(chmod(p, arg2));
5805 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005806 break;
bellardebc05482003-09-30 21:08:41 +00005807#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005808 case TARGET_NR_break:
5809 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005810#endif
5811#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005812 case TARGET_NR_oldstat:
5813 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005814#endif
bellard31e31b82003-02-18 22:55:36 +00005815 case TARGET_NR_lseek:
5816 ret = get_errno(lseek(arg1, arg2, arg3));
5817 break;
Richard Henderson92317332010-05-03 10:07:53 -07005818#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5819 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005820 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005821 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005822 ret = get_errno(getpid());
5823 break;
Richard Henderson92317332010-05-03 10:07:53 -07005824#endif
5825#ifdef TARGET_NR_getpid
5826 case TARGET_NR_getpid:
5827 ret = get_errno(getpid());
5828 break;
5829#endif
bellard31e31b82003-02-18 22:55:36 +00005830 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01005831 {
5832 /* need to look at the data field */
5833 void *p2, *p3;
5834
5835 if (arg1) {
5836 p = lock_user_string(arg1);
5837 if (!p) {
5838 goto efault;
5839 }
5840 } else {
5841 p = NULL;
5842 }
5843
5844 p2 = lock_user_string(arg2);
5845 if (!p2) {
5846 if (arg1) {
5847 unlock_user(p, arg1, 0);
5848 }
5849 goto efault;
5850 }
5851
5852 if (arg3) {
5853 p3 = lock_user_string(arg3);
5854 if (!p3) {
5855 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005856 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01005857 }
5858 unlock_user(p2, arg2, 0);
5859 goto efault;
5860 }
5861 } else {
5862 p3 = NULL;
5863 }
5864
5865 /* FIXME - arg5 should be locked, but it isn't clear how to
5866 * do that since it's not guaranteed to be a NULL-terminated
5867 * string.
5868 */
5869 if (!arg5) {
5870 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
5871 } else {
5872 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
5873 }
5874 ret = get_errno(ret);
5875
5876 if (arg1) {
5877 unlock_user(p, arg1, 0);
5878 }
5879 unlock_user(p2, arg2, 0);
5880 if (arg3) {
5881 unlock_user(p3, arg3, 0);
5882 }
5883 }
5884 break;
thse5febef2007-04-01 18:31:35 +00005885#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005886 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005887 if (!(p = lock_user_string(arg1)))
5888 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005889 ret = get_errno(umount(p));
5890 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005891 break;
thse5febef2007-04-01 18:31:35 +00005892#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005893#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005894 case TARGET_NR_stime:
5895 {
pbrook53a59602006-03-25 19:31:22 +00005896 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005897 if (get_user_sal(host_time, arg1))
5898 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005899 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005900 }
5901 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005902#endif
bellard31e31b82003-02-18 22:55:36 +00005903 case TARGET_NR_ptrace:
5904 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005905#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005906 case TARGET_NR_alarm:
5907 ret = alarm(arg1);
5908 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005909#endif
bellardebc05482003-09-30 21:08:41 +00005910#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005911 case TARGET_NR_oldfstat:
5912 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005913#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005914#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005915 case TARGET_NR_pause:
5916 ret = get_errno(pause());
5917 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005918#endif
thse5febef2007-04-01 18:31:35 +00005919#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005920 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005921 {
pbrook53a59602006-03-25 19:31:22 +00005922 struct utimbuf tbuf, *host_tbuf;
5923 struct target_utimbuf *target_tbuf;
5924 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005925 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5926 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005927 tbuf.actime = tswapal(target_tbuf->actime);
5928 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005929 unlock_user_struct(target_tbuf, arg2, 0);
5930 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005931 } else {
pbrook53a59602006-03-25 19:31:22 +00005932 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005933 }
bellard579a97f2007-11-11 14:26:47 +00005934 if (!(p = lock_user_string(arg1)))
5935 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005936 ret = get_errno(utime(p, host_tbuf));
5937 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005938 }
5939 break;
thse5febef2007-04-01 18:31:35 +00005940#endif
bellard978a66f2004-12-06 22:58:05 +00005941 case TARGET_NR_utimes:
5942 {
bellard978a66f2004-12-06 22:58:05 +00005943 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005944 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005945 if (copy_from_user_timeval(&tv[0], arg2)
5946 || copy_from_user_timeval(&tv[1],
5947 arg2 + sizeof(struct target_timeval)))
5948 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005949 tvp = tv;
5950 } else {
5951 tvp = NULL;
5952 }
bellard579a97f2007-11-11 14:26:47 +00005953 if (!(p = lock_user_string(arg1)))
5954 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005955 ret = get_errno(utimes(p, tvp));
5956 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005957 }
5958 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005959#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005960 case TARGET_NR_futimesat:
5961 {
5962 struct timeval *tvp, tv[2];
5963 if (arg3) {
5964 if (copy_from_user_timeval(&tv[0], arg3)
5965 || copy_from_user_timeval(&tv[1],
5966 arg3 + sizeof(struct target_timeval)))
5967 goto efault;
5968 tvp = tv;
5969 } else {
5970 tvp = NULL;
5971 }
5972 if (!(p = lock_user_string(arg2)))
5973 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005974 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005975 unlock_user(p, arg2, 0);
5976 }
5977 break;
5978#endif
bellardebc05482003-09-30 21:08:41 +00005979#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005980 case TARGET_NR_stty:
5981 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005982#endif
5983#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005984 case TARGET_NR_gtty:
5985 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005986#endif
bellard31e31b82003-02-18 22:55:36 +00005987 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005988 if (!(p = lock_user_string(arg1)))
5989 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005990 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005991 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005992 break;
ths92a34c12007-09-24 09:27:49 +00005993#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5994 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005995 if (!(p = lock_user_string(arg2)))
5996 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005997 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005998 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005999 break;
6000#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006001#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006002 case TARGET_NR_nice:
6003 ret = get_errno(nice(arg1));
6004 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006005#endif
bellardebc05482003-09-30 21:08:41 +00006006#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00006007 case TARGET_NR_ftime:
6008 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006009#endif
bellard31e31b82003-02-18 22:55:36 +00006010 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00006011 sync();
6012 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00006013 break;
6014 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00006015 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00006016 break;
6017 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00006018 {
6019 void *p2;
6020 p = lock_user_string(arg1);
6021 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006022 if (!p || !p2)
6023 ret = -TARGET_EFAULT;
6024 else
6025 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006026 unlock_user(p2, arg2, 0);
6027 unlock_user(p, arg1, 0);
6028 }
bellard31e31b82003-02-18 22:55:36 +00006029 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006030#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00006031 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00006032 {
bellard579a97f2007-11-11 14:26:47 +00006033 void *p2;
ths722183f2007-09-24 09:24:37 +00006034 p = lock_user_string(arg2);
6035 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00006036 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006037 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00006038 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006039 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00006040 unlock_user(p2, arg4, 0);
6041 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00006042 }
6043 break;
6044#endif
bellard31e31b82003-02-18 22:55:36 +00006045 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00006046 if (!(p = lock_user_string(arg1)))
6047 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006048 ret = get_errno(mkdir(p, arg2));
6049 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006050 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006051#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00006052 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00006053 if (!(p = lock_user_string(arg2)))
6054 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006055 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00006056 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00006057 break;
6058#endif
bellard31e31b82003-02-18 22:55:36 +00006059 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00006060 if (!(p = lock_user_string(arg1)))
6061 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006062 ret = get_errno(rmdir(p));
6063 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006064 break;
6065 case TARGET_NR_dup:
6066 ret = get_errno(dup(arg1));
6067 break;
6068 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07006069 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00006070 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03006071#ifdef TARGET_NR_pipe2
6072 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07006073 ret = do_pipe(cpu_env, arg1,
6074 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03006075 break;
6076#endif
bellard31e31b82003-02-18 22:55:36 +00006077 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00006078 {
pbrook53a59602006-03-25 19:31:22 +00006079 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00006080 struct tms tms;
6081 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00006082 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00006083 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
6084 if (!tmsp)
6085 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006086 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
6087 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
6088 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
6089 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00006090 }
bellardc596ed12003-07-13 17:32:31 +00006091 if (!is_error(ret))
6092 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00006093 }
6094 break;
bellardebc05482003-09-30 21:08:41 +00006095#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00006096 case TARGET_NR_prof:
6097 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006098#endif
thse5febef2007-04-01 18:31:35 +00006099#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00006100 case TARGET_NR_signal:
6101 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006102#endif
bellard31e31b82003-02-18 22:55:36 +00006103 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00006104 if (arg1 == 0) {
6105 ret = get_errno(acct(NULL));
6106 } else {
6107 if (!(p = lock_user_string(arg1)))
6108 goto efault;
6109 ret = get_errno(acct(path(p)));
6110 unlock_user(p, arg1, 0);
6111 }
pbrook24836682006-04-16 14:14:53 +00006112 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10006113#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00006114 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00006115 if (!(p = lock_user_string(arg1)))
6116 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006117 ret = get_errno(umount2(p, arg2));
6118 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006119 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006120#endif
bellardebc05482003-09-30 21:08:41 +00006121#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00006122 case TARGET_NR_lock:
6123 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006124#endif
bellard31e31b82003-02-18 22:55:36 +00006125 case TARGET_NR_ioctl:
6126 ret = do_ioctl(arg1, arg2, arg3);
6127 break;
6128 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00006129 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00006130 break;
bellardebc05482003-09-30 21:08:41 +00006131#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00006132 case TARGET_NR_mpx:
6133 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006134#endif
bellard31e31b82003-02-18 22:55:36 +00006135 case TARGET_NR_setpgid:
6136 ret = get_errno(setpgid(arg1, arg2));
6137 break;
bellardebc05482003-09-30 21:08:41 +00006138#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00006139 case TARGET_NR_ulimit:
6140 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006141#endif
6142#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00006143 case TARGET_NR_oldolduname:
6144 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006145#endif
bellard31e31b82003-02-18 22:55:36 +00006146 case TARGET_NR_umask:
6147 ret = get_errno(umask(arg1));
6148 break;
6149 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006150 if (!(p = lock_user_string(arg1)))
6151 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006152 ret = get_errno(chroot(p));
6153 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006154 break;
6155 case TARGET_NR_ustat:
6156 goto unimplemented;
6157 case TARGET_NR_dup2:
6158 ret = get_errno(dup2(arg1, arg2));
6159 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03006160#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6161 case TARGET_NR_dup3:
6162 ret = get_errno(dup3(arg1, arg2, arg3));
6163 break;
6164#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006165#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006166 case TARGET_NR_getppid:
6167 ret = get_errno(getppid());
6168 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006169#endif
bellard31e31b82003-02-18 22:55:36 +00006170 case TARGET_NR_getpgrp:
6171 ret = get_errno(getpgrp());
6172 break;
6173 case TARGET_NR_setsid:
6174 ret = get_errno(setsid());
6175 break;
thse5febef2007-04-01 18:31:35 +00006176#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006177 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006178 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006179#if defined(TARGET_ALPHA)
6180 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006181 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006182 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006183 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6184 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006185 act._sa_handler = old_act->_sa_handler;
6186 target_siginitset(&act.sa_mask, old_act->sa_mask);
6187 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006188 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006189 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006190 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006191 }
6192 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006193 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006194 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6195 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006196 old_act->_sa_handler = oact._sa_handler;
6197 old_act->sa_mask = oact.sa_mask.sig[0];
6198 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006199 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006200 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006201#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006202 struct target_sigaction act, oact, *pact, *old_act;
6203
6204 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006205 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6206 goto efault;
bellard106ec872006-06-27 21:08:10 +00006207 act._sa_handler = old_act->_sa_handler;
6208 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6209 act.sa_flags = old_act->sa_flags;
6210 unlock_user_struct(old_act, arg2, 0);
6211 pact = &act;
6212 } else {
6213 pact = NULL;
6214 }
6215
6216 ret = get_errno(do_sigaction(arg1, pact, &oact));
6217
6218 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006219 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6220 goto efault;
bellard106ec872006-06-27 21:08:10 +00006221 old_act->_sa_handler = oact._sa_handler;
6222 old_act->sa_flags = oact.sa_flags;
6223 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6224 old_act->sa_mask.sig[1] = 0;
6225 old_act->sa_mask.sig[2] = 0;
6226 old_act->sa_mask.sig[3] = 0;
6227 unlock_user_struct(old_act, arg3, 1);
6228 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006229#else
6230 struct target_old_sigaction *old_act;
6231 struct target_sigaction act, oact, *pact;
6232 if (arg2) {
6233 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6234 goto efault;
6235 act._sa_handler = old_act->_sa_handler;
6236 target_siginitset(&act.sa_mask, old_act->sa_mask);
6237 act.sa_flags = old_act->sa_flags;
6238 act.sa_restorer = old_act->sa_restorer;
6239 unlock_user_struct(old_act, arg2, 0);
6240 pact = &act;
6241 } else {
6242 pact = NULL;
6243 }
6244 ret = get_errno(do_sigaction(arg1, pact, &oact));
6245 if (!is_error(ret) && arg3) {
6246 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6247 goto efault;
6248 old_act->_sa_handler = oact._sa_handler;
6249 old_act->sa_mask = oact.sa_mask.sig[0];
6250 old_act->sa_flags = oact.sa_flags;
6251 old_act->sa_restorer = oact.sa_restorer;
6252 unlock_user_struct(old_act, arg3, 1);
6253 }
ths388bb212007-05-13 13:58:00 +00006254#endif
bellard31e31b82003-02-18 22:55:36 +00006255 }
6256 break;
thse5febef2007-04-01 18:31:35 +00006257#endif
bellard66fb9762003-03-23 01:06:05 +00006258 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006259 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006260#if defined(TARGET_ALPHA)
6261 struct target_sigaction act, oact, *pact = 0;
6262 struct target_rt_sigaction *rt_act;
6263 /* ??? arg4 == sizeof(sigset_t). */
6264 if (arg2) {
6265 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6266 goto efault;
6267 act._sa_handler = rt_act->_sa_handler;
6268 act.sa_mask = rt_act->sa_mask;
6269 act.sa_flags = rt_act->sa_flags;
6270 act.sa_restorer = arg5;
6271 unlock_user_struct(rt_act, arg2, 0);
6272 pact = &act;
6273 }
6274 ret = get_errno(do_sigaction(arg1, pact, &oact));
6275 if (!is_error(ret) && arg3) {
6276 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6277 goto efault;
6278 rt_act->_sa_handler = oact._sa_handler;
6279 rt_act->sa_mask = oact.sa_mask;
6280 rt_act->sa_flags = oact.sa_flags;
6281 unlock_user_struct(rt_act, arg3, 1);
6282 }
6283#else
pbrook53a59602006-03-25 19:31:22 +00006284 struct target_sigaction *act;
6285 struct target_sigaction *oact;
6286
bellard579a97f2007-11-11 14:26:47 +00006287 if (arg2) {
6288 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6289 goto efault;
6290 } else
pbrook53a59602006-03-25 19:31:22 +00006291 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006292 if (arg3) {
6293 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6294 ret = -TARGET_EFAULT;
6295 goto rt_sigaction_fail;
6296 }
6297 } else
pbrook53a59602006-03-25 19:31:22 +00006298 oact = NULL;
6299 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006300 rt_sigaction_fail:
6301 if (act)
pbrook53a59602006-03-25 19:31:22 +00006302 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006303 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006304 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006305#endif
pbrook53a59602006-03-25 19:31:22 +00006306 }
bellard66fb9762003-03-23 01:06:05 +00006307 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006308#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006309 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006310 {
6311 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006312 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006313 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006314 host_to_target_old_sigset(&target_set, &cur_set);
6315 ret = target_set;
6316 }
6317 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006318#endif
6319#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006320 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006321 {
6322 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006323 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006324 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006325 target_to_host_old_sigset(&set, &target_set);
6326 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006327 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006328 host_to_target_old_sigset(&target_set, &oset);
6329 ret = target_set;
6330 }
6331 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006332#endif
thse5febef2007-04-01 18:31:35 +00006333#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006334 case TARGET_NR_sigprocmask:
6335 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006336#if defined(TARGET_ALPHA)
6337 sigset_t set, oldset;
6338 abi_ulong mask;
6339 int how;
6340
6341 switch (arg1) {
6342 case TARGET_SIG_BLOCK:
6343 how = SIG_BLOCK;
6344 break;
6345 case TARGET_SIG_UNBLOCK:
6346 how = SIG_UNBLOCK;
6347 break;
6348 case TARGET_SIG_SETMASK:
6349 how = SIG_SETMASK;
6350 break;
6351 default:
6352 ret = -TARGET_EINVAL;
6353 goto fail;
6354 }
6355 mask = arg2;
6356 target_to_host_old_sigset(&set, &mask);
6357
Alex Barcelo1c275922014-03-14 14:36:55 +00006358 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006359 if (!is_error(ret)) {
6360 host_to_target_old_sigset(&mask, &oldset);
6361 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006362 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006363 }
6364#else
bellard66fb9762003-03-23 01:06:05 +00006365 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006366 int how;
ths3b46e622007-09-17 08:09:54 +00006367
pbrook53a59602006-03-25 19:31:22 +00006368 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006369 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006370 case TARGET_SIG_BLOCK:
6371 how = SIG_BLOCK;
6372 break;
6373 case TARGET_SIG_UNBLOCK:
6374 how = SIG_UNBLOCK;
6375 break;
6376 case TARGET_SIG_SETMASK:
6377 how = SIG_SETMASK;
6378 break;
6379 default:
ths0da46a62007-10-20 20:23:07 +00006380 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006381 goto fail;
6382 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006383 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006384 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006385 target_to_host_old_sigset(&set, p);
6386 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006387 set_ptr = &set;
6388 } else {
6389 how = 0;
6390 set_ptr = NULL;
6391 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006392 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006393 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006394 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006395 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006396 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006397 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006398 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006399#endif
bellard66fb9762003-03-23 01:06:05 +00006400 }
6401 break;
thse5febef2007-04-01 18:31:35 +00006402#endif
bellard66fb9762003-03-23 01:06:05 +00006403 case TARGET_NR_rt_sigprocmask:
6404 {
6405 int how = arg1;
6406 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006407
pbrook53a59602006-03-25 19:31:22 +00006408 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006409 switch(how) {
6410 case TARGET_SIG_BLOCK:
6411 how = SIG_BLOCK;
6412 break;
6413 case TARGET_SIG_UNBLOCK:
6414 how = SIG_UNBLOCK;
6415 break;
6416 case TARGET_SIG_SETMASK:
6417 how = SIG_SETMASK;
6418 break;
6419 default:
ths0da46a62007-10-20 20:23:07 +00006420 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006421 goto fail;
6422 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006423 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006424 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006425 target_to_host_sigset(&set, p);
6426 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006427 set_ptr = &set;
6428 } else {
6429 how = 0;
6430 set_ptr = NULL;
6431 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006432 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006433 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006434 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006435 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006436 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006437 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006438 }
6439 }
6440 break;
thse5febef2007-04-01 18:31:35 +00006441#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006442 case TARGET_NR_sigpending:
6443 {
6444 sigset_t set;
6445 ret = get_errno(sigpending(&set));
6446 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006447 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006448 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006449 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006450 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006451 }
6452 }
6453 break;
thse5febef2007-04-01 18:31:35 +00006454#endif
bellard66fb9762003-03-23 01:06:05 +00006455 case TARGET_NR_rt_sigpending:
6456 {
6457 sigset_t set;
6458 ret = get_errno(sigpending(&set));
6459 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006460 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006461 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006462 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006463 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006464 }
6465 }
6466 break;
thse5febef2007-04-01 18:31:35 +00006467#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006468 case TARGET_NR_sigsuspend:
6469 {
6470 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006471#if defined(TARGET_ALPHA)
6472 abi_ulong mask = arg1;
6473 target_to_host_old_sigset(&set, &mask);
6474#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006475 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006476 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006477 target_to_host_old_sigset(&set, p);
6478 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006479#endif
bellard66fb9762003-03-23 01:06:05 +00006480 ret = get_errno(sigsuspend(&set));
6481 }
6482 break;
thse5febef2007-04-01 18:31:35 +00006483#endif
bellard66fb9762003-03-23 01:06:05 +00006484 case TARGET_NR_rt_sigsuspend:
6485 {
6486 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006487 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006488 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006489 target_to_host_sigset(&set, p);
6490 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006491 ret = get_errno(sigsuspend(&set));
6492 }
6493 break;
6494 case TARGET_NR_rt_sigtimedwait:
6495 {
bellard66fb9762003-03-23 01:06:05 +00006496 sigset_t set;
6497 struct timespec uts, *puts;
6498 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006499
Anthony Liguoric227f092009-10-01 16:12:16 -05006500 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006501 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006502 target_to_host_sigset(&set, p);
6503 unlock_user(p, arg1, 0);
6504 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006505 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006506 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006507 } else {
6508 puts = NULL;
6509 }
6510 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006511 if (!is_error(ret)) {
6512 if (arg2) {
6513 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6514 0);
6515 if (!p) {
6516 goto efault;
6517 }
6518 host_to_target_siginfo(p, &uinfo);
6519 unlock_user(p, arg2, sizeof(target_siginfo_t));
6520 }
6521 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006522 }
6523 }
6524 break;
6525 case TARGET_NR_rt_sigqueueinfo:
6526 {
6527 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006528 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006529 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006530 target_to_host_siginfo(&uinfo, p);
6531 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006532 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6533 }
6534 break;
thse5febef2007-04-01 18:31:35 +00006535#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006536 case TARGET_NR_sigreturn:
6537 /* NOTE: ret is eax, so not transcoding must be done */
6538 ret = do_sigreturn(cpu_env);
6539 break;
thse5febef2007-04-01 18:31:35 +00006540#endif
bellard66fb9762003-03-23 01:06:05 +00006541 case TARGET_NR_rt_sigreturn:
6542 /* NOTE: ret is eax, so not transcoding must be done */
6543 ret = do_rt_sigreturn(cpu_env);
6544 break;
bellard31e31b82003-02-18 22:55:36 +00006545 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006546 if (!(p = lock_user_string(arg1)))
6547 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006548 ret = get_errno(sethostname(p, arg2));
6549 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006550 break;
6551 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006552 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006553 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006554 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006555 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006556 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6557 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006558 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6559 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006560 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006561 ret = get_errno(setrlimit(resource, &rlim));
6562 }
6563 break;
bellard31e31b82003-02-18 22:55:36 +00006564 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006565 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006566 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006567 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006568 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006569
bellard9de5e442003-03-23 16:49:39 +00006570 ret = get_errno(getrlimit(resource, &rlim));
6571 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006572 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6573 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006574 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6575 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006576 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006577 }
6578 }
6579 break;
bellard31e31b82003-02-18 22:55:36 +00006580 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006581 {
6582 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006583 ret = get_errno(getrusage(arg1, &rusage));
6584 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006585 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006586 }
6587 }
6588 break;
bellard31e31b82003-02-18 22:55:36 +00006589 case TARGET_NR_gettimeofday:
6590 {
bellard31e31b82003-02-18 22:55:36 +00006591 struct timeval tv;
6592 ret = get_errno(gettimeofday(&tv, NULL));
6593 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006594 if (copy_to_user_timeval(arg1, &tv))
6595 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006596 }
6597 }
6598 break;
6599 case TARGET_NR_settimeofday:
6600 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006601 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006602 struct timezone tz, *ptz = NULL;
6603
Paul Burtonb67d8032014-06-22 11:25:41 +01006604 if (arg1) {
6605 if (copy_from_user_timeval(&tv, arg1)) {
6606 goto efault;
6607 }
6608 ptv = &tv;
6609 }
Paul Burtonef4467e2014-06-22 11:25:40 +01006610
6611 if (arg2) {
6612 if (copy_from_user_timezone(&tz, arg2)) {
6613 goto efault;
6614 }
6615 ptz = &tz;
6616 }
6617
Paul Burtonb67d8032014-06-22 11:25:41 +01006618 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00006619 }
6620 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006621#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006622 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006623#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6624 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6625#else
bellardf2674e32003-07-09 12:26:09 +00006626 {
pbrook53a59602006-03-25 19:31:22 +00006627 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006628 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006629 long nsel;
6630
bellard579a97f2007-11-11 14:26:47 +00006631 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6632 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006633 nsel = tswapal(sel->n);
6634 inp = tswapal(sel->inp);
6635 outp = tswapal(sel->outp);
6636 exp = tswapal(sel->exp);
6637 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006638 unlock_user_struct(sel, arg1, 0);
6639 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006640 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006641#endif
bellardf2674e32003-07-09 12:26:09 +00006642 break;
bellard048f6b42005-11-26 18:47:20 +00006643#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006644#ifdef TARGET_NR_pselect6
6645 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006646 {
6647 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6648 fd_set rfds, wfds, efds;
6649 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6650 struct timespec ts, *ts_ptr;
6651
6652 /*
6653 * The 6th arg is actually two args smashed together,
6654 * so we cannot use the C library.
6655 */
6656 sigset_t set;
6657 struct {
6658 sigset_t *set;
6659 size_t size;
6660 } sig, *sig_ptr;
6661
6662 abi_ulong arg_sigset, arg_sigsize, *arg7;
6663 target_sigset_t *target_sigset;
6664
6665 n = arg1;
6666 rfd_addr = arg2;
6667 wfd_addr = arg3;
6668 efd_addr = arg4;
6669 ts_addr = arg5;
6670
6671 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6672 if (ret) {
6673 goto fail;
6674 }
6675 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6676 if (ret) {
6677 goto fail;
6678 }
6679 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6680 if (ret) {
6681 goto fail;
6682 }
6683
6684 /*
6685 * This takes a timespec, and not a timeval, so we cannot
6686 * use the do_select() helper ...
6687 */
6688 if (ts_addr) {
6689 if (target_to_host_timespec(&ts, ts_addr)) {
6690 goto efault;
6691 }
6692 ts_ptr = &ts;
6693 } else {
6694 ts_ptr = NULL;
6695 }
6696
6697 /* Extract the two packed args for the sigset */
6698 if (arg6) {
6699 sig_ptr = &sig;
6700 sig.size = _NSIG / 8;
6701
6702 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6703 if (!arg7) {
6704 goto efault;
6705 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006706 arg_sigset = tswapal(arg7[0]);
6707 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006708 unlock_user(arg7, arg6, 0);
6709
6710 if (arg_sigset) {
6711 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006712 if (arg_sigsize != sizeof(*target_sigset)) {
6713 /* Like the kernel, we enforce correct size sigsets */
6714 ret = -TARGET_EINVAL;
6715 goto fail;
6716 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006717 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6718 sizeof(*target_sigset), 1);
6719 if (!target_sigset) {
6720 goto efault;
6721 }
6722 target_to_host_sigset(&set, target_sigset);
6723 unlock_user(target_sigset, arg_sigset, 0);
6724 } else {
6725 sig.set = NULL;
6726 }
6727 } else {
6728 sig_ptr = NULL;
6729 }
6730
6731 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6732 ts_ptr, sig_ptr));
6733
6734 if (!is_error(ret)) {
6735 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6736 goto efault;
6737 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6738 goto efault;
6739 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6740 goto efault;
6741
6742 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6743 goto efault;
6744 }
6745 }
6746 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006747#endif
bellard31e31b82003-02-18 22:55:36 +00006748 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006749 {
6750 void *p2;
6751 p = lock_user_string(arg1);
6752 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006753 if (!p || !p2)
6754 ret = -TARGET_EFAULT;
6755 else
6756 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006757 unlock_user(p2, arg2, 0);
6758 unlock_user(p, arg1, 0);
6759 }
bellard31e31b82003-02-18 22:55:36 +00006760 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006761#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006762 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006763 {
bellard579a97f2007-11-11 14:26:47 +00006764 void *p2;
thsf0b62432007-09-24 09:25:40 +00006765 p = lock_user_string(arg1);
6766 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006767 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006768 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006769 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006770 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006771 unlock_user(p2, arg3, 0);
6772 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006773 }
6774 break;
6775#endif
bellardebc05482003-09-30 21:08:41 +00006776#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006777 case TARGET_NR_oldlstat:
6778 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006779#endif
bellard31e31b82003-02-18 22:55:36 +00006780 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006781 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006782 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006783 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006784 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006785 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006786 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09006787 } else if (!arg3) {
6788 /* Short circuit this for the magic exe check. */
6789 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006790 } else if (is_proc_myself((const char *)p, "exe")) {
6791 char real[PATH_MAX], *temp;
6792 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09006793 /* Return value is # of bytes that we wrote to the buffer. */
6794 if (temp == NULL) {
6795 ret = get_errno(-1);
6796 } else {
6797 /* Don't worry about sign mismatch as earlier mapping
6798 * logic would have thrown a bad address error. */
6799 ret = MIN(strlen(real), arg3);
6800 /* We cannot NUL terminate the string. */
6801 memcpy(p2, real, ret);
6802 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01006803 } else {
6804 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006805 }
pbrook53a59602006-03-25 19:31:22 +00006806 unlock_user(p2, arg2, ret);
6807 unlock_user(p, arg1, 0);
6808 }
bellard31e31b82003-02-18 22:55:36 +00006809 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006810#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006811 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006812 {
bellard579a97f2007-11-11 14:26:47 +00006813 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006814 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006815 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006816 if (!p || !p2) {
6817 ret = -TARGET_EFAULT;
6818 } else if (is_proc_myself((const char *)p, "exe")) {
6819 char real[PATH_MAX], *temp;
6820 temp = realpath(exec_path, real);
6821 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6822 snprintf((char *)p2, arg4, "%s", real);
6823 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006824 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006825 }
bellard579a97f2007-11-11 14:26:47 +00006826 unlock_user(p2, arg3, ret);
6827 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006828 }
6829 break;
6830#endif
thse5febef2007-04-01 18:31:35 +00006831#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006832 case TARGET_NR_uselib:
6833 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006834#endif
6835#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006836 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006837 if (!(p = lock_user_string(arg1)))
6838 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006839 ret = get_errno(swapon(p, arg2));
6840 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006841 break;
thse5febef2007-04-01 18:31:35 +00006842#endif
bellard31e31b82003-02-18 22:55:36 +00006843 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006844 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6845 /* arg4 must be ignored in all other cases */
6846 p = lock_user_string(arg4);
6847 if (!p) {
6848 goto efault;
6849 }
6850 ret = get_errno(reboot(arg1, arg2, arg3, p));
6851 unlock_user(p, arg4, 0);
6852 } else {
6853 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6854 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006855 break;
thse5febef2007-04-01 18:31:35 +00006856#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006857 case TARGET_NR_readdir:
6858 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006859#endif
6860#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006861 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006862#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6863 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006864 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6865 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006866 {
blueswir1992f48a2007-10-14 16:27:31 +00006867 abi_ulong *v;
6868 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006869 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6870 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006871 v1 = tswapal(v[0]);
6872 v2 = tswapal(v[1]);
6873 v3 = tswapal(v[2]);
6874 v4 = tswapal(v[3]);
6875 v5 = tswapal(v[4]);
6876 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006877 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006878 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006879 target_to_host_bitmask(v4, mmap_flags_tbl),
6880 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006881 }
bellard31e31b82003-02-18 22:55:36 +00006882#else
ths5fafdf22007-09-16 21:08:06 +00006883 ret = get_errno(target_mmap(arg1, arg2, arg3,
6884 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006885 arg5,
6886 arg6));
bellard31e31b82003-02-18 22:55:36 +00006887#endif
bellard6fb883e2003-07-09 17:12:39 +00006888 break;
thse5febef2007-04-01 18:31:35 +00006889#endif
bellarda315a142005-01-30 22:59:18 +00006890#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006891 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006892#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006893#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006894#endif
ths5fafdf22007-09-16 21:08:06 +00006895 ret = get_errno(target_mmap(arg1, arg2, arg3,
6896 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006897 arg5,
bellardc573ff62004-01-04 15:51:36 +00006898 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006899 break;
bellarda315a142005-01-30 22:59:18 +00006900#endif
bellard31e31b82003-02-18 22:55:36 +00006901 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006902 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006903 break;
bellard9de5e442003-03-23 16:49:39 +00006904 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006905 {
Andreas Färber0429a972013-08-26 18:14:44 +02006906 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006907 /* Special hack to detect libc making the stack executable. */
6908 if ((arg3 & PROT_GROWSDOWN)
6909 && arg1 >= ts->info->stack_limit
6910 && arg1 <= ts->info->start_stack) {
6911 arg3 &= ~PROT_GROWSDOWN;
6912 arg2 = arg2 + arg1 - ts->info->stack_limit;
6913 arg1 = ts->info->stack_limit;
6914 }
6915 }
bellard54936002003-05-13 00:25:15 +00006916 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006917 break;
thse5febef2007-04-01 18:31:35 +00006918#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006919 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006920 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006921 break;
thse5febef2007-04-01 18:31:35 +00006922#endif
pbrook53a59602006-03-25 19:31:22 +00006923 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006924#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006925 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006926 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006927 break;
thse5febef2007-04-01 18:31:35 +00006928#endif
6929#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006930 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006931 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006932 break;
thse5febef2007-04-01 18:31:35 +00006933#endif
6934#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006935 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006936 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006937 break;
thse5febef2007-04-01 18:31:35 +00006938#endif
6939#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006940 case TARGET_NR_mlockall:
Tom Musta6f6a4032014-08-12 13:53:42 -05006941 ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
bellard9de5e442003-03-23 16:49:39 +00006942 break;
thse5febef2007-04-01 18:31:35 +00006943#endif
6944#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006945 case TARGET_NR_munlockall:
6946 ret = get_errno(munlockall());
6947 break;
thse5febef2007-04-01 18:31:35 +00006948#endif
bellard31e31b82003-02-18 22:55:36 +00006949 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006950 if (!(p = lock_user_string(arg1)))
6951 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006952 ret = get_errno(truncate(p, arg2));
6953 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006954 break;
6955 case TARGET_NR_ftruncate:
6956 ret = get_errno(ftruncate(arg1, arg2));
6957 break;
6958 case TARGET_NR_fchmod:
6959 ret = get_errno(fchmod(arg1, arg2));
6960 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006961#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006962 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006963 if (!(p = lock_user_string(arg2)))
6964 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006965 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006966 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006967 break;
6968#endif
bellard31e31b82003-02-18 22:55:36 +00006969 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006970 /* Note that negative values are valid for getpriority, so we must
6971 differentiate based on errno settings. */
6972 errno = 0;
6973 ret = getpriority(arg1, arg2);
6974 if (ret == -1 && errno != 0) {
6975 ret = -host_to_target_errno(errno);
6976 break;
6977 }
6978#ifdef TARGET_ALPHA
6979 /* Return value is the unbiased priority. Signal no error. */
6980 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6981#else
6982 /* Return value is a biased priority to avoid negative numbers. */
6983 ret = 20 - ret;
6984#endif
bellard31e31b82003-02-18 22:55:36 +00006985 break;
6986 case TARGET_NR_setpriority:
6987 ret = get_errno(setpriority(arg1, arg2, arg3));
6988 break;
bellardebc05482003-09-30 21:08:41 +00006989#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006990 case TARGET_NR_profil:
6991 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006992#endif
bellard31e31b82003-02-18 22:55:36 +00006993 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006994 if (!(p = lock_user_string(arg1)))
6995 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006996 ret = get_errno(statfs(path(p), &stfs));
6997 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006998 convert_statfs:
6999 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007000 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007001
bellard579a97f2007-11-11 14:26:47 +00007002 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
7003 goto efault;
7004 __put_user(stfs.f_type, &target_stfs->f_type);
7005 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7006 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7007 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7008 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7009 __put_user(stfs.f_files, &target_stfs->f_files);
7010 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7011 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7012 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7013 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007014 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7015 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00007016 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007017 }
7018 break;
7019 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00007020 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00007021 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00007022#ifdef TARGET_NR_statfs64
7023 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00007024 if (!(p = lock_user_string(arg1)))
7025 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007026 ret = get_errno(statfs(path(p), &stfs));
7027 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00007028 convert_statfs64:
7029 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007030 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00007031
bellard579a97f2007-11-11 14:26:47 +00007032 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
7033 goto efault;
7034 __put_user(stfs.f_type, &target_stfs->f_type);
7035 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
7036 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
7037 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
7038 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
7039 __put_user(stfs.f_files, &target_stfs->f_files);
7040 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
7041 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
7042 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
7043 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02007044 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
7045 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00007046 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00007047 }
7048 break;
7049 case TARGET_NR_fstatfs64:
7050 ret = get_errno(fstatfs(arg1, &stfs));
7051 goto convert_statfs64;
7052#endif
bellardebc05482003-09-30 21:08:41 +00007053#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00007054 case TARGET_NR_ioperm:
7055 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007056#endif
thse5febef2007-04-01 18:31:35 +00007057#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00007058 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00007059 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00007060 break;
thse5febef2007-04-01 18:31:35 +00007061#endif
bellard3532fa72006-06-24 15:06:03 +00007062#ifdef TARGET_NR_accept
7063 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00007064 ret = do_accept4(arg1, arg2, arg3, 0);
7065 break;
7066#endif
7067#ifdef TARGET_NR_accept4
7068 case TARGET_NR_accept4:
7069#ifdef CONFIG_ACCEPT4
7070 ret = do_accept4(arg1, arg2, arg3, arg4);
7071#else
7072 goto unimplemented;
7073#endif
bellard3532fa72006-06-24 15:06:03 +00007074 break;
7075#endif
7076#ifdef TARGET_NR_bind
7077 case TARGET_NR_bind:
7078 ret = do_bind(arg1, arg2, arg3);
7079 break;
7080#endif
7081#ifdef TARGET_NR_connect
7082 case TARGET_NR_connect:
7083 ret = do_connect(arg1, arg2, arg3);
7084 break;
7085#endif
7086#ifdef TARGET_NR_getpeername
7087 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00007088 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007089 break;
7090#endif
7091#ifdef TARGET_NR_getsockname
7092 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00007093 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00007094 break;
7095#endif
7096#ifdef TARGET_NR_getsockopt
7097 case TARGET_NR_getsockopt:
7098 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
7099 break;
7100#endif
7101#ifdef TARGET_NR_listen
7102 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00007103 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007104 break;
7105#endif
7106#ifdef TARGET_NR_recv
7107 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00007108 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007109 break;
7110#endif
7111#ifdef TARGET_NR_recvfrom
7112 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00007113 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007114 break;
7115#endif
7116#ifdef TARGET_NR_recvmsg
7117 case TARGET_NR_recvmsg:
7118 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
7119 break;
7120#endif
7121#ifdef TARGET_NR_send
7122 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00007123 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00007124 break;
7125#endif
7126#ifdef TARGET_NR_sendmsg
7127 case TARGET_NR_sendmsg:
7128 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
7129 break;
7130#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00007131#ifdef TARGET_NR_sendmmsg
7132 case TARGET_NR_sendmmsg:
7133 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
7134 break;
7135 case TARGET_NR_recvmmsg:
7136 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
7137 break;
7138#endif
bellard3532fa72006-06-24 15:06:03 +00007139#ifdef TARGET_NR_sendto
7140 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00007141 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00007142 break;
7143#endif
7144#ifdef TARGET_NR_shutdown
7145 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00007146 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007147 break;
7148#endif
7149#ifdef TARGET_NR_socket
7150 case TARGET_NR_socket:
7151 ret = do_socket(arg1, arg2, arg3);
7152 break;
7153#endif
7154#ifdef TARGET_NR_socketpair
7155 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007156 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007157 break;
7158#endif
7159#ifdef TARGET_NR_setsockopt
7160 case TARGET_NR_setsockopt:
7161 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7162 break;
7163#endif
ths7494b0f2007-02-11 18:26:53 +00007164
bellard31e31b82003-02-18 22:55:36 +00007165 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007166 if (!(p = lock_user_string(arg2)))
7167 goto efault;
thse5574482007-02-11 20:03:13 +00007168 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7169 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007170 break;
7171
bellard31e31b82003-02-18 22:55:36 +00007172 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007173 {
bellard66fb9762003-03-23 01:06:05 +00007174 struct itimerval value, ovalue, *pvalue;
7175
pbrook53a59602006-03-25 19:31:22 +00007176 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007177 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007178 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7179 || copy_from_user_timeval(&pvalue->it_value,
7180 arg2 + sizeof(struct target_timeval)))
7181 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007182 } else {
7183 pvalue = NULL;
7184 }
7185 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007186 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007187 if (copy_to_user_timeval(arg3,
7188 &ovalue.it_interval)
7189 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7190 &ovalue.it_value))
7191 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007192 }
7193 }
7194 break;
bellard31e31b82003-02-18 22:55:36 +00007195 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007196 {
bellard66fb9762003-03-23 01:06:05 +00007197 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007198
bellard66fb9762003-03-23 01:06:05 +00007199 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007200 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007201 if (copy_to_user_timeval(arg2,
7202 &value.it_interval)
7203 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7204 &value.it_value))
7205 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007206 }
7207 }
7208 break;
bellard31e31b82003-02-18 22:55:36 +00007209 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007210 if (!(p = lock_user_string(arg1)))
7211 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007212 ret = get_errno(stat(path(p), &st));
7213 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007214 goto do_stat;
7215 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007216 if (!(p = lock_user_string(arg1)))
7217 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007218 ret = get_errno(lstat(path(p), &st));
7219 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007220 goto do_stat;
7221 case TARGET_NR_fstat:
7222 {
7223 ret = get_errno(fstat(arg1, &st));
7224 do_stat:
7225 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007226 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007227
bellard579a97f2007-11-11 14:26:47 +00007228 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7229 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007230 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007231 __put_user(st.st_dev, &target_st->st_dev);
7232 __put_user(st.st_ino, &target_st->st_ino);
7233 __put_user(st.st_mode, &target_st->st_mode);
7234 __put_user(st.st_uid, &target_st->st_uid);
7235 __put_user(st.st_gid, &target_st->st_gid);
7236 __put_user(st.st_nlink, &target_st->st_nlink);
7237 __put_user(st.st_rdev, &target_st->st_rdev);
7238 __put_user(st.st_size, &target_st->st_size);
7239 __put_user(st.st_blksize, &target_st->st_blksize);
7240 __put_user(st.st_blocks, &target_st->st_blocks);
7241 __put_user(st.st_atime, &target_st->target_st_atime);
7242 __put_user(st.st_mtime, &target_st->target_st_mtime);
7243 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007244 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007245 }
7246 }
7247 break;
bellardebc05482003-09-30 21:08:41 +00007248#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007249 case TARGET_NR_olduname:
7250 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007251#endif
7252#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007253 case TARGET_NR_iopl:
7254 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007255#endif
bellard31e31b82003-02-18 22:55:36 +00007256 case TARGET_NR_vhangup:
7257 ret = get_errno(vhangup());
7258 break;
bellardebc05482003-09-30 21:08:41 +00007259#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007260 case TARGET_NR_idle:
7261 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007262#endif
bellard42ad6ae2005-01-03 22:48:11 +00007263#ifdef TARGET_NR_syscall
7264 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007265 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7266 arg6, arg7, arg8, 0);
7267 break;
bellard42ad6ae2005-01-03 22:48:11 +00007268#endif
bellard31e31b82003-02-18 22:55:36 +00007269 case TARGET_NR_wait4:
7270 {
7271 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007272 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007273 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007274 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007275 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007276 if (target_rusage)
7277 rusage_ptr = &rusage;
7278 else
7279 rusage_ptr = NULL;
7280 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7281 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007282 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007283 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007284 if (put_user_s32(status, status_ptr))
7285 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007286 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007287 if (target_rusage) {
7288 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7289 if (rusage_err) {
7290 ret = rusage_err;
7291 }
7292 }
bellard31e31b82003-02-18 22:55:36 +00007293 }
7294 }
7295 break;
thse5febef2007-04-01 18:31:35 +00007296#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007297 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007298 if (!(p = lock_user_string(arg1)))
7299 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007300 ret = get_errno(swapoff(p));
7301 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007302 break;
thse5febef2007-04-01 18:31:35 +00007303#endif
bellard31e31b82003-02-18 22:55:36 +00007304 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007305 {
pbrook53a59602006-03-25 19:31:22 +00007306 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007307 struct sysinfo value;
7308 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007309 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007310 {
bellard579a97f2007-11-11 14:26:47 +00007311 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7312 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007313 __put_user(value.uptime, &target_value->uptime);
7314 __put_user(value.loads[0], &target_value->loads[0]);
7315 __put_user(value.loads[1], &target_value->loads[1]);
7316 __put_user(value.loads[2], &target_value->loads[2]);
7317 __put_user(value.totalram, &target_value->totalram);
7318 __put_user(value.freeram, &target_value->freeram);
7319 __put_user(value.sharedram, &target_value->sharedram);
7320 __put_user(value.bufferram, &target_value->bufferram);
7321 __put_user(value.totalswap, &target_value->totalswap);
7322 __put_user(value.freeswap, &target_value->freeswap);
7323 __put_user(value.procs, &target_value->procs);
7324 __put_user(value.totalhigh, &target_value->totalhigh);
7325 __put_user(value.freehigh, &target_value->freehigh);
7326 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007327 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007328 }
7329 }
7330 break;
thse5febef2007-04-01 18:31:35 +00007331#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007332 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007333 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7334 break;
thse5febef2007-04-01 18:31:35 +00007335#endif
aurel32e5289082009-04-18 16:16:12 +00007336#ifdef TARGET_NR_semget
7337 case TARGET_NR_semget:
7338 ret = get_errno(semget(arg1, arg2, arg3));
7339 break;
7340#endif
7341#ifdef TARGET_NR_semop
7342 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007343 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007344 break;
7345#endif
7346#ifdef TARGET_NR_semctl
7347 case TARGET_NR_semctl:
7348 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7349 break;
7350#endif
aurel32eeb438c2008-10-13 21:08:55 +00007351#ifdef TARGET_NR_msgctl
7352 case TARGET_NR_msgctl:
7353 ret = do_msgctl(arg1, arg2, arg3);
7354 break;
7355#endif
7356#ifdef TARGET_NR_msgget
7357 case TARGET_NR_msgget:
7358 ret = get_errno(msgget(arg1, arg2));
7359 break;
7360#endif
7361#ifdef TARGET_NR_msgrcv
7362 case TARGET_NR_msgrcv:
7363 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7364 break;
7365#endif
7366#ifdef TARGET_NR_msgsnd
7367 case TARGET_NR_msgsnd:
7368 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7369 break;
7370#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007371#ifdef TARGET_NR_shmget
7372 case TARGET_NR_shmget:
7373 ret = get_errno(shmget(arg1, arg2, arg3));
7374 break;
7375#endif
7376#ifdef TARGET_NR_shmctl
7377 case TARGET_NR_shmctl:
7378 ret = do_shmctl(arg1, arg2, arg3);
7379 break;
7380#endif
7381#ifdef TARGET_NR_shmat
7382 case TARGET_NR_shmat:
7383 ret = do_shmat(arg1, arg2, arg3);
7384 break;
7385#endif
7386#ifdef TARGET_NR_shmdt
7387 case TARGET_NR_shmdt:
7388 ret = do_shmdt(arg1);
7389 break;
7390#endif
bellard31e31b82003-02-18 22:55:36 +00007391 case TARGET_NR_fsync:
7392 ret = get_errno(fsync(arg1));
7393 break;
bellard31e31b82003-02-18 22:55:36 +00007394 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007395 /* Linux manages to have three different orderings for its
7396 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7397 * match the kernel's CONFIG_CLONE_* settings.
7398 * Microblaze is further special in that it uses a sixth
7399 * implicit argument to clone for the TLS pointer.
7400 */
7401#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007402 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007403#elif defined(TARGET_CLONE_BACKWARDS)
7404 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7405#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007406 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007407#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007408 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007409#endif
bellard1b6b0292003-03-22 17:31:38 +00007410 break;
bellardec86b0f2003-04-11 00:15:04 +00007411#ifdef __NR_exit_group
7412 /* new thread calls */
7413 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007414#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007415 _mcleanup();
7416#endif
bellarde9009672005-04-26 20:42:36 +00007417 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007418 ret = get_errno(exit_group(arg1));
7419 break;
7420#endif
bellard31e31b82003-02-18 22:55:36 +00007421 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007422 if (!(p = lock_user_string(arg1)))
7423 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007424 ret = get_errno(setdomainname(p, arg2));
7425 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007426 break;
7427 case TARGET_NR_uname:
7428 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007429 {
7430 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007431
bellard579a97f2007-11-11 14:26:47 +00007432 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7433 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007434 ret = get_errno(sys_uname(buf));
7435 if (!is_error(ret)) {
7436 /* Overrite the native machine name with whatever is being
7437 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007438 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007439 /* Allow the user to override the reported release. */
7440 if (qemu_uname_release && *qemu_uname_release)
7441 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007442 }
pbrook53a59602006-03-25 19:31:22 +00007443 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007444 }
bellard31e31b82003-02-18 22:55:36 +00007445 break;
bellard6dbad632003-03-16 18:05:05 +00007446#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007447 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007448 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007449 break;
j_mayer84409dd2007-04-06 08:56:50 +00007450#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007451 case TARGET_NR_vm86old:
7452 goto unimplemented;
7453 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007454 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007455 break;
7456#endif
j_mayer84409dd2007-04-06 08:56:50 +00007457#endif
bellard31e31b82003-02-18 22:55:36 +00007458 case TARGET_NR_adjtimex:
7459 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007460#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007461 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007462#endif
bellard31e31b82003-02-18 22:55:36 +00007463 case TARGET_NR_init_module:
7464 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007465#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007466 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007467#endif
bellard31e31b82003-02-18 22:55:36 +00007468 goto unimplemented;
7469 case TARGET_NR_quotactl:
7470 goto unimplemented;
7471 case TARGET_NR_getpgid:
7472 ret = get_errno(getpgid(arg1));
7473 break;
7474 case TARGET_NR_fchdir:
7475 ret = get_errno(fchdir(arg1));
7476 break;
j_mayer84409dd2007-04-06 08:56:50 +00007477#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007478 case TARGET_NR_bdflush:
7479 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007480#endif
thse5febef2007-04-01 18:31:35 +00007481#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007482 case TARGET_NR_sysfs:
7483 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007484#endif
bellard31e31b82003-02-18 22:55:36 +00007485 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007486 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007487 break;
thse5febef2007-04-01 18:31:35 +00007488#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007489 case TARGET_NR_afs_syscall:
7490 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007491#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007492#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007493 case TARGET_NR__llseek:
7494 {
7495 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007496#if !defined(__NR_llseek)
7497 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7498 if (res == -1) {
7499 ret = get_errno(res);
7500 } else {
7501 ret = 0;
7502 }
7503#else
bellard31e31b82003-02-18 22:55:36 +00007504 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007505#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007506 if ((ret == 0) && put_user_s64(res, arg4)) {
7507 goto efault;
7508 }
bellard31e31b82003-02-18 22:55:36 +00007509 }
7510 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007511#endif
bellard31e31b82003-02-18 22:55:36 +00007512 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007513#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007514#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007515 {
pbrook53a59602006-03-25 19:31:22 +00007516 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007517 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007518 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007519
7520 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007521 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007522 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007523 goto fail;
7524 }
ths3b46e622007-09-17 08:09:54 +00007525
bellard4add45b2003-06-05 01:52:59 +00007526 ret = get_errno(sys_getdents(arg1, dirp, count));
7527 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007528 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007529 struct target_dirent *tde;
7530 int len = ret;
7531 int reclen, treclen;
7532 int count1, tnamelen;
7533
7534 count1 = 0;
7535 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007536 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7537 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007538 tde = target_dirp;
7539 while (len > 0) {
7540 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007541 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7542 assert(tnamelen >= 0);
7543 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7544 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007545 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007546 tde->d_ino = tswapal(de->d_ino);
7547 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007548 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007549 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007550 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007551 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007552 count1 += treclen;
7553 }
7554 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007555 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007556 }
7557 free(dirp);
7558 }
7559#else
bellard31e31b82003-02-18 22:55:36 +00007560 {
aurel326556a832008-10-13 21:08:17 +00007561 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007562 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007563
bellard579a97f2007-11-11 14:26:47 +00007564 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7565 goto efault;
bellard72f03902003-02-18 23:33:18 +00007566 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007567 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007568 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007569 int len = ret;
7570 int reclen;
7571 de = dirp;
7572 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007573 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007574 if (reclen > len)
7575 break;
bellard8083a3e2003-03-24 23:12:16 +00007576 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007577 tswapls(&de->d_ino);
7578 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007579 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007580 len -= reclen;
7581 }
7582 }
pbrook53a59602006-03-25 19:31:22 +00007583 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007584 }
bellard4add45b2003-06-05 01:52:59 +00007585#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007586#else
7587 /* Implement getdents in terms of getdents64 */
7588 {
7589 struct linux_dirent64 *dirp;
7590 abi_long count = arg3;
7591
7592 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7593 if (!dirp) {
7594 goto efault;
7595 }
7596 ret = get_errno(sys_getdents64(arg1, dirp, count));
7597 if (!is_error(ret)) {
7598 /* Convert the dirent64 structs to target dirent. We do this
7599 * in-place, since we can guarantee that a target_dirent is no
7600 * larger than a dirent64; however this means we have to be
7601 * careful to read everything before writing in the new format.
7602 */
7603 struct linux_dirent64 *de;
7604 struct target_dirent *tde;
7605 int len = ret;
7606 int tlen = 0;
7607
7608 de = dirp;
7609 tde = (struct target_dirent *)dirp;
7610 while (len > 0) {
7611 int namelen, treclen;
7612 int reclen = de->d_reclen;
7613 uint64_t ino = de->d_ino;
7614 int64_t off = de->d_off;
7615 uint8_t type = de->d_type;
7616
7617 namelen = strlen(de->d_name);
7618 treclen = offsetof(struct target_dirent, d_name)
7619 + namelen + 2;
7620 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7621
7622 memmove(tde->d_name, de->d_name, namelen + 1);
7623 tde->d_ino = tswapal(ino);
7624 tde->d_off = tswapal(off);
7625 tde->d_reclen = tswap16(treclen);
7626 /* The target_dirent type is in what was formerly a padding
7627 * byte at the end of the structure:
7628 */
7629 *(((char *)tde) + treclen - 1) = type;
7630
7631 de = (struct linux_dirent64 *)((char *)de + reclen);
7632 tde = (struct target_dirent *)((char *)tde + treclen);
7633 len -= reclen;
7634 tlen += treclen;
7635 }
7636 ret = tlen;
7637 }
7638 unlock_user(dirp, arg2, ret);
7639 }
7640#endif
bellard31e31b82003-02-18 22:55:36 +00007641 break;
ths3ae43202007-09-16 21:39:48 +00007642#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007643 case TARGET_NR_getdents64:
7644 {
aurel326556a832008-10-13 21:08:17 +00007645 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007646 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007647 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7648 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007649 ret = get_errno(sys_getdents64(arg1, dirp, count));
7650 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007651 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007652 int len = ret;
7653 int reclen;
7654 de = dirp;
7655 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007656 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007657 if (reclen > len)
7658 break;
bellard8083a3e2003-03-24 23:12:16 +00007659 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007660 tswap64s((uint64_t *)&de->d_ino);
7661 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007662 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007663 len -= reclen;
7664 }
7665 }
pbrook53a59602006-03-25 19:31:22 +00007666 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007667 }
7668 break;
bellarda541f292004-04-12 20:39:29 +00007669#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007670#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007671 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007672 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007673 break;
thse5febef2007-04-01 18:31:35 +00007674#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007675#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7676# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007677 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007678# endif
7679# ifdef TARGET_NR_ppoll
7680 case TARGET_NR_ppoll:
7681# endif
bellard9de5e442003-03-23 16:49:39 +00007682 {
pbrook53a59602006-03-25 19:31:22 +00007683 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007684 unsigned int nfds = arg2;
7685 int timeout = arg3;
7686 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007687 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007688
bellard579a97f2007-11-11 14:26:47 +00007689 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7690 if (!target_pfd)
7691 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007692
bellard9de5e442003-03-23 16:49:39 +00007693 pfd = alloca(sizeof(struct pollfd) * nfds);
7694 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007695 pfd[i].fd = tswap32(target_pfd[i].fd);
7696 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007697 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007698
7699# ifdef TARGET_NR_ppoll
7700 if (num == TARGET_NR_ppoll) {
7701 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7702 target_sigset_t *target_set;
7703 sigset_t _set, *set = &_set;
7704
7705 if (arg3) {
7706 if (target_to_host_timespec(timeout_ts, arg3)) {
7707 unlock_user(target_pfd, arg1, 0);
7708 goto efault;
7709 }
7710 } else {
7711 timeout_ts = NULL;
7712 }
7713
7714 if (arg4) {
7715 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7716 if (!target_set) {
7717 unlock_user(target_pfd, arg1, 0);
7718 goto efault;
7719 }
7720 target_to_host_sigset(set, target_set);
7721 } else {
7722 set = NULL;
7723 }
7724
7725 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7726
7727 if (!is_error(ret) && arg3) {
7728 host_to_target_timespec(arg3, timeout_ts);
7729 }
7730 if (arg4) {
7731 unlock_user(target_set, arg4, 0);
7732 }
7733 } else
7734# endif
7735 ret = get_errno(poll(pfd, nfds, timeout));
7736
bellard9de5e442003-03-23 16:49:39 +00007737 if (!is_error(ret)) {
7738 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007739 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007740 }
7741 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007742 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007743 }
7744 break;
thse5febef2007-04-01 18:31:35 +00007745#endif
bellard31e31b82003-02-18 22:55:36 +00007746 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007747 /* NOTE: the flock constant seems to be the same for every
7748 Linux platform */
7749 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007750 break;
7751 case TARGET_NR_readv:
7752 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007753 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7754 if (vec != NULL) {
7755 ret = get_errno(readv(arg1, vec, arg3));
7756 unlock_iovec(vec, arg2, arg3, 1);
7757 } else {
7758 ret = -host_to_target_errno(errno);
7759 }
bellard31e31b82003-02-18 22:55:36 +00007760 }
7761 break;
7762 case TARGET_NR_writev:
7763 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007764 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7765 if (vec != NULL) {
7766 ret = get_errno(writev(arg1, vec, arg3));
7767 unlock_iovec(vec, arg2, arg3, 0);
7768 } else {
7769 ret = -host_to_target_errno(errno);
7770 }
bellard31e31b82003-02-18 22:55:36 +00007771 }
7772 break;
7773 case TARGET_NR_getsid:
7774 ret = get_errno(getsid(arg1));
7775 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007776#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007777 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007778 ret = get_errno(fdatasync(arg1));
7779 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007780#endif
bellard31e31b82003-02-18 22:55:36 +00007781 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007782 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007783 return value. */
ths0da46a62007-10-20 20:23:07 +00007784 ret = -TARGET_ENOTDIR;
7785 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007786 case TARGET_NR_sched_getaffinity:
7787 {
7788 unsigned int mask_size;
7789 unsigned long *mask;
7790
7791 /*
7792 * sched_getaffinity needs multiples of ulong, so need to take
7793 * care of mismatches between target ulong and host ulong sizes.
7794 */
7795 if (arg2 & (sizeof(abi_ulong) - 1)) {
7796 ret = -TARGET_EINVAL;
7797 break;
7798 }
7799 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7800
7801 mask = alloca(mask_size);
7802 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7803
7804 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007805 if (ret > arg2) {
7806 /* More data returned than the caller's buffer will fit.
7807 * This only happens if sizeof(abi_long) < sizeof(long)
7808 * and the caller passed us a buffer holding an odd number
7809 * of abi_longs. If the host kernel is actually using the
7810 * extra 4 bytes then fail EINVAL; otherwise we can just
7811 * ignore them and only copy the interesting part.
7812 */
7813 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7814 if (numcpus > arg2 * 8) {
7815 ret = -TARGET_EINVAL;
7816 break;
7817 }
7818 ret = arg2;
7819 }
7820
Mike McCormackcd18f052011-04-18 14:43:36 +09007821 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007822 goto efault;
7823 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007824 }
7825 }
7826 break;
7827 case TARGET_NR_sched_setaffinity:
7828 {
7829 unsigned int mask_size;
7830 unsigned long *mask;
7831
7832 /*
7833 * sched_setaffinity needs multiples of ulong, so need to take
7834 * care of mismatches between target ulong and host ulong sizes.
7835 */
7836 if (arg2 & (sizeof(abi_ulong) - 1)) {
7837 ret = -TARGET_EINVAL;
7838 break;
7839 }
7840 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7841
7842 mask = alloca(mask_size);
7843 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7844 goto efault;
7845 }
7846 memcpy(mask, p, arg2);
7847 unlock_user_struct(p, arg2, 0);
7848
7849 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7850 }
7851 break;
bellard31e31b82003-02-18 22:55:36 +00007852 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007853 {
pbrook53a59602006-03-25 19:31:22 +00007854 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007855 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007856
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007857 if (arg2 == 0) {
7858 return -TARGET_EINVAL;
7859 }
bellard579a97f2007-11-11 14:26:47 +00007860 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7861 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007862 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007863 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007864 ret = get_errno(sched_setparam(arg1, &schp));
7865 }
7866 break;
bellard31e31b82003-02-18 22:55:36 +00007867 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007868 {
pbrook53a59602006-03-25 19:31:22 +00007869 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007870 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007871
7872 if (arg2 == 0) {
7873 return -TARGET_EINVAL;
7874 }
bellard5cd43932003-03-29 16:54:36 +00007875 ret = get_errno(sched_getparam(arg1, &schp));
7876 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007877 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7878 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007879 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007880 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007881 }
7882 }
7883 break;
bellard31e31b82003-02-18 22:55:36 +00007884 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007885 {
pbrook53a59602006-03-25 19:31:22 +00007886 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007887 struct sched_param schp;
Tom Mustaa1d5c5b2014-08-12 13:53:38 -05007888 if (arg3 == 0) {
7889 return -TARGET_EINVAL;
7890 }
bellard579a97f2007-11-11 14:26:47 +00007891 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7892 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007893 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007894 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007895 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7896 }
7897 break;
bellard31e31b82003-02-18 22:55:36 +00007898 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007899 ret = get_errno(sched_getscheduler(arg1));
7900 break;
bellard31e31b82003-02-18 22:55:36 +00007901 case TARGET_NR_sched_yield:
7902 ret = get_errno(sched_yield());
7903 break;
7904 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007905 ret = get_errno(sched_get_priority_max(arg1));
7906 break;
bellard31e31b82003-02-18 22:55:36 +00007907 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007908 ret = get_errno(sched_get_priority_min(arg1));
7909 break;
bellard31e31b82003-02-18 22:55:36 +00007910 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007911 {
bellard5cd43932003-03-29 16:54:36 +00007912 struct timespec ts;
7913 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7914 if (!is_error(ret)) {
Tom Mustad4290c42014-08-12 13:53:39 -05007915 ret = host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007916 }
7917 }
7918 break;
bellard31e31b82003-02-18 22:55:36 +00007919 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007920 {
bellard1b6b0292003-03-22 17:31:38 +00007921 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007922 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007923 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007924 if (is_error(ret) && arg2) {
7925 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007926 }
7927 }
7928 break;
thse5febef2007-04-01 18:31:35 +00007929#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007930 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007931 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007932#endif
7933#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007934 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007935 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007936#endif
bellard31e31b82003-02-18 22:55:36 +00007937 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007938 switch (arg1) {
7939 case PR_GET_PDEATHSIG:
7940 {
7941 int deathsig;
7942 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7943 if (!is_error(ret) && arg2
7944 && put_user_ual(deathsig, arg2)) {
7945 goto efault;
thse5574482007-02-11 20:03:13 +00007946 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007947 break;
7948 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007949#ifdef PR_GET_NAME
7950 case PR_GET_NAME:
7951 {
7952 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7953 if (!name) {
7954 goto efault;
7955 }
7956 ret = get_errno(prctl(arg1, (unsigned long)name,
7957 arg3, arg4, arg5));
7958 unlock_user(name, arg2, 16);
7959 break;
7960 }
7961 case PR_SET_NAME:
7962 {
7963 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7964 if (!name) {
7965 goto efault;
7966 }
7967 ret = get_errno(prctl(arg1, (unsigned long)name,
7968 arg3, arg4, arg5));
7969 unlock_user(name, arg2, 0);
7970 break;
7971 }
7972#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007973 default:
7974 /* Most prctl options have no pointer arguments */
7975 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7976 break;
7977 }
ths39b9aae2007-02-11 18:36:44 +00007978 break;
bellardd2fd1af2007-11-14 18:08:56 +00007979#ifdef TARGET_NR_arch_prctl
7980 case TARGET_NR_arch_prctl:
7981#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7982 ret = do_arch_prctl(cpu_env, arg1, arg2);
7983 break;
7984#else
7985 goto unimplemented;
7986#endif
7987#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007988#ifdef TARGET_NR_pread64
7989 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007990 if (regpairs_aligned(cpu_env)) {
7991 arg4 = arg5;
7992 arg5 = arg6;
7993 }
aurel32f2c7ba12008-03-28 22:32:06 +00007994 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7995 goto efault;
7996 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7997 unlock_user(p, arg2, ret);
7998 break;
7999 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00008000 if (regpairs_aligned(cpu_env)) {
8001 arg4 = arg5;
8002 arg5 = arg6;
8003 }
aurel32f2c7ba12008-03-28 22:32:06 +00008004 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
8005 goto efault;
8006 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
8007 unlock_user(p, arg2, 0);
8008 break;
8009#endif
bellard31e31b82003-02-18 22:55:36 +00008010 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00008011 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
8012 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008013 ret = get_errno(sys_getcwd1(p, arg2));
8014 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00008015 break;
8016 case TARGET_NR_capget:
8017 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00008018 {
8019 struct target_user_cap_header *target_header;
8020 struct target_user_cap_data *target_data = NULL;
8021 struct __user_cap_header_struct header;
8022 struct __user_cap_data_struct data[2];
8023 struct __user_cap_data_struct *dataptr = NULL;
8024 int i, target_datalen;
8025 int data_items = 1;
8026
8027 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
8028 goto efault;
8029 }
8030 header.version = tswap32(target_header->version);
8031 header.pid = tswap32(target_header->pid);
8032
Peter Maydellec864872014-03-19 16:07:30 +00008033 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00008034 /* Version 2 and up takes pointer to two user_data structs */
8035 data_items = 2;
8036 }
8037
8038 target_datalen = sizeof(*target_data) * data_items;
8039
8040 if (arg2) {
8041 if (num == TARGET_NR_capget) {
8042 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
8043 } else {
8044 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
8045 }
8046 if (!target_data) {
8047 unlock_user_struct(target_header, arg1, 0);
8048 goto efault;
8049 }
8050
8051 if (num == TARGET_NR_capset) {
8052 for (i = 0; i < data_items; i++) {
8053 data[i].effective = tswap32(target_data[i].effective);
8054 data[i].permitted = tswap32(target_data[i].permitted);
8055 data[i].inheritable = tswap32(target_data[i].inheritable);
8056 }
8057 }
8058
8059 dataptr = data;
8060 }
8061
8062 if (num == TARGET_NR_capget) {
8063 ret = get_errno(capget(&header, dataptr));
8064 } else {
8065 ret = get_errno(capset(&header, dataptr));
8066 }
8067
8068 /* The kernel always updates version for both capget and capset */
8069 target_header->version = tswap32(header.version);
8070 unlock_user_struct(target_header, arg1, 1);
8071
8072 if (arg2) {
8073 if (num == TARGET_NR_capget) {
8074 for (i = 0; i < data_items; i++) {
8075 target_data[i].effective = tswap32(data[i].effective);
8076 target_data[i].permitted = tswap32(data[i].permitted);
8077 target_data[i].inheritable = tswap32(data[i].inheritable);
8078 }
8079 unlock_user(target_data, arg2, target_datalen);
8080 } else {
8081 unlock_user(target_data, arg2, 0);
8082 }
8083 }
8084 break;
8085 }
bellard31e31b82003-02-18 22:55:36 +00008086 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00008087#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02008088 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08008089 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01008090 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00008091 break;
8092#else
bellard5cd43932003-03-29 16:54:36 +00008093 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00008094#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008095
8096#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00008097 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008098 {
8099 off_t *offp = NULL;
8100 off_t off;
8101 if (arg3) {
8102 ret = get_user_sal(off, arg3);
8103 if (is_error(ret)) {
8104 break;
8105 }
8106 offp = &off;
8107 }
8108 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8109 if (!is_error(ret) && arg3) {
8110 abi_long ret2 = put_user_sal(off, arg3);
8111 if (is_error(ret2)) {
8112 ret = ret2;
8113 }
8114 }
8115 break;
8116 }
8117#ifdef TARGET_NR_sendfile64
8118 case TARGET_NR_sendfile64:
8119 {
8120 off_t *offp = NULL;
8121 off_t off;
8122 if (arg3) {
8123 ret = get_user_s64(off, arg3);
8124 if (is_error(ret)) {
8125 break;
8126 }
8127 offp = &off;
8128 }
8129 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
8130 if (!is_error(ret) && arg3) {
8131 abi_long ret2 = put_user_s64(off, arg3);
8132 if (is_error(ret2)) {
8133 ret = ret2;
8134 }
8135 }
8136 break;
8137 }
8138#endif
8139#else
8140 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01008141#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008142 case TARGET_NR_sendfile64:
8143#endif
bellard5cd43932003-03-29 16:54:36 +00008144 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00008145#endif
8146
bellardebc05482003-09-30 21:08:41 +00008147#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00008148 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00008149 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008150#endif
8151#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00008152 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00008153 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008154#endif
bellard048f6b42005-11-26 18:47:20 +00008155#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00008156 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008157 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8158 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008159 break;
bellard048f6b42005-11-26 18:47:20 +00008160#endif
bellardebc05482003-09-30 21:08:41 +00008161#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008162 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008163 {
8164 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008165 int resource = target_to_host_resource(arg1);
8166 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008167 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008168 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008169 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8170 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008171 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8172 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008173 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008174 }
8175 break;
8176 }
bellardebc05482003-09-30 21:08:41 +00008177#endif
bellarda315a142005-01-30 22:59:18 +00008178#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008179 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008180 if (!(p = lock_user_string(arg1)))
8181 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008182 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8183 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008184 break;
bellarda315a142005-01-30 22:59:18 +00008185#endif
8186#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008187 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008188 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008189 break;
bellarda315a142005-01-30 22:59:18 +00008190#endif
8191#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008192 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008193 if (!(p = lock_user_string(arg1)))
8194 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008195 ret = get_errno(stat(path(p), &st));
8196 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008197 if (!is_error(ret))
8198 ret = host_to_target_stat64(cpu_env, arg2, &st);
8199 break;
bellarda315a142005-01-30 22:59:18 +00008200#endif
8201#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008202 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008203 if (!(p = lock_user_string(arg1)))
8204 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008205 ret = get_errno(lstat(path(p), &st));
8206 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008207 if (!is_error(ret))
8208 ret = host_to_target_stat64(cpu_env, arg2, &st);
8209 break;
bellarda315a142005-01-30 22:59:18 +00008210#endif
8211#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008212 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008213 ret = get_errno(fstat(arg1, &st));
8214 if (!is_error(ret))
8215 ret = host_to_target_stat64(cpu_env, arg2, &st);
8216 break;
bellardec86b0f2003-04-11 00:15:04 +00008217#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008218#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008219#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008220 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008221#endif
8222#ifdef TARGET_NR_newfstatat
8223 case TARGET_NR_newfstatat:
8224#endif
balrog6a24a772008-09-20 02:23:36 +00008225 if (!(p = lock_user_string(arg2)))
8226 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008227 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008228 if (!is_error(ret))
8229 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008230 break;
bellarda315a142005-01-30 22:59:18 +00008231#endif
bellard67867302003-11-23 17:05:30 +00008232 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008233 if (!(p = lock_user_string(arg1)))
8234 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008235 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8236 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008237 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008238#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008239 case TARGET_NR_getuid:
8240 ret = get_errno(high2lowuid(getuid()));
8241 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008242#endif
8243#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008244 case TARGET_NR_getgid:
8245 ret = get_errno(high2lowgid(getgid()));
8246 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008247#endif
8248#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008249 case TARGET_NR_geteuid:
8250 ret = get_errno(high2lowuid(geteuid()));
8251 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008252#endif
8253#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008254 case TARGET_NR_getegid:
8255 ret = get_errno(high2lowgid(getegid()));
8256 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008257#endif
bellard67867302003-11-23 17:05:30 +00008258 case TARGET_NR_setreuid:
8259 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8260 break;
8261 case TARGET_NR_setregid:
8262 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8263 break;
8264 case TARGET_NR_getgroups:
8265 {
8266 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008267 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008268 gid_t *grouplist;
8269 int i;
8270
8271 grouplist = alloca(gidsetsize * sizeof(gid_t));
8272 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008273 if (gidsetsize == 0)
8274 break;
bellard67867302003-11-23 17:05:30 +00008275 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008276 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008277 if (!target_grouplist)
8278 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008279 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008280 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008281 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008282 }
8283 }
8284 break;
8285 case TARGET_NR_setgroups:
8286 {
8287 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008288 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008289 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008290 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008291 if (gidsetsize) {
8292 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008293 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008294 if (!target_grouplist) {
8295 ret = -TARGET_EFAULT;
8296 goto fail;
8297 }
8298 for (i = 0; i < gidsetsize; i++) {
8299 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8300 }
8301 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008302 }
bellard67867302003-11-23 17:05:30 +00008303 ret = get_errno(setgroups(gidsetsize, grouplist));
8304 }
8305 break;
8306 case TARGET_NR_fchown:
8307 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8308 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008309#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008310 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008311 if (!(p = lock_user_string(arg2)))
8312 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008313 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8314 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008315 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008316 break;
8317#endif
bellard67867302003-11-23 17:05:30 +00008318#ifdef TARGET_NR_setresuid
8319 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008320 ret = get_errno(setresuid(low2highuid(arg1),
8321 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008322 low2highuid(arg3)));
8323 break;
8324#endif
8325#ifdef TARGET_NR_getresuid
8326 case TARGET_NR_getresuid:
8327 {
pbrook53a59602006-03-25 19:31:22 +00008328 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008329 ret = get_errno(getresuid(&ruid, &euid, &suid));
8330 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008331 if (put_user_id(high2lowuid(ruid), arg1)
8332 || put_user_id(high2lowuid(euid), arg2)
8333 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008334 goto efault;
bellard67867302003-11-23 17:05:30 +00008335 }
8336 }
8337 break;
8338#endif
8339#ifdef TARGET_NR_getresgid
8340 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008341 ret = get_errno(setresgid(low2highgid(arg1),
8342 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008343 low2highgid(arg3)));
8344 break;
8345#endif
8346#ifdef TARGET_NR_getresgid
8347 case TARGET_NR_getresgid:
8348 {
pbrook53a59602006-03-25 19:31:22 +00008349 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008350 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8351 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008352 if (put_user_id(high2lowgid(rgid), arg1)
8353 || put_user_id(high2lowgid(egid), arg2)
8354 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008355 goto efault;
bellard67867302003-11-23 17:05:30 +00008356 }
8357 }
8358 break;
8359#endif
8360 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008361 if (!(p = lock_user_string(arg1)))
8362 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008363 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8364 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008365 break;
8366 case TARGET_NR_setuid:
8367 ret = get_errno(setuid(low2highuid(arg1)));
8368 break;
8369 case TARGET_NR_setgid:
8370 ret = get_errno(setgid(low2highgid(arg1)));
8371 break;
8372 case TARGET_NR_setfsuid:
8373 ret = get_errno(setfsuid(arg1));
8374 break;
8375 case TARGET_NR_setfsgid:
8376 ret = get_errno(setfsgid(arg1));
8377 break;
bellard67867302003-11-23 17:05:30 +00008378
bellarda315a142005-01-30 22:59:18 +00008379#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008380 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008381 if (!(p = lock_user_string(arg1)))
8382 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008383 ret = get_errno(lchown(p, arg2, arg3));
8384 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008385 break;
bellarda315a142005-01-30 22:59:18 +00008386#endif
8387#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008388 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008389 ret = get_errno(getuid());
8390 break;
bellarda315a142005-01-30 22:59:18 +00008391#endif
aurel3264b4d282008-11-14 17:20:15 +00008392
8393#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8394 /* Alpha specific */
8395 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008396 {
8397 uid_t euid;
8398 euid=geteuid();
8399 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8400 }
aurel3264b4d282008-11-14 17:20:15 +00008401 ret = get_errno(getuid());
8402 break;
8403#endif
8404#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8405 /* Alpha specific */
8406 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008407 {
8408 uid_t egid;
8409 egid=getegid();
8410 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8411 }
aurel3264b4d282008-11-14 17:20:15 +00008412 ret = get_errno(getgid());
8413 break;
8414#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008415#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8416 /* Alpha specific */
8417 case TARGET_NR_osf_getsysinfo:
8418 ret = -TARGET_EOPNOTSUPP;
8419 switch (arg1) {
8420 case TARGET_GSI_IEEE_FP_CONTROL:
8421 {
8422 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8423
8424 /* Copied from linux ieee_fpcr_to_swcr. */
8425 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8426 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8427 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8428 | SWCR_TRAP_ENABLE_DZE
8429 | SWCR_TRAP_ENABLE_OVF);
8430 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8431 | SWCR_TRAP_ENABLE_INE);
8432 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8433 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8434
8435 if (put_user_u64 (swcr, arg2))
8436 goto efault;
8437 ret = 0;
8438 }
8439 break;
8440
8441 /* case GSI_IEEE_STATE_AT_SIGNAL:
8442 -- Not implemented in linux kernel.
8443 case GSI_UACPROC:
8444 -- Retrieves current unaligned access state; not much used.
8445 case GSI_PROC_TYPE:
8446 -- Retrieves implver information; surely not used.
8447 case GSI_GET_HWRPB:
8448 -- Grabs a copy of the HWRPB; surely not used.
8449 */
8450 }
8451 break;
8452#endif
8453#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8454 /* Alpha specific */
8455 case TARGET_NR_osf_setsysinfo:
8456 ret = -TARGET_EOPNOTSUPP;
8457 switch (arg1) {
8458 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008459 {
8460 uint64_t swcr, fpcr, orig_fpcr;
8461
Richard Henderson6e06d512012-06-01 09:08:21 -07008462 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008463 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008464 }
8465 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008466 fpcr = orig_fpcr & FPCR_DYN_MASK;
8467
8468 /* Copied from linux ieee_swcr_to_fpcr. */
8469 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8470 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8471 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8472 | SWCR_TRAP_ENABLE_DZE
8473 | SWCR_TRAP_ENABLE_OVF)) << 48;
8474 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8475 | SWCR_TRAP_ENABLE_INE)) << 57;
8476 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8477 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8478
Richard Henderson6e06d512012-06-01 09:08:21 -07008479 cpu_alpha_store_fpcr(cpu_env, fpcr);
8480 ret = 0;
8481 }
8482 break;
8483
8484 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8485 {
8486 uint64_t exc, fpcr, orig_fpcr;
8487 int si_code;
8488
8489 if (get_user_u64(exc, arg2)) {
8490 goto efault;
8491 }
8492
8493 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8494
8495 /* We only add to the exception status here. */
8496 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8497
8498 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008499 ret = 0;
8500
Richard Henderson6e06d512012-06-01 09:08:21 -07008501 /* Old exceptions are not signaled. */
8502 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008503
Richard Henderson6e06d512012-06-01 09:08:21 -07008504 /* If any exceptions set by this call,
8505 and are unmasked, send a signal. */
8506 si_code = 0;
8507 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8508 si_code = TARGET_FPE_FLTRES;
8509 }
8510 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8511 si_code = TARGET_FPE_FLTUND;
8512 }
8513 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8514 si_code = TARGET_FPE_FLTOVF;
8515 }
8516 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8517 si_code = TARGET_FPE_FLTDIV;
8518 }
8519 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8520 si_code = TARGET_FPE_FLTINV;
8521 }
8522 if (si_code != 0) {
8523 target_siginfo_t info;
8524 info.si_signo = SIGFPE;
8525 info.si_errno = 0;
8526 info.si_code = si_code;
8527 info._sifields._sigfault._addr
8528 = ((CPUArchState *)cpu_env)->pc;
8529 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008530 }
8531 }
8532 break;
8533
8534 /* case SSI_NVPAIRS:
8535 -- Used with SSIN_UACPROC to enable unaligned accesses.
8536 case SSI_IEEE_STATE_AT_SIGNAL:
8537 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8538 -- Not implemented in linux kernel
8539 */
8540 }
8541 break;
8542#endif
8543#ifdef TARGET_NR_osf_sigprocmask
8544 /* Alpha specific. */
8545 case TARGET_NR_osf_sigprocmask:
8546 {
8547 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008548 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008549 sigset_t set, oldset;
8550
8551 switch(arg1) {
8552 case TARGET_SIG_BLOCK:
8553 how = SIG_BLOCK;
8554 break;
8555 case TARGET_SIG_UNBLOCK:
8556 how = SIG_UNBLOCK;
8557 break;
8558 case TARGET_SIG_SETMASK:
8559 how = SIG_SETMASK;
8560 break;
8561 default:
8562 ret = -TARGET_EINVAL;
8563 goto fail;
8564 }
8565 mask = arg2;
8566 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008567 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008568 host_to_target_old_sigset(&mask, &oldset);
8569 ret = mask;
8570 }
8571 break;
8572#endif
aurel3264b4d282008-11-14 17:20:15 +00008573
bellarda315a142005-01-30 22:59:18 +00008574#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008575 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008576 ret = get_errno(getgid());
8577 break;
bellarda315a142005-01-30 22:59:18 +00008578#endif
8579#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008580 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008581 ret = get_errno(geteuid());
8582 break;
bellarda315a142005-01-30 22:59:18 +00008583#endif
8584#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008585 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008586 ret = get_errno(getegid());
8587 break;
bellarda315a142005-01-30 22:59:18 +00008588#endif
8589#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008590 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008591 ret = get_errno(setreuid(arg1, arg2));
8592 break;
bellarda315a142005-01-30 22:59:18 +00008593#endif
8594#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008595 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008596 ret = get_errno(setregid(arg1, arg2));
8597 break;
bellarda315a142005-01-30 22:59:18 +00008598#endif
8599#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008600 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008601 {
8602 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008603 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008604 gid_t *grouplist;
8605 int i;
8606
8607 grouplist = alloca(gidsetsize * sizeof(gid_t));
8608 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008609 if (gidsetsize == 0)
8610 break;
bellard99c475a2005-01-31 20:45:13 +00008611 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008612 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8613 if (!target_grouplist) {
8614 ret = -TARGET_EFAULT;
8615 goto fail;
8616 }
balroga2155fc2008-09-20 02:12:08 +00008617 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008618 target_grouplist[i] = tswap32(grouplist[i]);
8619 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008620 }
8621 }
8622 break;
bellarda315a142005-01-30 22:59:18 +00008623#endif
8624#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008625 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008626 {
8627 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008628 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008629 gid_t *grouplist;
8630 int i;
ths3b46e622007-09-17 08:09:54 +00008631
bellard99c475a2005-01-31 20:45:13 +00008632 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008633 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8634 if (!target_grouplist) {
8635 ret = -TARGET_EFAULT;
8636 goto fail;
8637 }
bellard99c475a2005-01-31 20:45:13 +00008638 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008639 grouplist[i] = tswap32(target_grouplist[i]);
8640 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008641 ret = get_errno(setgroups(gidsetsize, grouplist));
8642 }
8643 break;
bellarda315a142005-01-30 22:59:18 +00008644#endif
8645#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008646 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008647 ret = get_errno(fchown(arg1, arg2, arg3));
8648 break;
bellarda315a142005-01-30 22:59:18 +00008649#endif
8650#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008651 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008652 ret = get_errno(setresuid(arg1, arg2, arg3));
8653 break;
bellarda315a142005-01-30 22:59:18 +00008654#endif
8655#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008656 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008657 {
pbrook53a59602006-03-25 19:31:22 +00008658 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008659 ret = get_errno(getresuid(&ruid, &euid, &suid));
8660 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008661 if (put_user_u32(ruid, arg1)
8662 || put_user_u32(euid, arg2)
8663 || put_user_u32(suid, arg3))
8664 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008665 }
8666 }
8667 break;
bellarda315a142005-01-30 22:59:18 +00008668#endif
8669#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008670 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008671 ret = get_errno(setresgid(arg1, arg2, arg3));
8672 break;
bellarda315a142005-01-30 22:59:18 +00008673#endif
8674#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008675 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008676 {
pbrook53a59602006-03-25 19:31:22 +00008677 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008678 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8679 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008680 if (put_user_u32(rgid, arg1)
8681 || put_user_u32(egid, arg2)
8682 || put_user_u32(sgid, arg3))
8683 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008684 }
8685 }
8686 break;
bellarda315a142005-01-30 22:59:18 +00008687#endif
8688#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008689 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008690 if (!(p = lock_user_string(arg1)))
8691 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008692 ret = get_errno(chown(p, arg2, arg3));
8693 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008694 break;
bellarda315a142005-01-30 22:59:18 +00008695#endif
8696#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008697 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008698 ret = get_errno(setuid(arg1));
8699 break;
bellarda315a142005-01-30 22:59:18 +00008700#endif
8701#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008702 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008703 ret = get_errno(setgid(arg1));
8704 break;
bellarda315a142005-01-30 22:59:18 +00008705#endif
8706#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008707 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008708 ret = get_errno(setfsuid(arg1));
8709 break;
bellarda315a142005-01-30 22:59:18 +00008710#endif
8711#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008712 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008713 ret = get_errno(setfsgid(arg1));
8714 break;
bellarda315a142005-01-30 22:59:18 +00008715#endif
bellard67867302003-11-23 17:05:30 +00008716
bellard31e31b82003-02-18 22:55:36 +00008717 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008718 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008719#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008720 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008721 {
8722 void *a;
8723 ret = -TARGET_EFAULT;
8724 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8725 goto efault;
8726 if (!(p = lock_user_string(arg3)))
8727 goto mincore_fail;
8728 ret = get_errno(mincore(a, arg2, p));
8729 unlock_user(p, arg3, ret);
8730 mincore_fail:
8731 unlock_user(a, arg1, 0);
8732 }
8733 break;
bellardffa65c32004-01-04 23:57:22 +00008734#endif
aurel32408321b2008-10-01 21:46:32 +00008735#ifdef TARGET_NR_arm_fadvise64_64
8736 case TARGET_NR_arm_fadvise64_64:
8737 {
8738 /*
8739 * arm_fadvise64_64 looks like fadvise64_64 but
8740 * with different argument order
8741 */
8742 abi_long temp;
8743 temp = arg3;
8744 arg3 = arg4;
8745 arg4 = temp;
8746 }
8747#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008748#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008749#ifdef TARGET_NR_fadvise64_64
8750 case TARGET_NR_fadvise64_64:
8751#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008752#ifdef TARGET_NR_fadvise64
8753 case TARGET_NR_fadvise64:
8754#endif
8755#ifdef TARGET_S390X
8756 switch (arg4) {
8757 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8758 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8759 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8760 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8761 default: break;
8762 }
8763#endif
8764 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008765 break;
8766#endif
bellardffa65c32004-01-04 23:57:22 +00008767#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008768 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008769 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008770 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008771 This will break MADV_DONTNEED.
8772 This is a hint, so ignoring and returning success is ok. */
8773 ret = get_errno(0);
8774 break;
bellardffa65c32004-01-04 23:57:22 +00008775#endif
blueswir1992f48a2007-10-14 16:27:31 +00008776#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008777 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008778 {
thsb1e341e2007-03-20 21:50:52 +00008779 int cmd;
bellard77e46722003-04-29 20:39:06 +00008780 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008781 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008782#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008783 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008784#endif
bellard77e46722003-04-29 20:39:06 +00008785
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008786 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008787 if (cmd == -TARGET_EINVAL) {
8788 ret = cmd;
8789 break;
8790 }
thsb1e341e2007-03-20 21:50:52 +00008791
bellard60cd49d2003-03-16 22:53:56 +00008792 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008793 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008794#ifdef TARGET_ARM
8795 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008796 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8797 goto efault;
ths58134272007-03-31 18:59:32 +00008798 fl.l_type = tswap16(target_efl->l_type);
8799 fl.l_whence = tswap16(target_efl->l_whence);
8800 fl.l_start = tswap64(target_efl->l_start);
8801 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008802 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008803 unlock_user_struct(target_efl, arg3, 0);
8804 } else
8805#endif
8806 {
bellard9ee1fa22007-11-11 15:11:19 +00008807 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8808 goto efault;
ths58134272007-03-31 18:59:32 +00008809 fl.l_type = tswap16(target_fl->l_type);
8810 fl.l_whence = tswap16(target_fl->l_whence);
8811 fl.l_start = tswap64(target_fl->l_start);
8812 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008813 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008814 unlock_user_struct(target_fl, arg3, 0);
8815 }
thsb1e341e2007-03-20 21:50:52 +00008816 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008817 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008818#ifdef TARGET_ARM
8819 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008820 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8821 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008822 target_efl->l_type = tswap16(fl.l_type);
8823 target_efl->l_whence = tswap16(fl.l_whence);
8824 target_efl->l_start = tswap64(fl.l_start);
8825 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008826 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008827 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008828 } else
8829#endif
8830 {
bellard9ee1fa22007-11-11 15:11:19 +00008831 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8832 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008833 target_fl->l_type = tswap16(fl.l_type);
8834 target_fl->l_whence = tswap16(fl.l_whence);
8835 target_fl->l_start = tswap64(fl.l_start);
8836 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008837 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008838 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008839 }
bellard77e46722003-04-29 20:39:06 +00008840 }
8841 break;
8842
thsb1e341e2007-03-20 21:50:52 +00008843 case TARGET_F_SETLK64:
8844 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008845#ifdef TARGET_ARM
8846 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008847 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8848 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008849 fl.l_type = tswap16(target_efl->l_type);
8850 fl.l_whence = tswap16(target_efl->l_whence);
8851 fl.l_start = tswap64(target_efl->l_start);
8852 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008853 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008854 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008855 } else
8856#endif
8857 {
bellard9ee1fa22007-11-11 15:11:19 +00008858 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8859 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008860 fl.l_type = tswap16(target_fl->l_type);
8861 fl.l_whence = tswap16(target_fl->l_whence);
8862 fl.l_start = tswap64(target_fl->l_start);
8863 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008864 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008865 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008866 }
thsb1e341e2007-03-20 21:50:52 +00008867 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008868 break;
bellard60cd49d2003-03-16 22:53:56 +00008869 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008870 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008871 break;
8872 }
bellard77e46722003-04-29 20:39:06 +00008873 break;
8874 }
bellard60cd49d2003-03-16 22:53:56 +00008875#endif
ths7d600c82006-12-08 01:32:58 +00008876#ifdef TARGET_NR_cacheflush
8877 case TARGET_NR_cacheflush:
8878 /* self-modifying code is handled automatically, so nothing needed */
8879 ret = 0;
8880 break;
8881#endif
bellardebc05482003-09-30 21:08:41 +00008882#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008883 case TARGET_NR_security:
8884 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008885#endif
bellardc573ff62004-01-04 15:51:36 +00008886#ifdef TARGET_NR_getpagesize
8887 case TARGET_NR_getpagesize:
8888 ret = TARGET_PAGE_SIZE;
8889 break;
8890#endif
bellard31e31b82003-02-18 22:55:36 +00008891 case TARGET_NR_gettid:
8892 ret = get_errno(gettid());
8893 break;
thse5febef2007-04-01 18:31:35 +00008894#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008895 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008896#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008897 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008898 arg2 = arg3;
8899 arg3 = arg4;
8900 arg4 = arg5;
8901 }
aurel322054ac92008-10-13 21:08:07 +00008902 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8903#else
8904 ret = get_errno(readahead(arg1, arg2, arg3));
8905#endif
8906 break;
thse5febef2007-04-01 18:31:35 +00008907#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008908#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008909#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008910 case TARGET_NR_listxattr:
8911 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008912 {
8913 void *p, *b = 0;
8914 if (arg2) {
8915 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8916 if (!b) {
8917 ret = -TARGET_EFAULT;
8918 break;
8919 }
8920 }
8921 p = lock_user_string(arg1);
8922 if (p) {
8923 if (num == TARGET_NR_listxattr) {
8924 ret = get_errno(listxattr(p, b, arg3));
8925 } else {
8926 ret = get_errno(llistxattr(p, b, arg3));
8927 }
8928 } else {
8929 ret = -TARGET_EFAULT;
8930 }
8931 unlock_user(p, arg1, 0);
8932 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008933 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008934 }
8935 case TARGET_NR_flistxattr:
8936 {
8937 void *b = 0;
8938 if (arg2) {
8939 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8940 if (!b) {
8941 ret = -TARGET_EFAULT;
8942 break;
8943 }
8944 }
8945 ret = get_errno(flistxattr(arg1, b, arg3));
8946 unlock_user(b, arg2, arg3);
8947 break;
8948 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008949 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008950 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008951 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008952 void *p, *n, *v = 0;
8953 if (arg3) {
8954 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8955 if (!v) {
8956 ret = -TARGET_EFAULT;
8957 break;
8958 }
8959 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008960 p = lock_user_string(arg1);
8961 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008962 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008963 if (num == TARGET_NR_setxattr) {
8964 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8965 } else {
8966 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8967 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008968 } else {
8969 ret = -TARGET_EFAULT;
8970 }
8971 unlock_user(p, arg1, 0);
8972 unlock_user(n, arg2, 0);
8973 unlock_user(v, arg3, 0);
8974 }
8975 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008976 case TARGET_NR_fsetxattr:
8977 {
8978 void *n, *v = 0;
8979 if (arg3) {
8980 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8981 if (!v) {
8982 ret = -TARGET_EFAULT;
8983 break;
8984 }
8985 }
8986 n = lock_user_string(arg2);
8987 if (n) {
8988 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8989 } else {
8990 ret = -TARGET_EFAULT;
8991 }
8992 unlock_user(n, arg2, 0);
8993 unlock_user(v, arg3, 0);
8994 }
8995 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008996 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008997 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008998 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008999 void *p, *n, *v = 0;
9000 if (arg3) {
9001 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9002 if (!v) {
9003 ret = -TARGET_EFAULT;
9004 break;
9005 }
9006 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009007 p = lock_user_string(arg1);
9008 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00009009 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009010 if (num == TARGET_NR_getxattr) {
9011 ret = get_errno(getxattr(p, n, v, arg4));
9012 } else {
9013 ret = get_errno(lgetxattr(p, n, v, arg4));
9014 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009015 } else {
9016 ret = -TARGET_EFAULT;
9017 }
9018 unlock_user(p, arg1, 0);
9019 unlock_user(n, arg2, 0);
9020 unlock_user(v, arg3, arg4);
9021 }
9022 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009023 case TARGET_NR_fgetxattr:
9024 {
9025 void *n, *v = 0;
9026 if (arg3) {
9027 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
9028 if (!v) {
9029 ret = -TARGET_EFAULT;
9030 break;
9031 }
9032 }
9033 n = lock_user_string(arg2);
9034 if (n) {
9035 ret = get_errno(fgetxattr(arg1, n, v, arg4));
9036 } else {
9037 ret = -TARGET_EFAULT;
9038 }
9039 unlock_user(n, arg2, 0);
9040 unlock_user(v, arg3, arg4);
9041 }
9042 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009043 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00009044 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009045 {
9046 void *p, *n;
9047 p = lock_user_string(arg1);
9048 n = lock_user_string(arg2);
9049 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00009050 if (num == TARGET_NR_removexattr) {
9051 ret = get_errno(removexattr(p, n));
9052 } else {
9053 ret = get_errno(lremovexattr(p, n));
9054 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009055 } else {
9056 ret = -TARGET_EFAULT;
9057 }
9058 unlock_user(p, arg1, 0);
9059 unlock_user(n, arg2, 0);
9060 }
9061 break;
Peter Maydell30297b52011-12-14 15:37:18 +00009062 case TARGET_NR_fremovexattr:
9063 {
9064 void *n;
9065 n = lock_user_string(arg2);
9066 if (n) {
9067 ret = get_errno(fremovexattr(arg1, n));
9068 } else {
9069 ret = -TARGET_EFAULT;
9070 }
9071 unlock_user(n, arg2, 0);
9072 }
9073 break;
bellardebc05482003-09-30 21:08:41 +00009074#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07009075#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00009076#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00009077 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009078#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02009079 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00009080 ret = 0;
9081 break;
edgar_iglef967792009-01-07 14:19:38 +00009082#elif defined(TARGET_CRIS)
9083 if (arg1 & 0xff)
9084 ret = -TARGET_EINVAL;
9085 else {
9086 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
9087 ret = 0;
9088 }
9089 break;
bellard8d18e892007-11-14 15:18:40 +00009090#elif defined(TARGET_I386) && defined(TARGET_ABI32)
9091 ret = do_set_thread_area(cpu_env, arg1);
9092 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009093#elif defined(TARGET_M68K)
9094 {
Andreas Färber0429a972013-08-26 18:14:44 +02009095 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009096 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01009097 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009098 break;
9099 }
ths6f5b89a2007-03-02 20:48:00 +00009100#else
9101 goto unimplemented_nowarn;
9102#endif
9103#endif
9104#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00009105 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00009106#if defined(TARGET_I386) && defined(TARGET_ABI32)
9107 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01009108 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009109#elif defined(TARGET_M68K)
9110 {
Andreas Färber0429a972013-08-26 18:14:44 +02009111 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01009112 ret = ts->tp_value;
9113 break;
9114 }
bellard8d18e892007-11-14 15:18:40 +00009115#else
bellard5cd43932003-03-29 16:54:36 +00009116 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00009117#endif
bellard8d18e892007-11-14 15:18:40 +00009118#endif
bellard48dc41e2006-06-21 18:15:50 +00009119#ifdef TARGET_NR_getdomainname
9120 case TARGET_NR_getdomainname:
9121 goto unimplemented_nowarn;
9122#endif
ths6f5b89a2007-03-02 20:48:00 +00009123
thsb5906f92007-03-19 13:32:45 +00009124#ifdef TARGET_NR_clock_gettime
9125 case TARGET_NR_clock_gettime:
9126 {
9127 struct timespec ts;
9128 ret = get_errno(clock_gettime(arg1, &ts));
9129 if (!is_error(ret)) {
9130 host_to_target_timespec(arg2, &ts);
9131 }
9132 break;
9133 }
9134#endif
9135#ifdef TARGET_NR_clock_getres
9136 case TARGET_NR_clock_getres:
9137 {
9138 struct timespec ts;
9139 ret = get_errno(clock_getres(arg1, &ts));
9140 if (!is_error(ret)) {
9141 host_to_target_timespec(arg2, &ts);
9142 }
9143 break;
9144 }
9145#endif
pbrook63d76512008-05-29 13:43:29 +00009146#ifdef TARGET_NR_clock_nanosleep
9147 case TARGET_NR_clock_nanosleep:
9148 {
9149 struct timespec ts;
9150 target_to_host_timespec(&ts, arg3);
9151 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
9152 if (arg4)
9153 host_to_target_timespec(arg4, &ts);
Tom Musta8fbe8fd2014-08-12 13:53:41 -05009154
9155#if defined(TARGET_PPC)
9156 /* clock_nanosleep is odd in that it returns positive errno values.
9157 * On PPC, CR0 bit 3 should be set in such a situation. */
9158 if (ret) {
9159 ((CPUPPCState *)cpu_env)->crf[0] |= 1;
9160 }
9161#endif
pbrook63d76512008-05-29 13:43:29 +00009162 break;
9163 }
9164#endif
thsb5906f92007-03-19 13:32:45 +00009165
ths6f5b89a2007-03-02 20:48:00 +00009166#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9167 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009168 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9169 break;
ths6f5b89a2007-03-02 20:48:00 +00009170#endif
9171
ths3ae43202007-09-16 21:39:48 +00009172#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009173 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009174 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009175 break;
9176#endif
9177
ths3ae43202007-09-16 21:39:48 +00009178#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009179 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009180 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9181 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009182 break;
9183#endif
9184
ths4f2b1fe2007-06-21 21:57:12 +00009185#ifdef TARGET_NR_set_robust_list
9186 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009187 case TARGET_NR_get_robust_list:
9188 /* The ABI for supporting robust futexes has userspace pass
9189 * the kernel a pointer to a linked list which is updated by
9190 * userspace after the syscall; the list is walked by the kernel
9191 * when the thread exits. Since the linked list in QEMU guest
9192 * memory isn't a valid linked list for the host and we have
9193 * no way to reliably intercept the thread-death event, we can't
9194 * support these. Silently return ENOSYS so that guest userspace
9195 * falls back to a non-robust futex implementation (which should
9196 * be OK except in the corner case of the guest crashing while
9197 * holding a mutex that is shared with another process via
9198 * shared memory).
9199 */
9200 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009201#endif
9202
Peter Maydell1acae9f2013-07-02 14:04:12 +01009203#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009204 case TARGET_NR_utimensat:
9205 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009206 struct timespec *tsp, ts[2];
9207 if (!arg3) {
9208 tsp = NULL;
9209 } else {
9210 target_to_host_timespec(ts, arg3);
9211 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9212 tsp = ts;
9213 }
ths9007f0e2007-09-25 17:50:37 +00009214 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009215 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009216 else {
bellard579a97f2007-11-11 14:26:47 +00009217 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009218 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009219 goto fail;
9220 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009221 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009222 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009223 }
9224 }
9225 break;
9226#endif
pbrookbd0c5662008-05-29 14:34:11 +00009227 case TARGET_NR_futex:
9228 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9229 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009230#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009231 case TARGET_NR_inotify_init:
9232 ret = get_errno(sys_inotify_init());
9233 break;
9234#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009235#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009236#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9237 case TARGET_NR_inotify_init1:
9238 ret = get_errno(sys_inotify_init1(arg1));
9239 break;
9240#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009241#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009242#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009243 case TARGET_NR_inotify_add_watch:
9244 p = lock_user_string(arg2);
9245 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9246 unlock_user(p, arg2, 0);
9247 break;
9248#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009249#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009250 case TARGET_NR_inotify_rm_watch:
9251 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9252 break;
9253#endif
ths9007f0e2007-09-25 17:50:37 +00009254
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009255#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009256 case TARGET_NR_mq_open:
9257 {
Tom Mustab6ce1f62014-08-12 13:53:36 -05009258 struct mq_attr posix_mq_attr, *attrp;
aurel3224e10032009-04-15 16:11:43 +00009259
9260 p = lock_user_string(arg1 - 1);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009261 if (arg4 != 0) {
aurel3224e10032009-04-15 16:11:43 +00009262 copy_from_user_mq_attr (&posix_mq_attr, arg4);
Tom Mustab6ce1f62014-08-12 13:53:36 -05009263 attrp = &posix_mq_attr;
9264 } else {
9265 attrp = 0;
9266 }
9267 ret = get_errno(mq_open(p, arg2, arg3, attrp));
aurel3224e10032009-04-15 16:11:43 +00009268 unlock_user (p, arg1, 0);
9269 }
9270 break;
9271
9272 case TARGET_NR_mq_unlink:
9273 p = lock_user_string(arg1 - 1);
9274 ret = get_errno(mq_unlink(p));
9275 unlock_user (p, arg1, 0);
9276 break;
9277
9278 case TARGET_NR_mq_timedsend:
9279 {
9280 struct timespec ts;
9281
9282 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9283 if (arg5 != 0) {
9284 target_to_host_timespec(&ts, arg5);
9285 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9286 host_to_target_timespec(arg5, &ts);
9287 }
9288 else
9289 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9290 unlock_user (p, arg2, arg3);
9291 }
9292 break;
9293
9294 case TARGET_NR_mq_timedreceive:
9295 {
9296 struct timespec ts;
9297 unsigned int prio;
9298
9299 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9300 if (arg5 != 0) {
9301 target_to_host_timespec(&ts, arg5);
9302 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9303 host_to_target_timespec(arg5, &ts);
9304 }
9305 else
9306 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9307 unlock_user (p, arg2, arg3);
9308 if (arg4 != 0)
9309 put_user_u32(prio, arg4);
9310 }
9311 break;
9312
9313 /* Not implemented for now... */
9314/* case TARGET_NR_mq_notify: */
9315/* break; */
9316
9317 case TARGET_NR_mq_getsetattr:
9318 {
9319 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9320 ret = 0;
9321 if (arg3 != 0) {
9322 ret = mq_getattr(arg1, &posix_mq_attr_out);
9323 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9324 }
9325 if (arg2 != 0) {
9326 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9327 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9328 }
9329
9330 }
9331 break;
9332#endif
9333
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309334#ifdef CONFIG_SPLICE
9335#ifdef TARGET_NR_tee
9336 case TARGET_NR_tee:
9337 {
9338 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9339 }
9340 break;
9341#endif
9342#ifdef TARGET_NR_splice
9343 case TARGET_NR_splice:
9344 {
9345 loff_t loff_in, loff_out;
9346 loff_t *ploff_in = NULL, *ploff_out = NULL;
9347 if(arg2) {
9348 get_user_u64(loff_in, arg2);
9349 ploff_in = &loff_in;
9350 }
9351 if(arg4) {
9352 get_user_u64(loff_out, arg2);
9353 ploff_out = &loff_out;
9354 }
9355 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9356 }
9357 break;
9358#endif
9359#ifdef TARGET_NR_vmsplice
9360 case TARGET_NR_vmsplice:
9361 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009362 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9363 if (vec != NULL) {
9364 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9365 unlock_iovec(vec, arg2, arg3, 0);
9366 } else {
9367 ret = -host_to_target_errno(errno);
9368 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309369 }
9370 break;
9371#endif
9372#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009373#ifdef CONFIG_EVENTFD
9374#if defined(TARGET_NR_eventfd)
9375 case TARGET_NR_eventfd:
9376 ret = get_errno(eventfd(arg1, 0));
9377 break;
9378#endif
9379#if defined(TARGET_NR_eventfd2)
9380 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009381 {
9382 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9383 if (arg2 & TARGET_O_NONBLOCK) {
9384 host_flags |= O_NONBLOCK;
9385 }
9386 if (arg2 & TARGET_O_CLOEXEC) {
9387 host_flags |= O_CLOEXEC;
9388 }
9389 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009390 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009391 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009392#endif
9393#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009394#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9395 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009396#if TARGET_ABI_BITS == 32
9397 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9398 target_offset64(arg5, arg6)));
9399#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009400 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009401#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009402 break;
9403#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009404#if defined(CONFIG_SYNC_FILE_RANGE)
9405#if defined(TARGET_NR_sync_file_range)
9406 case TARGET_NR_sync_file_range:
9407#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009408#if defined(TARGET_MIPS)
9409 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9410 target_offset64(arg5, arg6), arg7));
9411#else
Peter Maydellc727f472011-01-06 11:05:10 +00009412 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9413 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009414#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009415#else
9416 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9417#endif
9418 break;
9419#endif
9420#if defined(TARGET_NR_sync_file_range2)
9421 case TARGET_NR_sync_file_range2:
9422 /* This is like sync_file_range but the arguments are reordered */
9423#if TARGET_ABI_BITS == 32
9424 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9425 target_offset64(arg5, arg6), arg2));
9426#else
9427 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9428#endif
9429 break;
9430#endif
9431#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009432#if defined(CONFIG_EPOLL)
9433#if defined(TARGET_NR_epoll_create)
9434 case TARGET_NR_epoll_create:
9435 ret = get_errno(epoll_create(arg1));
9436 break;
9437#endif
9438#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9439 case TARGET_NR_epoll_create1:
9440 ret = get_errno(epoll_create1(arg1));
9441 break;
9442#endif
9443#if defined(TARGET_NR_epoll_ctl)
9444 case TARGET_NR_epoll_ctl:
9445 {
9446 struct epoll_event ep;
9447 struct epoll_event *epp = 0;
9448 if (arg4) {
9449 struct target_epoll_event *target_ep;
9450 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9451 goto efault;
9452 }
9453 ep.events = tswap32(target_ep->events);
9454 /* The epoll_data_t union is just opaque data to the kernel,
9455 * so we transfer all 64 bits across and need not worry what
9456 * actual data type it is.
9457 */
9458 ep.data.u64 = tswap64(target_ep->data.u64);
9459 unlock_user_struct(target_ep, arg4, 0);
9460 epp = &ep;
9461 }
9462 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9463 break;
9464 }
9465#endif
9466
9467#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9468#define IMPLEMENT_EPOLL_PWAIT
9469#endif
9470#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9471#if defined(TARGET_NR_epoll_wait)
9472 case TARGET_NR_epoll_wait:
9473#endif
9474#if defined(IMPLEMENT_EPOLL_PWAIT)
9475 case TARGET_NR_epoll_pwait:
9476#endif
9477 {
9478 struct target_epoll_event *target_ep;
9479 struct epoll_event *ep;
9480 int epfd = arg1;
9481 int maxevents = arg3;
9482 int timeout = arg4;
9483
9484 target_ep = lock_user(VERIFY_WRITE, arg2,
9485 maxevents * sizeof(struct target_epoll_event), 1);
9486 if (!target_ep) {
9487 goto efault;
9488 }
9489
9490 ep = alloca(maxevents * sizeof(struct epoll_event));
9491
9492 switch (num) {
9493#if defined(IMPLEMENT_EPOLL_PWAIT)
9494 case TARGET_NR_epoll_pwait:
9495 {
9496 target_sigset_t *target_set;
9497 sigset_t _set, *set = &_set;
9498
9499 if (arg5) {
9500 target_set = lock_user(VERIFY_READ, arg5,
9501 sizeof(target_sigset_t), 1);
9502 if (!target_set) {
9503 unlock_user(target_ep, arg2, 0);
9504 goto efault;
9505 }
9506 target_to_host_sigset(set, target_set);
9507 unlock_user(target_set, arg5, 0);
9508 } else {
9509 set = NULL;
9510 }
9511
9512 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9513 break;
9514 }
9515#endif
9516#if defined(TARGET_NR_epoll_wait)
9517 case TARGET_NR_epoll_wait:
9518 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9519 break;
9520#endif
9521 default:
9522 ret = -TARGET_ENOSYS;
9523 }
9524 if (!is_error(ret)) {
9525 int i;
9526 for (i = 0; i < ret; i++) {
9527 target_ep[i].events = tswap32(ep[i].events);
9528 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9529 }
9530 }
9531 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9532 break;
9533 }
9534#endif
9535#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009536#ifdef TARGET_NR_prlimit64
9537 case TARGET_NR_prlimit64:
9538 {
9539 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9540 struct target_rlimit64 *target_rnew, *target_rold;
9541 struct host_rlimit64 rnew, rold, *rnewp = 0;
Felix Janda95018012014-12-02 22:11:17 +01009542 int resource = target_to_host_resource(arg2);
Peter Maydell163a05a2011-06-27 17:44:52 +01009543 if (arg3) {
9544 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9545 goto efault;
9546 }
9547 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9548 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9549 unlock_user_struct(target_rnew, arg3, 0);
9550 rnewp = &rnew;
9551 }
9552
Felix Janda95018012014-12-02 22:11:17 +01009553 ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
Peter Maydell163a05a2011-06-27 17:44:52 +01009554 if (!is_error(ret) && arg4) {
9555 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9556 goto efault;
9557 }
9558 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9559 target_rold->rlim_max = tswap64(rold.rlim_max);
9560 unlock_user_struct(target_rold, arg4, 1);
9561 }
9562 break;
9563 }
9564#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009565#ifdef TARGET_NR_gethostname
9566 case TARGET_NR_gethostname:
9567 {
9568 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9569 if (name) {
9570 ret = get_errno(gethostname(name, arg2));
9571 unlock_user(name, arg1, arg2);
9572 } else {
9573 ret = -TARGET_EFAULT;
9574 }
9575 break;
9576 }
9577#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009578#ifdef TARGET_NR_atomic_cmpxchg_32
9579 case TARGET_NR_atomic_cmpxchg_32:
9580 {
9581 /* should use start_exclusive from main.c */
9582 abi_ulong mem_value;
9583 if (get_user_u32(mem_value, arg6)) {
9584 target_siginfo_t info;
9585 info.si_signo = SIGSEGV;
9586 info.si_errno = 0;
9587 info.si_code = TARGET_SEGV_MAPERR;
9588 info._sifields._sigfault._addr = arg6;
9589 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9590 ret = 0xdeadbeef;
9591
9592 }
9593 if (mem_value == arg2)
9594 put_user_u32(arg1, arg6);
9595 ret = mem_value;
9596 break;
9597 }
9598#endif
9599#ifdef TARGET_NR_atomic_barrier
9600 case TARGET_NR_atomic_barrier:
9601 {
9602 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009603 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009604 break;
9605 }
9606#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009607
9608#ifdef TARGET_NR_timer_create
9609 case TARGET_NR_timer_create:
9610 {
9611 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9612
9613 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009614
9615 int clkid = arg1;
9616 int timer_index = next_free_host_timer();
9617
9618 if (timer_index < 0) {
9619 ret = -TARGET_EAGAIN;
9620 } else {
9621 timer_t *phtimer = g_posix_timers + timer_index;
9622
9623 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009624 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +01009625 ret = target_to_host_sigevent(phost_sevp, arg2);
9626 if (ret != 0) {
9627 break;
9628 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009629 }
9630
9631 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9632 if (ret) {
9633 phtimer = NULL;
9634 } else {
Alexander Grafaecc8862014-11-10 21:33:03 +01009635 if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009636 goto efault;
9637 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009638 }
9639 }
9640 break;
9641 }
9642#endif
9643
9644#ifdef TARGET_NR_timer_settime
9645 case TARGET_NR_timer_settime:
9646 {
9647 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9648 * struct itimerspec * old_value */
Alexander Grafaecc8862014-11-10 21:33:03 +01009649 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +02009650
Alexander Grafaecc8862014-11-10 21:33:03 +01009651 if (timerid < 0) {
9652 ret = timerid;
9653 } else if (arg3 == 0) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009654 ret = -TARGET_EINVAL;
9655 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009656 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009657 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9658
9659 target_to_host_itimerspec(&hspec_new, arg3);
9660 ret = get_errno(
9661 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9662 host_to_target_itimerspec(arg2, &hspec_old);
9663 }
9664 break;
9665 }
9666#endif
9667
9668#ifdef TARGET_NR_timer_gettime
9669 case TARGET_NR_timer_gettime:
9670 {
9671 /* args: timer_t timerid, struct itimerspec *curr_value */
Alexander Grafaecc8862014-11-10 21:33:03 +01009672 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +02009673
Alexander Grafaecc8862014-11-10 21:33:03 +01009674 if (timerid < 0) {
9675 ret = timerid;
9676 } else if (!arg2) {
9677 ret = -TARGET_EFAULT;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009678 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009679 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009680 struct itimerspec hspec;
9681 ret = get_errno(timer_gettime(htimer, &hspec));
9682
9683 if (host_to_target_itimerspec(arg2, &hspec)) {
9684 ret = -TARGET_EFAULT;
9685 }
9686 }
9687 break;
9688 }
9689#endif
9690
9691#ifdef TARGET_NR_timer_getoverrun
9692 case TARGET_NR_timer_getoverrun:
9693 {
9694 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +01009695 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +02009696
Alexander Grafaecc8862014-11-10 21:33:03 +01009697 if (timerid < 0) {
9698 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009699 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009700 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009701 ret = get_errno(timer_getoverrun(htimer));
9702 }
9703 break;
9704 }
9705#endif
9706
9707#ifdef TARGET_NR_timer_delete
9708 case TARGET_NR_timer_delete:
9709 {
9710 /* args: timer_t timerid */
Alexander Grafaecc8862014-11-10 21:33:03 +01009711 target_timer_t timerid = get_timer_id(arg1);
Alexander Grafe52a99f2014-08-22 13:56:18 +02009712
Alexander Grafaecc8862014-11-10 21:33:03 +01009713 if (timerid < 0) {
9714 ret = timerid;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009715 } else {
Alexander Grafe52a99f2014-08-22 13:56:18 +02009716 timer_t htimer = g_posix_timers[timerid];
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009717 ret = get_errno(timer_delete(htimer));
Alexander Grafe52a99f2014-08-22 13:56:18 +02009718 g_posix_timers[timerid] = 0;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009719 }
9720 break;
9721 }
9722#endif
9723
Riku Voipio51834342014-06-22 11:25:42 +01009724#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
9725 case TARGET_NR_timerfd_create:
9726 ret = get_errno(timerfd_create(arg1,
9727 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
9728 break;
9729#endif
9730
9731#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
9732 case TARGET_NR_timerfd_gettime:
9733 {
9734 struct itimerspec its_curr;
9735
9736 ret = get_errno(timerfd_gettime(arg1, &its_curr));
9737
9738 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
9739 goto efault;
9740 }
9741 }
9742 break;
9743#endif
9744
9745#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
9746 case TARGET_NR_timerfd_settime:
9747 {
9748 struct itimerspec its_new, its_old, *p_new;
9749
9750 if (arg3) {
9751 if (target_to_host_itimerspec(&its_new, arg3)) {
9752 goto efault;
9753 }
9754 p_new = &its_new;
9755 } else {
9756 p_new = NULL;
9757 }
9758
9759 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
9760
9761 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
9762 goto efault;
9763 }
9764 }
9765 break;
9766#endif
9767
Paul Burtonab31cda2014-06-22 11:25:43 +01009768#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
9769 case TARGET_NR_ioprio_get:
9770 ret = get_errno(ioprio_get(arg1, arg2));
9771 break;
9772#endif
9773
9774#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
9775 case TARGET_NR_ioprio_set:
9776 ret = get_errno(ioprio_set(arg1, arg2, arg3));
9777 break;
9778#endif
9779
Riku Voipio9af5c902014-08-12 15:58:57 +03009780#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
9781 case TARGET_NR_setns:
9782 ret = get_errno(setns(arg1, arg2));
9783 break;
9784#endif
9785#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
9786 case TARGET_NR_unshare:
9787 ret = get_errno(unshare(arg1));
9788 break;
9789#endif
9790
bellard31e31b82003-02-18 22:55:36 +00009791 default:
9792 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009793 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009794#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 +00009795 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009796#endif
ths0da46a62007-10-20 20:23:07 +00009797 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009798 break;
9799 }
bellard579a97f2007-11-11 14:26:47 +00009800fail:
bellardc573ff62004-01-04 15:51:36 +00009801#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009802 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009803#endif
thsb92c47c2007-11-01 00:07:38 +00009804 if(do_strace)
9805 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009806 return ret;
bellard579a97f2007-11-11 14:26:47 +00009807efault:
9808 ret = -TARGET_EFAULT;
9809 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009810}