blob: 007d59d70cc6183498c181cf22d1ee7230835397 [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"
Juan Quintela9788c9c2009-07-27 16:13:02 +020069#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000070#include <sys/gmon.h>
71#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030072#ifdef CONFIG_EVENTFD
73#include <sys/eventfd.h>
74#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000075#ifdef CONFIG_EPOLL
76#include <sys/epoll.h>
77#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070078#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010079#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070080#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000081#ifdef CONFIG_SENDFILE
82#include <sys/sendfile.h>
83#endif
bellard31e31b82003-02-18 22:55:36 +000084
85#define termios host_termios
86#define winsize host_winsize
87#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000088#define sgttyb host_sgttyb /* same as target */
89#define tchars host_tchars /* same as target */
90#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000091
92#include <linux/termios.h>
93#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000094#include <linux/cdrom.h>
95#include <linux/hdreg.h>
96#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000097#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000098#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +030099#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000100#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000101#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000102#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200103#include <linux/fb.h>
104#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100105#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000106#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100107#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200108#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100109#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000110#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200111#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000112
bellard3ef693a2003-03-23 20:17:16 +0000113#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000114
pbrookd865bab2008-06-07 22:12:17 +0000115#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
116 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000117
bellard72f03902003-02-18 23:33:18 +0000118//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000119
bellard1a9353d2003-03-16 20:28:50 +0000120//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000121#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
122#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000123
bellard70a194b2003-08-11 22:20:16 +0000124
bellard70a194b2003-08-11 22:20:16 +0000125#undef _syscall0
126#undef _syscall1
127#undef _syscall2
128#undef _syscall3
129#undef _syscall4
130#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000131#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000132
bellard83fcb512006-06-14 13:37:16 +0000133#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000134static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000135{ \
136 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000137}
138
bellard83fcb512006-06-14 13:37:16 +0000139#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000140static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000141{ \
142 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000143}
144
bellard83fcb512006-06-14 13:37:16 +0000145#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000146static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000147{ \
148 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000149}
150
bellard83fcb512006-06-14 13:37:16 +0000151#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000152static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000153{ \
154 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000155}
156
bellard83fcb512006-06-14 13:37:16 +0000157#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000158static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000159{ \
160 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000161}
162
bellard83fcb512006-06-14 13:37:16 +0000163#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
164 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000165static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000166{ \
167 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000168}
bellard83fcb512006-06-14 13:37:16 +0000169
170
171#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
172 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000173static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
174 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000175{ \
176 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
177}
178
bellard70a194b2003-08-11 22:20:16 +0000179
bellard31e31b82003-02-18 22:55:36 +0000180#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000181#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000183#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000184#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000185#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000186#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000187#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000188#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000189#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000190#define __NR_sys_inotify_init __NR_inotify_init
191#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
192#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000193
Alexander Graf42a39fb2011-04-15 17:32:45 +0200194#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
195 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000196#define __NR__llseek __NR_lseek
197#endif
198
James Hogana29e5ba2014-03-25 21:51:08 +0000199/* Newer kernel ports have llseek() instead of _llseek() */
200#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
201#define TARGET_NR__llseek TARGET_NR_llseek
202#endif
203
bellard72f03902003-02-18 23:33:18 +0000204#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000205_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000206#else
ths0da46a62007-10-20 20:23:07 +0000207/* This is a replacement for the host gettid() and must return a host
208 errno. */
bellard72f03902003-02-18 23:33:18 +0000209static int gettid(void) {
210 return -ENOSYS;
211}
212#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100213#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000214_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100215#endif
216#if !defined(__NR_getdents) || \
217 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000218_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
219#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700220#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000221_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
222 loff_t *, res, uint, wh);
223#endif
224_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
225_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
226#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
227_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
228#endif
229#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
230_syscall2(int,sys_tkill,int,tid,int,sig)
231#endif
232#ifdef __NR_exit_group
233_syscall1(int,exit_group,int,error_code)
234#endif
235#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
236_syscall1(int,set_tid_address,int *,tidptr)
237#endif
aurel323b3f24a2009-04-15 16:12:13 +0000238#if defined(TARGET_NR_futex) && defined(__NR_futex)
239_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
240 const struct timespec *,timeout,int *,uaddr2,int,val3)
241#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500242#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
243_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
244 unsigned long *, user_mask_ptr);
245#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
246_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
247 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200248_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
249 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000250_syscall2(int, capget, struct __user_cap_header_struct *, header,
251 struct __user_cap_data_struct *, data);
252_syscall2(int, capset, struct __user_cap_header_struct *, header,
253 struct __user_cap_data_struct *, data);
aurel323b3f24a2009-04-15 16:12:13 +0000254
255static bitmask_transtbl fcntl_flags_tbl[] = {
256 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
257 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
258 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
259 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
260 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
261 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
262 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
263 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700264 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000265 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
266 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
267 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
268 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000269#if defined(O_DIRECT)
270 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
271#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700272#if defined(O_NOATIME)
273 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
274#endif
275#if defined(O_CLOEXEC)
276 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
277#endif
278#if defined(O_PATH)
279 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
280#endif
281 /* Don't terminate the list prematurely on 64-bit host+guest. */
282#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
283 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
284#endif
aurel323b3f24a2009-04-15 16:12:13 +0000285 { 0, 0, 0, 0 }
286};
287
aurel323b3f24a2009-04-15 16:12:13 +0000288static int sys_getcwd1(char *buf, size_t size)
289{
290 if (getcwd(buf, size) == NULL) {
291 /* getcwd() sets errno */
292 return (-1);
293 }
aurel32aaf4ad32009-04-16 14:17:14 +0000294 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000295}
296
aurel323b3f24a2009-04-15 16:12:13 +0000297#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200298static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000299{
300 /*
301 * open(2) has extra parameter 'mode' when called with
302 * flag O_CREAT.
303 */
304 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000305 return (openat(dirfd, pathname, flags, mode));
306 }
307 return (openat(dirfd, pathname, flags));
308}
309#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300310
Peter Maydell1acae9f2013-07-02 14:04:12 +0100311#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300312#ifdef CONFIG_UTIMENSAT
313static int sys_utimensat(int dirfd, const char *pathname,
314 const struct timespec times[2], int flags)
315{
316 if (pathname == NULL)
317 return futimens(dirfd, times);
318 else
319 return utimensat(dirfd, pathname, times, flags);
320}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100321#elif defined(__NR_utimensat)
322#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000323_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
324 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100325#else
326static int sys_utimensat(int dirfd, const char *pathname,
327 const struct timespec times[2], int flags)
328{
329 errno = ENOSYS;
330 return -1;
331}
ths9007f0e2007-09-25 17:50:37 +0000332#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100333#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000334
335#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000336#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000337
aurel3239b59762008-10-01 21:46:50 +0000338#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000339static int sys_inotify_init(void)
340{
341 return (inotify_init());
342}
aurel3239b59762008-10-01 21:46:50 +0000343#endif
344#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000345static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
346{
347 return (inotify_add_watch(fd, pathname, mask));
348}
aurel3239b59762008-10-01 21:46:50 +0000349#endif
350#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000351static int sys_inotify_rm_watch(int fd, int32_t wd)
352{
aurel328690e422009-04-17 13:50:32 +0000353 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000354}
aurel3239b59762008-10-01 21:46:50 +0000355#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000356#ifdef CONFIG_INOTIFY1
357#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
358static int sys_inotify_init1(int flags)
359{
360 return (inotify_init1(flags));
361}
362#endif
363#endif
aurel323b3f24a2009-04-15 16:12:13 +0000364#else
365/* Userspace can usually survive runtime without inotify */
366#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000367#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000368#undef TARGET_NR_inotify_add_watch
369#undef TARGET_NR_inotify_rm_watch
370#endif /* CONFIG_INOTIFY */
371
Mike Frysingerd8035d42011-02-07 01:05:51 -0500372#if defined(TARGET_NR_ppoll)
373#ifndef __NR_ppoll
374# define __NR_ppoll -1
375#endif
376#define __NR_sys_ppoll __NR_ppoll
377_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200378 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500379 size_t, sigsetsize)
380#endif
bellard66fb9762003-03-23 01:06:05 +0000381
Mike Frysinger055e0902011-06-03 17:01:49 -0400382#if defined(TARGET_NR_pselect6)
383#ifndef __NR_pselect6
384# define __NR_pselect6 -1
385#endif
386#define __NR_sys_pselect6 __NR_pselect6
387_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
388 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
389#endif
390
Peter Maydell163a05a2011-06-27 17:44:52 +0100391#if defined(TARGET_NR_prlimit64)
392#ifndef __NR_prlimit64
393# define __NR_prlimit64 -1
394#endif
395#define __NR_sys_prlimit64 __NR_prlimit64
396/* The glibc rlimit structure may not be that used by the underlying syscall */
397struct host_rlimit64 {
398 uint64_t rlim_cur;
399 uint64_t rlim_max;
400};
401_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
402 const struct host_rlimit64 *, new_limit,
403 struct host_rlimit64 *, old_limit)
404#endif
405
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100406
407#if defined(TARGET_NR_timer_create)
408/* Maxiumum of 32 active POSIX timers allowed at any one time. */
409static timer_t g_posix_timers[32] = { 0, } ;
410
411static inline int next_free_host_timer(void)
412{
413 int k ;
414 /* FIXME: Does finding the next free slot require a lock? */
415 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
416 if (g_posix_timers[k] == 0) {
417 g_posix_timers[k] = (timer_t) 1;
418 return k;
419 }
420 }
421 return -1;
422}
423#endif
424
Riku Voipio48e515d2011-07-12 15:40:51 +0300425/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000426#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300427static inline int regpairs_aligned(void *cpu_env) {
428 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
429}
430#elif defined(TARGET_MIPS)
431static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000432#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
433/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
434 * of registers which translates to the same as ARM/MIPS, because we start with
435 * r3 as arg1 */
436static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300437#else
438static inline int regpairs_aligned(void *cpu_env) { return 0; }
439#endif
440
thsb92c47c2007-11-01 00:07:38 +0000441#define ERRNO_TABLE_SIZE 1200
442
443/* target_to_host_errno_table[] is initialized from
444 * host_to_target_errno_table[] in syscall_init(). */
445static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
446};
447
ths637947f2007-06-01 12:09:19 +0000448/*
thsfe8f0962007-07-12 10:59:21 +0000449 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000450 * minus the errnos that are not actually generic to all archs.
451 */
thsb92c47c2007-11-01 00:07:38 +0000452static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000453 [EIDRM] = TARGET_EIDRM,
454 [ECHRNG] = TARGET_ECHRNG,
455 [EL2NSYNC] = TARGET_EL2NSYNC,
456 [EL3HLT] = TARGET_EL3HLT,
457 [EL3RST] = TARGET_EL3RST,
458 [ELNRNG] = TARGET_ELNRNG,
459 [EUNATCH] = TARGET_EUNATCH,
460 [ENOCSI] = TARGET_ENOCSI,
461 [EL2HLT] = TARGET_EL2HLT,
462 [EDEADLK] = TARGET_EDEADLK,
463 [ENOLCK] = TARGET_ENOLCK,
464 [EBADE] = TARGET_EBADE,
465 [EBADR] = TARGET_EBADR,
466 [EXFULL] = TARGET_EXFULL,
467 [ENOANO] = TARGET_ENOANO,
468 [EBADRQC] = TARGET_EBADRQC,
469 [EBADSLT] = TARGET_EBADSLT,
470 [EBFONT] = TARGET_EBFONT,
471 [ENOSTR] = TARGET_ENOSTR,
472 [ENODATA] = TARGET_ENODATA,
473 [ETIME] = TARGET_ETIME,
474 [ENOSR] = TARGET_ENOSR,
475 [ENONET] = TARGET_ENONET,
476 [ENOPKG] = TARGET_ENOPKG,
477 [EREMOTE] = TARGET_EREMOTE,
478 [ENOLINK] = TARGET_ENOLINK,
479 [EADV] = TARGET_EADV,
480 [ESRMNT] = TARGET_ESRMNT,
481 [ECOMM] = TARGET_ECOMM,
482 [EPROTO] = TARGET_EPROTO,
483 [EDOTDOT] = TARGET_EDOTDOT,
484 [EMULTIHOP] = TARGET_EMULTIHOP,
485 [EBADMSG] = TARGET_EBADMSG,
486 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
487 [EOVERFLOW] = TARGET_EOVERFLOW,
488 [ENOTUNIQ] = TARGET_ENOTUNIQ,
489 [EBADFD] = TARGET_EBADFD,
490 [EREMCHG] = TARGET_EREMCHG,
491 [ELIBACC] = TARGET_ELIBACC,
492 [ELIBBAD] = TARGET_ELIBBAD,
493 [ELIBSCN] = TARGET_ELIBSCN,
494 [ELIBMAX] = TARGET_ELIBMAX,
495 [ELIBEXEC] = TARGET_ELIBEXEC,
496 [EILSEQ] = TARGET_EILSEQ,
497 [ENOSYS] = TARGET_ENOSYS,
498 [ELOOP] = TARGET_ELOOP,
499 [ERESTART] = TARGET_ERESTART,
500 [ESTRPIPE] = TARGET_ESTRPIPE,
501 [ENOTEMPTY] = TARGET_ENOTEMPTY,
502 [EUSERS] = TARGET_EUSERS,
503 [ENOTSOCK] = TARGET_ENOTSOCK,
504 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
505 [EMSGSIZE] = TARGET_EMSGSIZE,
506 [EPROTOTYPE] = TARGET_EPROTOTYPE,
507 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
508 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
509 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
510 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
511 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
512 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
513 [EADDRINUSE] = TARGET_EADDRINUSE,
514 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
515 [ENETDOWN] = TARGET_ENETDOWN,
516 [ENETUNREACH] = TARGET_ENETUNREACH,
517 [ENETRESET] = TARGET_ENETRESET,
518 [ECONNABORTED] = TARGET_ECONNABORTED,
519 [ECONNRESET] = TARGET_ECONNRESET,
520 [ENOBUFS] = TARGET_ENOBUFS,
521 [EISCONN] = TARGET_EISCONN,
522 [ENOTCONN] = TARGET_ENOTCONN,
523 [EUCLEAN] = TARGET_EUCLEAN,
524 [ENOTNAM] = TARGET_ENOTNAM,
525 [ENAVAIL] = TARGET_ENAVAIL,
526 [EISNAM] = TARGET_EISNAM,
527 [EREMOTEIO] = TARGET_EREMOTEIO,
528 [ESHUTDOWN] = TARGET_ESHUTDOWN,
529 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
530 [ETIMEDOUT] = TARGET_ETIMEDOUT,
531 [ECONNREFUSED] = TARGET_ECONNREFUSED,
532 [EHOSTDOWN] = TARGET_EHOSTDOWN,
533 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
534 [EALREADY] = TARGET_EALREADY,
535 [EINPROGRESS] = TARGET_EINPROGRESS,
536 [ESTALE] = TARGET_ESTALE,
537 [ECANCELED] = TARGET_ECANCELED,
538 [ENOMEDIUM] = TARGET_ENOMEDIUM,
539 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000540#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000541 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000542#endif
543#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000544 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000545#endif
546#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000547 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000548#endif
549#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000550 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000551#endif
552#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000553 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000554#endif
555#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000556 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000557#endif
thsb92c47c2007-11-01 00:07:38 +0000558};
ths637947f2007-06-01 12:09:19 +0000559
560static inline int host_to_target_errno(int err)
561{
562 if(host_to_target_errno_table[err])
563 return host_to_target_errno_table[err];
564 return err;
565}
566
thsb92c47c2007-11-01 00:07:38 +0000567static inline int target_to_host_errno(int err)
568{
569 if (target_to_host_errno_table[err])
570 return target_to_host_errno_table[err];
571 return err;
572}
573
blueswir1992f48a2007-10-14 16:27:31 +0000574static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000575{
576 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000577 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000578 else
579 return ret;
580}
581
blueswir1992f48a2007-10-14 16:27:31 +0000582static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000583{
blueswir1992f48a2007-10-14 16:27:31 +0000584 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000585}
586
thsb92c47c2007-11-01 00:07:38 +0000587char *target_strerror(int err)
588{
Alexander Graf962b2892011-11-21 12:04:07 +0100589 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
590 return NULL;
591 }
thsb92c47c2007-11-01 00:07:38 +0000592 return strerror(target_to_host_errno(err));
593}
594
blueswir1992f48a2007-10-14 16:27:31 +0000595static abi_ulong target_brk;
596static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000597static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000598
blueswir1992f48a2007-10-14 16:27:31 +0000599void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000600{
blueswir14c1de732007-07-07 20:45:44 +0000601 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000602 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000603}
604
vincent4d1de872011-06-14 21:56:33 +0000605//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
606#define DEBUGF_BRK(message, args...)
607
ths0da46a62007-10-20 20:23:07 +0000608/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000609abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000610{
blueswir1992f48a2007-10-14 16:27:31 +0000611 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000612 int new_alloc_size;
613
Paul Brook3a0c6c42012-02-09 19:04:27 +0000614 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000615
vincent4d1de872011-06-14 21:56:33 +0000616 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000617 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000618 return target_brk;
619 }
620 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000621 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
622 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000623 return target_brk;
624 }
bellard31e31b82003-02-18 22:55:36 +0000625
vincent4d1de872011-06-14 21:56:33 +0000626 /* If the new brk is less than the highest page reserved to the
627 * target heap allocation, set it and we're almost done... */
628 if (new_brk <= brk_page) {
629 /* Heap contents are initialized to zero, as for anonymous
630 * mapped pages. */
631 if (new_brk > target_brk) {
632 memset(g2h(target_brk), 0, new_brk - target_brk);
633 }
bellard31e31b82003-02-18 22:55:36 +0000634 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000635 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000636 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000637 }
638
Peter Maydell00faf082011-04-18 16:34:24 +0100639 /* We need to allocate more memory after the brk... Note that
640 * we don't use MAP_FIXED because that will map over the top of
641 * any existing mapping (like the one with the host libc or qemu
642 * itself); instead we treat "mapped but at wrong address" as
643 * a failure and unmap again.
644 */
vincent4d1de872011-06-14 21:56:33 +0000645 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000646 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000647 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100648 MAP_ANON|MAP_PRIVATE, 0, 0));
649
650 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200651 /* Heap contents are initialized to zero, as for anonymous
652 * mapped pages. Technically the new pages are already
653 * initialized to zero since they *are* anonymous mapped
654 * pages, however we have to take care with the contents that
655 * come from the remaining part of the previous page: it may
656 * contains garbage data due to a previous heap usage (grown
657 * then shrunken). */
658 memset(g2h(target_brk), 0, brk_page - target_brk);
659
Peter Maydell00faf082011-04-18 16:34:24 +0100660 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000661 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000662 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
663 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100664 return target_brk;
665 } else if (mapped_addr != -1) {
666 /* Mapped but at wrong address, meaning there wasn't actually
667 * enough space for this brk.
668 */
669 target_munmap(mapped_addr, new_alloc_size);
670 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000671 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000672 }
673 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000674 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100675 }
balrog7ab240a2008-04-26 12:17:34 +0000676
Richard Henderson7dd46c02010-05-03 10:07:49 -0700677#if defined(TARGET_ALPHA)
678 /* We (partially) emulate OSF/1 on Alpha, which requires we
679 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100680 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700681#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100682 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000683 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000684}
685
ths26edcf42007-12-09 02:25:24 +0000686static inline abi_long copy_from_user_fdset(fd_set *fds,
687 abi_ulong target_fds_addr,
688 int n)
bellard31e31b82003-02-18 22:55:36 +0000689{
ths26edcf42007-12-09 02:25:24 +0000690 int i, nw, j, k;
691 abi_ulong b, *target_fds;
692
693 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
694 if (!(target_fds = lock_user(VERIFY_READ,
695 target_fds_addr,
696 sizeof(abi_ulong) * nw,
697 1)))
698 return -TARGET_EFAULT;
699
700 FD_ZERO(fds);
701 k = 0;
702 for (i = 0; i < nw; i++) {
703 /* grab the abi_ulong */
704 __get_user(b, &target_fds[i]);
705 for (j = 0; j < TARGET_ABI_BITS; j++) {
706 /* check the bit inside the abi_ulong */
707 if ((b >> j) & 1)
708 FD_SET(k, fds);
709 k++;
bellard31e31b82003-02-18 22:55:36 +0000710 }
bellard31e31b82003-02-18 22:55:36 +0000711 }
ths26edcf42007-12-09 02:25:24 +0000712
713 unlock_user(target_fds, target_fds_addr, 0);
714
715 return 0;
bellard31e31b82003-02-18 22:55:36 +0000716}
717
Mike Frysinger055e0902011-06-03 17:01:49 -0400718static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
719 abi_ulong target_fds_addr,
720 int n)
721{
722 if (target_fds_addr) {
723 if (copy_from_user_fdset(fds, target_fds_addr, n))
724 return -TARGET_EFAULT;
725 *fds_ptr = fds;
726 } else {
727 *fds_ptr = NULL;
728 }
729 return 0;
730}
731
ths26edcf42007-12-09 02:25:24 +0000732static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
733 const fd_set *fds,
734 int n)
bellard31e31b82003-02-18 22:55:36 +0000735{
bellard31e31b82003-02-18 22:55:36 +0000736 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000737 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000738 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000739
ths26edcf42007-12-09 02:25:24 +0000740 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
741 if (!(target_fds = lock_user(VERIFY_WRITE,
742 target_fds_addr,
743 sizeof(abi_ulong) * nw,
744 0)))
745 return -TARGET_EFAULT;
746
747 k = 0;
748 for (i = 0; i < nw; i++) {
749 v = 0;
750 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000751 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000752 k++;
bellard31e31b82003-02-18 22:55:36 +0000753 }
ths26edcf42007-12-09 02:25:24 +0000754 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000755 }
ths26edcf42007-12-09 02:25:24 +0000756
757 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
758
759 return 0;
bellard31e31b82003-02-18 22:55:36 +0000760}
761
bellardc596ed12003-07-13 17:32:31 +0000762#if defined(__alpha__)
763#define HOST_HZ 1024
764#else
765#define HOST_HZ 100
766#endif
767
blueswir1992f48a2007-10-14 16:27:31 +0000768static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000769{
770#if HOST_HZ == TARGET_HZ
771 return ticks;
772#else
773 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
774#endif
775}
776
bellard579a97f2007-11-11 14:26:47 +0000777static inline abi_long host_to_target_rusage(abi_ulong target_addr,
778 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000779{
pbrook53a59602006-03-25 19:31:22 +0000780 struct target_rusage *target_rusage;
781
bellard579a97f2007-11-11 14:26:47 +0000782 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
783 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200784 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
785 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
786 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
787 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
788 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
789 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
790 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
791 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
792 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
793 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
794 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
795 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
796 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
797 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
798 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
799 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
800 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
801 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000802 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000803
804 return 0;
bellardb4091862003-05-16 15:39:34 +0000805}
806
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200807static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900808{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200809 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300810 rlim_t result;
811
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200812 target_rlim_swap = tswapal(target_rlim);
813 if (target_rlim_swap == TARGET_RLIM_INFINITY)
814 return RLIM_INFINITY;
815
816 result = target_rlim_swap;
817 if (target_rlim_swap != (rlim_t)result)
818 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300819
820 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900821}
822
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200823static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900824{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200825 abi_ulong target_rlim_swap;
826 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300827
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200828 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300829 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900830 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300831 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200832 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300833
834 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900835}
836
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300837static inline int target_to_host_resource(int code)
838{
839 switch (code) {
840 case TARGET_RLIMIT_AS:
841 return RLIMIT_AS;
842 case TARGET_RLIMIT_CORE:
843 return RLIMIT_CORE;
844 case TARGET_RLIMIT_CPU:
845 return RLIMIT_CPU;
846 case TARGET_RLIMIT_DATA:
847 return RLIMIT_DATA;
848 case TARGET_RLIMIT_FSIZE:
849 return RLIMIT_FSIZE;
850 case TARGET_RLIMIT_LOCKS:
851 return RLIMIT_LOCKS;
852 case TARGET_RLIMIT_MEMLOCK:
853 return RLIMIT_MEMLOCK;
854 case TARGET_RLIMIT_MSGQUEUE:
855 return RLIMIT_MSGQUEUE;
856 case TARGET_RLIMIT_NICE:
857 return RLIMIT_NICE;
858 case TARGET_RLIMIT_NOFILE:
859 return RLIMIT_NOFILE;
860 case TARGET_RLIMIT_NPROC:
861 return RLIMIT_NPROC;
862 case TARGET_RLIMIT_RSS:
863 return RLIMIT_RSS;
864 case TARGET_RLIMIT_RTPRIO:
865 return RLIMIT_RTPRIO;
866 case TARGET_RLIMIT_SIGPENDING:
867 return RLIMIT_SIGPENDING;
868 case TARGET_RLIMIT_STACK:
869 return RLIMIT_STACK;
870 default:
871 return code;
872 }
873}
874
ths788f5ec2007-12-09 02:37:05 +0000875static inline abi_long copy_from_user_timeval(struct timeval *tv,
876 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000877{
pbrook53a59602006-03-25 19:31:22 +0000878 struct target_timeval *target_tv;
879
ths788f5ec2007-12-09 02:37:05 +0000880 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000881 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000882
883 __get_user(tv->tv_sec, &target_tv->tv_sec);
884 __get_user(tv->tv_usec, &target_tv->tv_usec);
885
886 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000887
888 return 0;
bellard31e31b82003-02-18 22:55:36 +0000889}
890
ths788f5ec2007-12-09 02:37:05 +0000891static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
892 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000893{
pbrook53a59602006-03-25 19:31:22 +0000894 struct target_timeval *target_tv;
895
ths788f5ec2007-12-09 02:37:05 +0000896 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000897 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000898
899 __put_user(tv->tv_sec, &target_tv->tv_sec);
900 __put_user(tv->tv_usec, &target_tv->tv_usec);
901
902 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000903
904 return 0;
bellard31e31b82003-02-18 22:55:36 +0000905}
906
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700907#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
908#include <mqueue.h>
909
aurel3224e10032009-04-15 16:11:43 +0000910static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
911 abi_ulong target_mq_attr_addr)
912{
913 struct target_mq_attr *target_mq_attr;
914
915 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
916 target_mq_attr_addr, 1))
917 return -TARGET_EFAULT;
918
919 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
920 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
921 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
922 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
923
924 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
925
926 return 0;
927}
928
929static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
930 const struct mq_attr *attr)
931{
932 struct target_mq_attr *target_mq_attr;
933
934 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
935 target_mq_attr_addr, 0))
936 return -TARGET_EFAULT;
937
938 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
939 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
940 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
941 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
942
943 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
944
945 return 0;
946}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700947#endif
bellard31e31b82003-02-18 22:55:36 +0000948
Mike Frysinger055e0902011-06-03 17:01:49 -0400949#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000950/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000951static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000952 abi_ulong rfd_addr, abi_ulong wfd_addr,
953 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000954{
955 fd_set rfds, wfds, efds;
956 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
957 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000958 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000959
Mike Frysinger055e0902011-06-03 17:01:49 -0400960 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
961 if (ret) {
962 return ret;
pbrook53a59602006-03-25 19:31:22 +0000963 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400964 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
965 if (ret) {
966 return ret;
pbrook53a59602006-03-25 19:31:22 +0000967 }
Mike Frysinger055e0902011-06-03 17:01:49 -0400968 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
969 if (ret) {
970 return ret;
pbrook53a59602006-03-25 19:31:22 +0000971 }
ths3b46e622007-09-17 08:09:54 +0000972
ths26edcf42007-12-09 02:25:24 +0000973 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +0000974 if (copy_from_user_timeval(&tv, target_tv_addr))
975 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000976 tv_ptr = &tv;
977 } else {
978 tv_ptr = NULL;
979 }
ths26edcf42007-12-09 02:25:24 +0000980
bellard31e31b82003-02-18 22:55:36 +0000981 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +0000982
ths26edcf42007-12-09 02:25:24 +0000983 if (!is_error(ret)) {
984 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
985 return -TARGET_EFAULT;
986 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
987 return -TARGET_EFAULT;
988 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
989 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000990
ths788f5ec2007-12-09 02:37:05 +0000991 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
992 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +0000993 }
bellard579a97f2007-11-11 14:26:47 +0000994
bellard31e31b82003-02-18 22:55:36 +0000995 return ret;
996}
Mike Frysinger055e0902011-06-03 17:01:49 -0400997#endif
bellard31e31b82003-02-18 22:55:36 +0000998
Riku Voipio099d6b02009-05-05 12:10:04 +0300999static abi_long do_pipe2(int host_pipe[], int flags)
1000{
1001#ifdef CONFIG_PIPE2
1002 return pipe2(host_pipe, flags);
1003#else
1004 return -ENOSYS;
1005#endif
1006}
1007
Richard Hendersonfb41a662010-05-03 10:07:52 -07001008static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1009 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001010{
1011 int host_pipe[2];
1012 abi_long ret;
1013 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1014
1015 if (is_error(ret))
1016 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001017
1018 /* Several targets have special calling conventions for the original
1019 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1020 if (!is_pipe2) {
1021#if defined(TARGET_ALPHA)
1022 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1023 return host_pipe[0];
1024#elif defined(TARGET_MIPS)
1025 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1026 return host_pipe[0];
1027#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001028 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001029 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001030#elif defined(TARGET_SPARC)
1031 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1032 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001033#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001034 }
1035
Riku Voipio099d6b02009-05-05 12:10:04 +03001036 if (put_user_s32(host_pipe[0], pipedes)
1037 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1038 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001039 return get_errno(ret);
1040}
1041
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001042static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1043 abi_ulong target_addr,
1044 socklen_t len)
1045{
1046 struct target_ip_mreqn *target_smreqn;
1047
1048 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1049 if (!target_smreqn)
1050 return -TARGET_EFAULT;
1051 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1052 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1053 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001054 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001055 unlock_user(target_smreqn, target_addr, 0);
1056
1057 return 0;
1058}
1059
bellard579a97f2007-11-11 14:26:47 +00001060static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1061 abi_ulong target_addr,
1062 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001063{
aurel32607175e2009-04-15 16:11:59 +00001064 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1065 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001066 struct target_sockaddr *target_saddr;
1067
bellard579a97f2007-11-11 14:26:47 +00001068 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1069 if (!target_saddr)
1070 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001071
1072 sa_family = tswap16(target_saddr->sa_family);
1073
1074 /* Oops. The caller might send a incomplete sun_path; sun_path
1075 * must be terminated by \0 (see the manual page), but
1076 * unfortunately it is quite common to specify sockaddr_un
1077 * length as "strlen(x->sun_path)" while it should be
1078 * "strlen(...) + 1". We'll fix that here if needed.
1079 * Linux kernel has a similar feature.
1080 */
1081
1082 if (sa_family == AF_UNIX) {
1083 if (len < unix_maxlen && len > 0) {
1084 char *cp = (char*)target_saddr;
1085
1086 if ( cp[len-1] && !cp[len] )
1087 len++;
1088 }
1089 if (len > unix_maxlen)
1090 len = unix_maxlen;
1091 }
1092
pbrook53a59602006-03-25 19:31:22 +00001093 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001094 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001095 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001096
1097 return 0;
bellard7854b052003-03-29 17:22:23 +00001098}
1099
bellard579a97f2007-11-11 14:26:47 +00001100static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1101 struct sockaddr *addr,
1102 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001103{
pbrook53a59602006-03-25 19:31:22 +00001104 struct target_sockaddr *target_saddr;
1105
bellard579a97f2007-11-11 14:26:47 +00001106 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1107 if (!target_saddr)
1108 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001109 memcpy(target_saddr, addr, len);
1110 target_saddr->sa_family = tswap16(addr->sa_family);
1111 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001112
1113 return 0;
bellard7854b052003-03-29 17:22:23 +00001114}
1115
bellard5a4a8982007-11-11 17:39:18 +00001116static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1117 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001118{
1119 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001120 abi_long msg_controllen;
1121 abi_ulong target_cmsg_addr;
1122 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001123 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001124
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001125 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001126 if (msg_controllen < sizeof (struct target_cmsghdr))
1127 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001128 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001129 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1130 if (!target_cmsg)
1131 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001132
1133 while (cmsg && target_cmsg) {
1134 void *data = CMSG_DATA(cmsg);
1135 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1136
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001137 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001138 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1139
1140 space += CMSG_SPACE(len);
1141 if (space > msgh->msg_controllen) {
1142 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001143 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001144 break;
1145 }
1146
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001147 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1148 cmsg->cmsg_level = SOL_SOCKET;
1149 } else {
1150 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1151 }
bellard7854b052003-03-29 17:22:23 +00001152 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1153 cmsg->cmsg_len = CMSG_LEN(len);
1154
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001155 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001156 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1157 memcpy(data, target_data, len);
1158 } else {
1159 int *fd = (int *)data;
1160 int *target_fd = (int *)target_data;
1161 int i, numfds = len / sizeof(int);
1162
1163 for (i = 0; i < numfds; i++)
1164 fd[i] = tswap32(target_fd[i]);
1165 }
1166
1167 cmsg = CMSG_NXTHDR(msgh, cmsg);
1168 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1169 }
bellard5a4a8982007-11-11 17:39:18 +00001170 unlock_user(target_cmsg, target_cmsg_addr, 0);
1171 the_end:
bellard7854b052003-03-29 17:22:23 +00001172 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001173 return 0;
bellard7854b052003-03-29 17:22:23 +00001174}
1175
bellard5a4a8982007-11-11 17:39:18 +00001176static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1177 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001178{
1179 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001180 abi_long msg_controllen;
1181 abi_ulong target_cmsg_addr;
1182 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001183 socklen_t space = 0;
1184
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001185 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001186 if (msg_controllen < sizeof (struct target_cmsghdr))
1187 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001188 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001189 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1190 if (!target_cmsg)
1191 return -TARGET_EFAULT;
1192
bellard7854b052003-03-29 17:22:23 +00001193 while (cmsg && target_cmsg) {
1194 void *data = CMSG_DATA(cmsg);
1195 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1196
1197 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1198
1199 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001200 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001201 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001202 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001203 break;
1204 }
1205
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001206 if (cmsg->cmsg_level == SOL_SOCKET) {
1207 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1208 } else {
1209 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1210 }
bellard7854b052003-03-29 17:22:23 +00001211 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001212 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001213
Huw Davies52b65492014-04-17 14:02:47 +01001214 switch (cmsg->cmsg_level) {
1215 case SOL_SOCKET:
1216 switch (cmsg->cmsg_type) {
1217 case SCM_RIGHTS:
1218 {
1219 int *fd = (int *)data;
1220 int *target_fd = (int *)target_data;
1221 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001222
Huw Davies52b65492014-04-17 14:02:47 +01001223 for (i = 0; i < numfds; i++)
1224 target_fd[i] = tswap32(fd[i]);
1225 break;
1226 }
1227 case SO_TIMESTAMP:
1228 {
1229 struct timeval *tv = (struct timeval *)data;
1230 struct target_timeval *target_tv =
1231 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001232
Huw Davies52b65492014-04-17 14:02:47 +01001233 if (len != sizeof(struct timeval))
1234 goto unimplemented;
1235
1236 /* copy struct timeval to target */
1237 target_tv->tv_sec = tswapal(tv->tv_sec);
1238 target_tv->tv_usec = tswapal(tv->tv_usec);
1239 break;
1240 }
Huw Davies4bc29752014-04-17 14:02:48 +01001241 case SCM_CREDENTIALS:
1242 {
1243 struct ucred *cred = (struct ucred *)data;
1244 struct target_ucred *target_cred =
1245 (struct target_ucred *)target_data;
1246
1247 __put_user(cred->pid, &target_cred->pid);
1248 __put_user(cred->uid, &target_cred->uid);
1249 __put_user(cred->gid, &target_cred->gid);
1250 break;
1251 }
Huw Davies52b65492014-04-17 14:02:47 +01001252 default:
1253 goto unimplemented;
1254 }
1255 break;
1256
1257 default:
1258 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001259 gemu_log("Unsupported ancillary data: %d/%d\n",
1260 cmsg->cmsg_level, cmsg->cmsg_type);
1261 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001262 }
1263
1264 cmsg = CMSG_NXTHDR(msgh, cmsg);
1265 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1266 }
bellard5a4a8982007-11-11 17:39:18 +00001267 unlock_user(target_cmsg, target_cmsg_addr, space);
1268 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001269 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001270 return 0;
bellard7854b052003-03-29 17:22:23 +00001271}
1272
ths0da46a62007-10-20 20:23:07 +00001273/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001274static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001275 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001276{
blueswir1992f48a2007-10-14 16:27:31 +00001277 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001278 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001279 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001280 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001281
bellard8853f862004-02-22 14:57:26 +00001282 switch(level) {
1283 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001284 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001285 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001286 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001287
bellard2f619692007-11-16 10:46:05 +00001288 if (get_user_u32(val, optval_addr))
1289 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001290 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1291 break;
1292 case SOL_IP:
1293 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001294 case IP_TOS:
1295 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001296 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001297 case IP_ROUTER_ALERT:
1298 case IP_RECVOPTS:
1299 case IP_RETOPTS:
1300 case IP_PKTINFO:
1301 case IP_MTU_DISCOVER:
1302 case IP_RECVERR:
1303 case IP_RECVTOS:
1304#ifdef IP_FREEBIND
1305 case IP_FREEBIND:
1306#endif
1307 case IP_MULTICAST_TTL:
1308 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001309 val = 0;
1310 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001311 if (get_user_u32(val, optval_addr))
1312 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001313 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001314 if (get_user_u8(val, optval_addr))
1315 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001316 }
1317 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1318 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001319 case IP_ADD_MEMBERSHIP:
1320 case IP_DROP_MEMBERSHIP:
1321 if (optlen < sizeof (struct target_ip_mreq) ||
1322 optlen > sizeof (struct target_ip_mreqn))
1323 return -TARGET_EINVAL;
1324
1325 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1326 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1327 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1328 break;
1329
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001330 case IP_BLOCK_SOURCE:
1331 case IP_UNBLOCK_SOURCE:
1332 case IP_ADD_SOURCE_MEMBERSHIP:
1333 case IP_DROP_SOURCE_MEMBERSHIP:
1334 if (optlen != sizeof (struct target_ip_mreq_source))
1335 return -TARGET_EINVAL;
1336
1337 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1338 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1339 unlock_user (ip_mreq_source, optval_addr, 0);
1340 break;
1341
bellard8853f862004-02-22 14:57:26 +00001342 default:
1343 goto unimplemented;
1344 }
1345 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001346 case SOL_IPV6:
1347 switch (optname) {
1348 case IPV6_MTU_DISCOVER:
1349 case IPV6_MTU:
1350 case IPV6_V6ONLY:
1351 case IPV6_RECVPKTINFO:
1352 val = 0;
1353 if (optlen < sizeof(uint32_t)) {
1354 return -TARGET_EINVAL;
1355 }
1356 if (get_user_u32(val, optval_addr)) {
1357 return -TARGET_EFAULT;
1358 }
1359 ret = get_errno(setsockopt(sockfd, level, optname,
1360 &val, sizeof(val)));
1361 break;
1362 default:
1363 goto unimplemented;
1364 }
1365 break;
Jing Huang920394d2012-07-24 13:59:23 +00001366 case SOL_RAW:
1367 switch (optname) {
1368 case ICMP_FILTER:
1369 /* struct icmp_filter takes an u32 value */
1370 if (optlen < sizeof(uint32_t)) {
1371 return -TARGET_EINVAL;
1372 }
1373
1374 if (get_user_u32(val, optval_addr)) {
1375 return -TARGET_EFAULT;
1376 }
1377 ret = get_errno(setsockopt(sockfd, level, optname,
1378 &val, sizeof(val)));
1379 break;
1380
1381 default:
1382 goto unimplemented;
1383 }
1384 break;
bellard3532fa72006-06-24 15:06:03 +00001385 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001386 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001387 case TARGET_SO_RCVTIMEO:
1388 {
1389 struct timeval tv;
1390
1391 optname = SO_RCVTIMEO;
1392
1393set_timeout:
1394 if (optlen != sizeof(struct target_timeval)) {
1395 return -TARGET_EINVAL;
1396 }
1397
1398 if (copy_from_user_timeval(&tv, optval_addr)) {
1399 return -TARGET_EFAULT;
1400 }
1401
1402 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1403 &tv, sizeof(tv)));
1404 return ret;
1405 }
1406 case TARGET_SO_SNDTIMEO:
1407 optname = SO_SNDTIMEO;
1408 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001409 case TARGET_SO_ATTACH_FILTER:
1410 {
1411 struct target_sock_fprog *tfprog;
1412 struct target_sock_filter *tfilter;
1413 struct sock_fprog fprog;
1414 struct sock_filter *filter;
1415 int i;
1416
1417 if (optlen != sizeof(*tfprog)) {
1418 return -TARGET_EINVAL;
1419 }
1420 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1421 return -TARGET_EFAULT;
1422 }
1423 if (!lock_user_struct(VERIFY_READ, tfilter,
1424 tswapal(tfprog->filter), 0)) {
1425 unlock_user_struct(tfprog, optval_addr, 1);
1426 return -TARGET_EFAULT;
1427 }
1428
1429 fprog.len = tswap16(tfprog->len);
1430 filter = malloc(fprog.len * sizeof(*filter));
1431 if (filter == NULL) {
1432 unlock_user_struct(tfilter, tfprog->filter, 1);
1433 unlock_user_struct(tfprog, optval_addr, 1);
1434 return -TARGET_ENOMEM;
1435 }
1436 for (i = 0; i < fprog.len; i++) {
1437 filter[i].code = tswap16(tfilter[i].code);
1438 filter[i].jt = tfilter[i].jt;
1439 filter[i].jf = tfilter[i].jf;
1440 filter[i].k = tswap32(tfilter[i].k);
1441 }
1442 fprog.filter = filter;
1443
1444 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1445 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1446 free(filter);
1447
1448 unlock_user_struct(tfilter, tfprog->filter, 1);
1449 unlock_user_struct(tfprog, optval_addr, 1);
1450 return ret;
1451 }
bellard8853f862004-02-22 14:57:26 +00001452 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001453 case TARGET_SO_DEBUG:
1454 optname = SO_DEBUG;
1455 break;
1456 case TARGET_SO_REUSEADDR:
1457 optname = SO_REUSEADDR;
1458 break;
1459 case TARGET_SO_TYPE:
1460 optname = SO_TYPE;
1461 break;
1462 case TARGET_SO_ERROR:
1463 optname = SO_ERROR;
1464 break;
1465 case TARGET_SO_DONTROUTE:
1466 optname = SO_DONTROUTE;
1467 break;
1468 case TARGET_SO_BROADCAST:
1469 optname = SO_BROADCAST;
1470 break;
1471 case TARGET_SO_SNDBUF:
1472 optname = SO_SNDBUF;
1473 break;
1474 case TARGET_SO_RCVBUF:
1475 optname = SO_RCVBUF;
1476 break;
1477 case TARGET_SO_KEEPALIVE:
1478 optname = SO_KEEPALIVE;
1479 break;
1480 case TARGET_SO_OOBINLINE:
1481 optname = SO_OOBINLINE;
1482 break;
1483 case TARGET_SO_NO_CHECK:
1484 optname = SO_NO_CHECK;
1485 break;
1486 case TARGET_SO_PRIORITY:
1487 optname = SO_PRIORITY;
1488 break;
bellard5e83e8e2005-03-01 22:32:06 +00001489#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001490 case TARGET_SO_BSDCOMPAT:
1491 optname = SO_BSDCOMPAT;
1492 break;
bellard5e83e8e2005-03-01 22:32:06 +00001493#endif
bellard3532fa72006-06-24 15:06:03 +00001494 case TARGET_SO_PASSCRED:
1495 optname = SO_PASSCRED;
1496 break;
1497 case TARGET_SO_TIMESTAMP:
1498 optname = SO_TIMESTAMP;
1499 break;
1500 case TARGET_SO_RCVLOWAT:
1501 optname = SO_RCVLOWAT;
1502 break;
bellard8853f862004-02-22 14:57:26 +00001503 break;
1504 default:
1505 goto unimplemented;
1506 }
bellard3532fa72006-06-24 15:06:03 +00001507 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001508 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001509
bellard2f619692007-11-16 10:46:05 +00001510 if (get_user_u32(val, optval_addr))
1511 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001512 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001513 break;
bellard7854b052003-03-29 17:22:23 +00001514 default:
bellard8853f862004-02-22 14:57:26 +00001515 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001516 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001517 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001518 }
bellard8853f862004-02-22 14:57:26 +00001519 return ret;
bellard7854b052003-03-29 17:22:23 +00001520}
1521
ths0da46a62007-10-20 20:23:07 +00001522/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001523static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001524 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001525{
blueswir1992f48a2007-10-14 16:27:31 +00001526 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001527 int len, val;
1528 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001529
1530 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001531 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001532 level = SOL_SOCKET;
1533 switch (optname) {
1534 /* These don't just return a single integer */
1535 case TARGET_SO_LINGER:
1536 case TARGET_SO_RCVTIMEO:
1537 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001538 case TARGET_SO_PEERNAME:
1539 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001540 case TARGET_SO_PEERCRED: {
1541 struct ucred cr;
1542 socklen_t crlen;
1543 struct target_ucred *tcr;
1544
1545 if (get_user_u32(len, optlen)) {
1546 return -TARGET_EFAULT;
1547 }
1548 if (len < 0) {
1549 return -TARGET_EINVAL;
1550 }
1551
1552 crlen = sizeof(cr);
1553 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1554 &cr, &crlen));
1555 if (ret < 0) {
1556 return ret;
1557 }
1558 if (len > crlen) {
1559 len = crlen;
1560 }
1561 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1562 return -TARGET_EFAULT;
1563 }
1564 __put_user(cr.pid, &tcr->pid);
1565 __put_user(cr.uid, &tcr->uid);
1566 __put_user(cr.gid, &tcr->gid);
1567 unlock_user_struct(tcr, optval_addr, 1);
1568 if (put_user_u32(len, optlen)) {
1569 return -TARGET_EFAULT;
1570 }
1571 break;
1572 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001573 /* Options with 'int' argument. */
1574 case TARGET_SO_DEBUG:
1575 optname = SO_DEBUG;
1576 goto int_case;
1577 case TARGET_SO_REUSEADDR:
1578 optname = SO_REUSEADDR;
1579 goto int_case;
1580 case TARGET_SO_TYPE:
1581 optname = SO_TYPE;
1582 goto int_case;
1583 case TARGET_SO_ERROR:
1584 optname = SO_ERROR;
1585 goto int_case;
1586 case TARGET_SO_DONTROUTE:
1587 optname = SO_DONTROUTE;
1588 goto int_case;
1589 case TARGET_SO_BROADCAST:
1590 optname = SO_BROADCAST;
1591 goto int_case;
1592 case TARGET_SO_SNDBUF:
1593 optname = SO_SNDBUF;
1594 goto int_case;
1595 case TARGET_SO_RCVBUF:
1596 optname = SO_RCVBUF;
1597 goto int_case;
1598 case TARGET_SO_KEEPALIVE:
1599 optname = SO_KEEPALIVE;
1600 goto int_case;
1601 case TARGET_SO_OOBINLINE:
1602 optname = SO_OOBINLINE;
1603 goto int_case;
1604 case TARGET_SO_NO_CHECK:
1605 optname = SO_NO_CHECK;
1606 goto int_case;
1607 case TARGET_SO_PRIORITY:
1608 optname = SO_PRIORITY;
1609 goto int_case;
1610#ifdef SO_BSDCOMPAT
1611 case TARGET_SO_BSDCOMPAT:
1612 optname = SO_BSDCOMPAT;
1613 goto int_case;
1614#endif
1615 case TARGET_SO_PASSCRED:
1616 optname = SO_PASSCRED;
1617 goto int_case;
1618 case TARGET_SO_TIMESTAMP:
1619 optname = SO_TIMESTAMP;
1620 goto int_case;
1621 case TARGET_SO_RCVLOWAT:
1622 optname = SO_RCVLOWAT;
1623 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001624 default:
bellard2efbe912005-07-23 15:10:20 +00001625 goto int_case;
1626 }
1627 break;
1628 case SOL_TCP:
1629 /* TCP options all take an 'int' value. */
1630 int_case:
bellard2f619692007-11-16 10:46:05 +00001631 if (get_user_u32(len, optlen))
1632 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001633 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001634 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001635 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001636 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1637 if (ret < 0)
1638 return ret;
bellard2efbe912005-07-23 15:10:20 +00001639 if (len > lv)
1640 len = lv;
bellard2f619692007-11-16 10:46:05 +00001641 if (len == 4) {
1642 if (put_user_u32(val, optval_addr))
1643 return -TARGET_EFAULT;
1644 } else {
1645 if (put_user_u8(val, optval_addr))
1646 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001647 }
bellard2f619692007-11-16 10:46:05 +00001648 if (put_user_u32(len, optlen))
1649 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001650 break;
1651 case SOL_IP:
1652 switch(optname) {
1653 case IP_TOS:
1654 case IP_TTL:
1655 case IP_HDRINCL:
1656 case IP_ROUTER_ALERT:
1657 case IP_RECVOPTS:
1658 case IP_RETOPTS:
1659 case IP_PKTINFO:
1660 case IP_MTU_DISCOVER:
1661 case IP_RECVERR:
1662 case IP_RECVTOS:
1663#ifdef IP_FREEBIND
1664 case IP_FREEBIND:
1665#endif
1666 case IP_MULTICAST_TTL:
1667 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001668 if (get_user_u32(len, optlen))
1669 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001670 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001671 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001672 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001673 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1674 if (ret < 0)
1675 return ret;
bellard2efbe912005-07-23 15:10:20 +00001676 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001677 len = 1;
bellard2f619692007-11-16 10:46:05 +00001678 if (put_user_u32(len, optlen)
1679 || put_user_u8(val, optval_addr))
1680 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001681 } else {
bellard2efbe912005-07-23 15:10:20 +00001682 if (len > sizeof(int))
1683 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001684 if (put_user_u32(len, optlen)
1685 || put_user_u32(val, optval_addr))
1686 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001687 }
bellard8853f862004-02-22 14:57:26 +00001688 break;
bellard2efbe912005-07-23 15:10:20 +00001689 default:
thsc02f4992007-12-18 02:39:59 +00001690 ret = -TARGET_ENOPROTOOPT;
1691 break;
bellard8853f862004-02-22 14:57:26 +00001692 }
1693 break;
1694 default:
1695 unimplemented:
1696 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1697 level, optname);
thsc02f4992007-12-18 02:39:59 +00001698 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001699 break;
1700 }
1701 return ret;
bellard7854b052003-03-29 17:22:23 +00001702}
1703
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001704static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1705 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001706{
1707 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001708 struct iovec *vec;
1709 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001710 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001711 int err = 0;
pbrook53a59602006-03-25 19:31:22 +00001712
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001713 if (count == 0) {
1714 errno = 0;
1715 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001716 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001717 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001718 errno = EINVAL;
1719 return NULL;
1720 }
1721
1722 vec = calloc(count, sizeof(struct iovec));
1723 if (vec == NULL) {
1724 errno = ENOMEM;
1725 return NULL;
1726 }
1727
1728 target_vec = lock_user(VERIFY_READ, target_addr,
1729 count * sizeof(struct target_iovec), 1);
1730 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001731 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001732 goto fail2;
1733 }
1734
1735 /* ??? If host page size > target page size, this will result in a
1736 value larger than what we can actually support. */
1737 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1738 total_len = 0;
1739
1740 for (i = 0; i < count; i++) {
1741 abi_ulong base = tswapal(target_vec[i].iov_base);
1742 abi_long len = tswapal(target_vec[i].iov_len);
1743
1744 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001745 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001746 goto fail;
1747 } else if (len == 0) {
1748 /* Zero length pointer is ignored. */
1749 vec[i].iov_base = 0;
1750 } else {
1751 vec[i].iov_base = lock_user(type, base, len, copy);
1752 if (!vec[i].iov_base) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001753 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001754 goto fail;
1755 }
1756 if (len > max_len - total_len) {
1757 len = max_len - total_len;
1758 }
1759 }
1760 vec[i].iov_len = len;
1761 total_len += len;
1762 }
1763
1764 unlock_user(target_vec, target_addr, 0);
1765 return vec;
1766
1767 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001768 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001769 fail2:
1770 free(vec);
1771 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001772 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001773}
1774
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001775static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1776 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001777{
1778 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001779 int i;
1780
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001781 target_vec = lock_user(VERIFY_READ, target_addr,
1782 count * sizeof(struct target_iovec), 1);
1783 if (target_vec) {
1784 for (i = 0; i < count; i++) {
1785 abi_ulong base = tswapal(target_vec[i].iov_base);
1786 abi_long len = tswapal(target_vec[i].iov_base);
1787 if (len < 0) {
1788 break;
1789 }
balrogd732dcb2008-10-28 10:21:03 +00001790 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1791 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001792 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001793 }
bellard579a97f2007-11-11 14:26:47 +00001794
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001795 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001796}
1797
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001798static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001799{
1800 int host_type = 0;
1801 int target_type = *type;
1802
1803 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1804 case TARGET_SOCK_DGRAM:
1805 host_type = SOCK_DGRAM;
1806 break;
1807 case TARGET_SOCK_STREAM:
1808 host_type = SOCK_STREAM;
1809 break;
1810 default:
1811 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1812 break;
1813 }
1814 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001815#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001816 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001817#else
1818 return -TARGET_EINVAL;
1819#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001820 }
1821 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001822#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001823 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001824#elif !defined(O_NONBLOCK)
1825 return -TARGET_EINVAL;
1826#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001827 }
1828 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001829 return 0;
1830}
1831
1832/* Try to emulate socket type flags after socket creation. */
1833static int sock_flags_fixup(int fd, int target_type)
1834{
1835#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1836 if (target_type & TARGET_SOCK_NONBLOCK) {
1837 int flags = fcntl(fd, F_GETFL);
1838 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1839 close(fd);
1840 return -TARGET_EINVAL;
1841 }
1842 }
1843#endif
1844 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001845}
1846
ths0da46a62007-10-20 20:23:07 +00001847/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001848static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001849{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001850 int target_type = type;
1851 int ret;
1852
1853 ret = target_to_host_sock_type(&type);
1854 if (ret) {
1855 return ret;
1856 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001857
balrog12bc92a2007-10-30 21:06:14 +00001858 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07001859 return -TARGET_EAFNOSUPPORT;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001860 ret = get_errno(socket(domain, type, protocol));
1861 if (ret >= 0) {
1862 ret = sock_flags_fixup(ret, target_type);
1863 }
1864 return ret;
bellard3532fa72006-06-24 15:06:03 +00001865}
1866
ths0da46a62007-10-20 20:23:07 +00001867/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001868static abi_long do_bind(int sockfd, abi_ulong target_addr,
1869 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001870{
aurel328f7aeaf2009-01-30 19:47:57 +00001871 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001872 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001873
Blue Swirl38724252010-09-18 05:53:14 +00001874 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001875 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001876 }
aurel328f7aeaf2009-01-30 19:47:57 +00001877
aurel32607175e2009-04-15 16:11:59 +00001878 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001879
Arnaud Patard917507b2009-06-19 10:44:45 +03001880 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1881 if (ret)
1882 return ret;
1883
bellard3532fa72006-06-24 15:06:03 +00001884 return get_errno(bind(sockfd, addr, addrlen));
1885}
1886
ths0da46a62007-10-20 20:23:07 +00001887/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001888static abi_long do_connect(int sockfd, abi_ulong target_addr,
1889 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001890{
aurel328f7aeaf2009-01-30 19:47:57 +00001891 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001892 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001893
Blue Swirl38724252010-09-18 05:53:14 +00001894 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001895 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001896 }
aurel328f7aeaf2009-01-30 19:47:57 +00001897
1898 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001899
Arnaud Patard917507b2009-06-19 10:44:45 +03001900 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1901 if (ret)
1902 return ret;
1903
bellard3532fa72006-06-24 15:06:03 +00001904 return get_errno(connect(sockfd, addr, addrlen));
1905}
1906
Alexander Graff19e00d2014-03-02 19:36:42 +00001907/* do_sendrecvmsg_locked() Must return target values and target errnos. */
1908static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
1909 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001910{
balrog6de645c2008-10-28 10:26:29 +00001911 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001912 struct msghdr msg;
1913 int count;
1914 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001915 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001916
bellard3532fa72006-06-24 15:06:03 +00001917 if (msgp->msg_name) {
1918 msg.msg_namelen = tswap32(msgp->msg_namelen);
1919 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001920 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001921 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001922 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001923 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001924 }
bellard3532fa72006-06-24 15:06:03 +00001925 } else {
1926 msg.msg_name = NULL;
1927 msg.msg_namelen = 0;
1928 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001929 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001930 msg.msg_control = alloca(msg.msg_controllen);
1931 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001932
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001933 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001934 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001935 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1936 target_vec, count, send);
1937 if (vec == NULL) {
1938 ret = -host_to_target_errno(errno);
1939 goto out2;
1940 }
bellard3532fa72006-06-24 15:06:03 +00001941 msg.msg_iovlen = count;
1942 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001943
bellard3532fa72006-06-24 15:06:03 +00001944 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001945 ret = target_to_host_cmsg(&msg, msgp);
1946 if (ret == 0)
1947 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001948 } else {
1949 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001950 if (!is_error(ret)) {
1951 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001952 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001953 if (!is_error(ret)) {
1954 msgp->msg_namelen = tswap32(msg.msg_namelen);
1955 if (msg.msg_name != NULL) {
1956 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1957 msg.msg_name, msg.msg_namelen);
1958 if (ret) {
1959 goto out;
1960 }
1961 }
1962
balrog6de645c2008-10-28 10:26:29 +00001963 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00001964 }
balrog6de645c2008-10-28 10:26:29 +00001965 }
bellard3532fa72006-06-24 15:06:03 +00001966 }
Jing Huangca619062012-07-24 13:58:02 +00001967
1968out:
bellard3532fa72006-06-24 15:06:03 +00001969 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001970out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00001971 return ret;
1972}
1973
1974static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
1975 int flags, int send)
1976{
1977 abi_long ret;
1978 struct target_msghdr *msgp;
1979
1980 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
1981 msgp,
1982 target_msg,
1983 send ? 1 : 0)) {
1984 return -TARGET_EFAULT;
1985 }
1986 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00001987 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00001988 return ret;
1989}
1990
Alexander Graff19e00d2014-03-02 19:36:42 +00001991#ifdef TARGET_NR_sendmmsg
1992/* We don't rely on the C library to have sendmmsg/recvmmsg support,
1993 * so it might not have this *mmsg-specific flag either.
1994 */
1995#ifndef MSG_WAITFORONE
1996#define MSG_WAITFORONE 0x10000
1997#endif
1998
1999static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2000 unsigned int vlen, unsigned int flags,
2001 int send)
2002{
2003 struct target_mmsghdr *mmsgp;
2004 abi_long ret = 0;
2005 int i;
2006
2007 if (vlen > UIO_MAXIOV) {
2008 vlen = UIO_MAXIOV;
2009 }
2010
2011 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2012 if (!mmsgp) {
2013 return -TARGET_EFAULT;
2014 }
2015
2016 for (i = 0; i < vlen; i++) {
2017 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2018 if (is_error(ret)) {
2019 break;
2020 }
2021 mmsgp[i].msg_len = tswap32(ret);
2022 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2023 if (flags & MSG_WAITFORONE) {
2024 flags |= MSG_DONTWAIT;
2025 }
2026 }
2027
2028 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2029
2030 /* Return number of datagrams sent if we sent any at all;
2031 * otherwise return the error.
2032 */
2033 if (i) {
2034 return i;
2035 }
2036 return ret;
2037}
2038#endif
2039
Peter Maydella94b4982013-02-08 04:35:04 +00002040/* If we don't have a system accept4() then just call accept.
2041 * The callsites to do_accept4() will ensure that they don't
2042 * pass a non-zero flags argument in this config.
2043 */
2044#ifndef CONFIG_ACCEPT4
2045static inline int accept4(int sockfd, struct sockaddr *addr,
2046 socklen_t *addrlen, int flags)
2047{
2048 assert(flags == 0);
2049 return accept(sockfd, addr, addrlen);
2050}
2051#endif
2052
2053/* do_accept4() Must return target values and target errnos. */
2054static abi_long do_accept4(int fd, abi_ulong target_addr,
2055 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002056{
bellard2f619692007-11-16 10:46:05 +00002057 socklen_t addrlen;
2058 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002059 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002060 int host_flags;
2061
2062 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002063
Peter Maydella94b4982013-02-08 04:35:04 +00002064 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002065 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002066 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002067
2068 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002069 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002070 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002071
Blue Swirl38724252010-09-18 05:53:14 +00002072 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002073 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002074 }
aurel328f7aeaf2009-01-30 19:47:57 +00002075
Arnaud Patard917507b2009-06-19 10:44:45 +03002076 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2077 return -TARGET_EINVAL;
2078
bellard2f619692007-11-16 10:46:05 +00002079 addr = alloca(addrlen);
2080
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002081 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002082 if (!is_error(ret)) {
2083 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002084 if (put_user_u32(addrlen, target_addrlen_addr))
2085 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002086 }
2087 return ret;
2088}
2089
ths0da46a62007-10-20 20:23:07 +00002090/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002091static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002092 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002093{
bellard2f619692007-11-16 10:46:05 +00002094 socklen_t addrlen;
2095 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002096 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002097
bellard2f619692007-11-16 10:46:05 +00002098 if (get_user_u32(addrlen, target_addrlen_addr))
2099 return -TARGET_EFAULT;
2100
Blue Swirl38724252010-09-18 05:53:14 +00002101 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002102 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002103 }
aurel328f7aeaf2009-01-30 19:47:57 +00002104
Arnaud Patard917507b2009-06-19 10:44:45 +03002105 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2106 return -TARGET_EFAULT;
2107
bellard2f619692007-11-16 10:46:05 +00002108 addr = alloca(addrlen);
2109
pbrook1be9e1d2006-11-19 15:26:04 +00002110 ret = get_errno(getpeername(fd, addr, &addrlen));
2111 if (!is_error(ret)) {
2112 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002113 if (put_user_u32(addrlen, target_addrlen_addr))
2114 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002115 }
2116 return ret;
2117}
2118
ths0da46a62007-10-20 20:23:07 +00002119/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002120static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002121 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002122{
bellard2f619692007-11-16 10:46:05 +00002123 socklen_t addrlen;
2124 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002125 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002126
bellard2f619692007-11-16 10:46:05 +00002127 if (get_user_u32(addrlen, target_addrlen_addr))
2128 return -TARGET_EFAULT;
2129
Blue Swirl38724252010-09-18 05:53:14 +00002130 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002131 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002132 }
aurel328f7aeaf2009-01-30 19:47:57 +00002133
Arnaud Patard917507b2009-06-19 10:44:45 +03002134 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2135 return -TARGET_EFAULT;
2136
bellard2f619692007-11-16 10:46:05 +00002137 addr = alloca(addrlen);
2138
pbrook1be9e1d2006-11-19 15:26:04 +00002139 ret = get_errno(getsockname(fd, addr, &addrlen));
2140 if (!is_error(ret)) {
2141 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002142 if (put_user_u32(addrlen, target_addrlen_addr))
2143 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002144 }
2145 return ret;
2146}
2147
ths0da46a62007-10-20 20:23:07 +00002148/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002149static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002150 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002151{
2152 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002153 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002154
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002155 target_to_host_sock_type(&type);
2156
pbrook1be9e1d2006-11-19 15:26:04 +00002157 ret = get_errno(socketpair(domain, type, protocol, tab));
2158 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002159 if (put_user_s32(tab[0], target_tab_addr)
2160 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2161 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002162 }
2163 return ret;
2164}
2165
ths0da46a62007-10-20 20:23:07 +00002166/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002167static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2168 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002169{
2170 void *addr;
2171 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002172 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002173
Blue Swirl38724252010-09-18 05:53:14 +00002174 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002175 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002176 }
aurel328f7aeaf2009-01-30 19:47:57 +00002177
bellard579a97f2007-11-11 14:26:47 +00002178 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2179 if (!host_msg)
2180 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002181 if (target_addr) {
2182 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002183 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2184 if (ret) {
2185 unlock_user(host_msg, msg, 0);
2186 return ret;
2187 }
pbrook1be9e1d2006-11-19 15:26:04 +00002188 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2189 } else {
2190 ret = get_errno(send(fd, host_msg, len, flags));
2191 }
2192 unlock_user(host_msg, msg, 0);
2193 return ret;
2194}
2195
ths0da46a62007-10-20 20:23:07 +00002196/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002197static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2198 abi_ulong target_addr,
2199 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002200{
2201 socklen_t addrlen;
2202 void *addr;
2203 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002204 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002205
bellard579a97f2007-11-11 14:26:47 +00002206 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2207 if (!host_msg)
2208 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002209 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002210 if (get_user_u32(addrlen, target_addrlen)) {
2211 ret = -TARGET_EFAULT;
2212 goto fail;
2213 }
Blue Swirl38724252010-09-18 05:53:14 +00002214 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002215 ret = -TARGET_EINVAL;
2216 goto fail;
2217 }
pbrook1be9e1d2006-11-19 15:26:04 +00002218 addr = alloca(addrlen);
2219 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2220 } else {
2221 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002222 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002223 }
2224 if (!is_error(ret)) {
2225 if (target_addr) {
2226 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002227 if (put_user_u32(addrlen, target_addrlen)) {
2228 ret = -TARGET_EFAULT;
2229 goto fail;
2230 }
pbrook1be9e1d2006-11-19 15:26:04 +00002231 }
2232 unlock_user(host_msg, msg, len);
2233 } else {
bellard2f619692007-11-16 10:46:05 +00002234fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002235 unlock_user(host_msg, msg, 0);
2236 }
2237 return ret;
2238}
2239
j_mayer32407102007-09-26 23:01:49 +00002240#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002241/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002242static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002243{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002244 static const unsigned ac[] = { /* number of arguments per call */
2245 [SOCKOP_socket] = 3, /* domain, type, protocol */
2246 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2247 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2248 [SOCKOP_listen] = 2, /* sockfd, backlog */
2249 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2250 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2251 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2252 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2253 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2254 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2255 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2256 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2257 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2258 [SOCKOP_shutdown] = 2, /* sockfd, how */
2259 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2260 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2261 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2262 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2263 };
2264 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002265
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002266 /* first, collect the arguments in a[] according to ac[] */
2267 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2268 unsigned i;
2269 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2270 for (i = 0; i < ac[num]; ++i) {
2271 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002272 return -TARGET_EFAULT;
2273 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002274 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002275 }
bellard2f619692007-11-16 10:46:05 +00002276
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002277 /* now when we have the args, actually handle the call */
2278 switch (num) {
2279 case SOCKOP_socket: /* domain, type, protocol */
2280 return do_socket(a[0], a[1], a[2]);
2281 case SOCKOP_bind: /* sockfd, addr, addrlen */
2282 return do_bind(a[0], a[1], a[2]);
2283 case SOCKOP_connect: /* sockfd, addr, addrlen */
2284 return do_connect(a[0], a[1], a[2]);
2285 case SOCKOP_listen: /* sockfd, backlog */
2286 return get_errno(listen(a[0], a[1]));
2287 case SOCKOP_accept: /* sockfd, addr, addrlen */
2288 return do_accept4(a[0], a[1], a[2], 0);
2289 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2290 return do_accept4(a[0], a[1], a[2], a[3]);
2291 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2292 return do_getsockname(a[0], a[1], a[2]);
2293 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2294 return do_getpeername(a[0], a[1], a[2]);
2295 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2296 return do_socketpair(a[0], a[1], a[2], a[3]);
2297 case SOCKOP_send: /* sockfd, msg, len, flags */
2298 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2299 case SOCKOP_recv: /* sockfd, msg, len, flags */
2300 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2301 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2302 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2303 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2304 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2305 case SOCKOP_shutdown: /* sockfd, how */
2306 return get_errno(shutdown(a[0], a[1]));
2307 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2308 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2309 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2310 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2311 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2312 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2313 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2314 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002315 default:
2316 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002317 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002318 }
bellard31e31b82003-02-18 22:55:36 +00002319}
j_mayer32407102007-09-26 23:01:49 +00002320#endif
bellard31e31b82003-02-18 22:55:36 +00002321
bellard8853f862004-02-22 14:57:26 +00002322#define N_SHM_REGIONS 32
2323
2324static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002325 abi_ulong start;
2326 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002327} shm_regions[N_SHM_REGIONS];
2328
ths3eb6b042007-06-03 14:26:27 +00002329struct target_semid_ds
2330{
2331 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002332 abi_ulong sem_otime;
2333 abi_ulong __unused1;
2334 abi_ulong sem_ctime;
2335 abi_ulong __unused2;
2336 abi_ulong sem_nsems;
2337 abi_ulong __unused3;
2338 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002339};
2340
bellard579a97f2007-11-11 14:26:47 +00002341static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2342 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002343{
2344 struct target_ipc_perm *target_ip;
2345 struct target_semid_ds *target_sd;
2346
bellard579a97f2007-11-11 14:26:47 +00002347 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2348 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002349 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002350 host_ip->__key = tswap32(target_ip->__key);
2351 host_ip->uid = tswap32(target_ip->uid);
2352 host_ip->gid = tswap32(target_ip->gid);
2353 host_ip->cuid = tswap32(target_ip->cuid);
2354 host_ip->cgid = tswap32(target_ip->cgid);
2355#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2356 host_ip->mode = tswap32(target_ip->mode);
2357#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002358 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002359#endif
2360#if defined(TARGET_PPC)
2361 host_ip->__seq = tswap32(target_ip->__seq);
2362#else
2363 host_ip->__seq = tswap16(target_ip->__seq);
2364#endif
ths3eb6b042007-06-03 14:26:27 +00002365 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002366 return 0;
ths3eb6b042007-06-03 14:26:27 +00002367}
2368
bellard579a97f2007-11-11 14:26:47 +00002369static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2370 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002371{
2372 struct target_ipc_perm *target_ip;
2373 struct target_semid_ds *target_sd;
2374
bellard579a97f2007-11-11 14:26:47 +00002375 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2376 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002377 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002378 target_ip->__key = tswap32(host_ip->__key);
2379 target_ip->uid = tswap32(host_ip->uid);
2380 target_ip->gid = tswap32(host_ip->gid);
2381 target_ip->cuid = tswap32(host_ip->cuid);
2382 target_ip->cgid = tswap32(host_ip->cgid);
2383#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2384 target_ip->mode = tswap32(host_ip->mode);
2385#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002386 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002387#endif
2388#if defined(TARGET_PPC)
2389 target_ip->__seq = tswap32(host_ip->__seq);
2390#else
2391 target_ip->__seq = tswap16(host_ip->__seq);
2392#endif
ths3eb6b042007-06-03 14:26:27 +00002393 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002394 return 0;
ths3eb6b042007-06-03 14:26:27 +00002395}
2396
bellard579a97f2007-11-11 14:26:47 +00002397static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2398 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002399{
2400 struct target_semid_ds *target_sd;
2401
bellard579a97f2007-11-11 14:26:47 +00002402 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2403 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002404 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2405 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002406 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2407 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2408 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002409 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002410 return 0;
ths3eb6b042007-06-03 14:26:27 +00002411}
2412
bellard579a97f2007-11-11 14:26:47 +00002413static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2414 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002415{
2416 struct target_semid_ds *target_sd;
2417
bellard579a97f2007-11-11 14:26:47 +00002418 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2419 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002420 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002421 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002422 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2423 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2424 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002425 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002426 return 0;
ths3eb6b042007-06-03 14:26:27 +00002427}
2428
aurel32e5289082009-04-18 16:16:12 +00002429struct target_seminfo {
2430 int semmap;
2431 int semmni;
2432 int semmns;
2433 int semmnu;
2434 int semmsl;
2435 int semopm;
2436 int semume;
2437 int semusz;
2438 int semvmx;
2439 int semaem;
2440};
2441
2442static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2443 struct seminfo *host_seminfo)
2444{
2445 struct target_seminfo *target_seminfo;
2446 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2447 return -TARGET_EFAULT;
2448 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2449 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2450 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2451 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2452 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2453 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2454 __put_user(host_seminfo->semume, &target_seminfo->semume);
2455 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2456 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2457 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2458 unlock_user_struct(target_seminfo, target_addr, 1);
2459 return 0;
2460}
2461
thsfa294812007-02-02 22:05:00 +00002462union semun {
2463 int val;
ths3eb6b042007-06-03 14:26:27 +00002464 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002465 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002466 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002467};
2468
ths3eb6b042007-06-03 14:26:27 +00002469union target_semun {
2470 int val;
aurel32e5289082009-04-18 16:16:12 +00002471 abi_ulong buf;
2472 abi_ulong array;
2473 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002474};
2475
aurel32e5289082009-04-18 16:16:12 +00002476static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2477 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002478{
aurel32e5289082009-04-18 16:16:12 +00002479 int nsems;
2480 unsigned short *array;
2481 union semun semun;
2482 struct semid_ds semid_ds;
2483 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002484
aurel32e5289082009-04-18 16:16:12 +00002485 semun.buf = &semid_ds;
2486
2487 ret = semctl(semid, 0, IPC_STAT, semun);
2488 if (ret == -1)
2489 return get_errno(ret);
2490
2491 nsems = semid_ds.sem_nsems;
2492
2493 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002494 if (!*host_array) {
2495 return -TARGET_ENOMEM;
2496 }
aurel32e5289082009-04-18 16:16:12 +00002497 array = lock_user(VERIFY_READ, target_addr,
2498 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002499 if (!array) {
2500 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002501 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002502 }
aurel32e5289082009-04-18 16:16:12 +00002503
2504 for(i=0; i<nsems; i++) {
2505 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002506 }
aurel32e5289082009-04-18 16:16:12 +00002507 unlock_user(array, target_addr, 0);
2508
bellard579a97f2007-11-11 14:26:47 +00002509 return 0;
ths3eb6b042007-06-03 14:26:27 +00002510}
2511
aurel32e5289082009-04-18 16:16:12 +00002512static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2513 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002514{
aurel32e5289082009-04-18 16:16:12 +00002515 int nsems;
2516 unsigned short *array;
2517 union semun semun;
2518 struct semid_ds semid_ds;
2519 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002520
aurel32e5289082009-04-18 16:16:12 +00002521 semun.buf = &semid_ds;
2522
2523 ret = semctl(semid, 0, IPC_STAT, semun);
2524 if (ret == -1)
2525 return get_errno(ret);
2526
2527 nsems = semid_ds.sem_nsems;
2528
2529 array = lock_user(VERIFY_WRITE, target_addr,
2530 nsems*sizeof(unsigned short), 0);
2531 if (!array)
2532 return -TARGET_EFAULT;
2533
2534 for(i=0; i<nsems; i++) {
2535 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002536 }
aurel32e5289082009-04-18 16:16:12 +00002537 free(*host_array);
2538 unlock_user(array, target_addr, 1);
2539
bellard579a97f2007-11-11 14:26:47 +00002540 return 0;
ths3eb6b042007-06-03 14:26:27 +00002541}
2542
aurel32e5289082009-04-18 16:16:12 +00002543static inline abi_long do_semctl(int semid, int semnum, int cmd,
2544 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002545{
2546 union semun arg;
2547 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302548 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002549 struct seminfo seminfo;
2550 abi_long ret = -TARGET_EINVAL;
2551 abi_long err;
2552 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002553
2554 switch( cmd ) {
2555 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002556 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002557 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002558 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002559 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002560 break;
2561 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002562 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002563 err = target_to_host_semarray(semid, &array, target_su.array);
2564 if (err)
2565 return err;
2566 arg.array = array;
2567 ret = get_errno(semctl(semid, semnum, cmd, arg));
2568 err = host_to_target_semarray(semid, target_su.array, &array);
2569 if (err)
2570 return err;
ths3eb6b042007-06-03 14:26:27 +00002571 break;
2572 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002573 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002574 case SEM_STAT:
2575 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2576 if (err)
2577 return err;
2578 arg.buf = &dsarg;
2579 ret = get_errno(semctl(semid, semnum, cmd, arg));
2580 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2581 if (err)
2582 return err;
ths3eb6b042007-06-03 14:26:27 +00002583 break;
aurel32e5289082009-04-18 16:16:12 +00002584 case IPC_INFO:
2585 case SEM_INFO:
2586 arg.__buf = &seminfo;
2587 ret = get_errno(semctl(semid, semnum, cmd, arg));
2588 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2589 if (err)
2590 return err;
2591 break;
2592 case IPC_RMID:
2593 case GETPID:
2594 case GETNCNT:
2595 case GETZCNT:
2596 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2597 break;
ths3eb6b042007-06-03 14:26:27 +00002598 }
2599
2600 return ret;
2601}
2602
aurel32e5289082009-04-18 16:16:12 +00002603struct target_sembuf {
2604 unsigned short sem_num;
2605 short sem_op;
2606 short sem_flg;
2607};
2608
2609static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2610 abi_ulong target_addr,
2611 unsigned nsops)
2612{
2613 struct target_sembuf *target_sembuf;
2614 int i;
2615
2616 target_sembuf = lock_user(VERIFY_READ, target_addr,
2617 nsops*sizeof(struct target_sembuf), 1);
2618 if (!target_sembuf)
2619 return -TARGET_EFAULT;
2620
2621 for(i=0; i<nsops; i++) {
2622 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2623 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2624 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2625 }
2626
2627 unlock_user(target_sembuf, target_addr, 0);
2628
2629 return 0;
2630}
2631
2632static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2633{
2634 struct sembuf sops[nsops];
2635
2636 if (target_to_host_sembuf(sops, ptr, nsops))
2637 return -TARGET_EFAULT;
2638
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002639 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002640}
2641
ths1bc012f2007-06-03 14:27:49 +00002642struct target_msqid_ds
2643{
aurel321c54ff92008-10-13 21:08:44 +00002644 struct target_ipc_perm msg_perm;
2645 abi_ulong msg_stime;
2646#if TARGET_ABI_BITS == 32
2647 abi_ulong __unused1;
2648#endif
2649 abi_ulong msg_rtime;
2650#if TARGET_ABI_BITS == 32
2651 abi_ulong __unused2;
2652#endif
2653 abi_ulong msg_ctime;
2654#if TARGET_ABI_BITS == 32
2655 abi_ulong __unused3;
2656#endif
2657 abi_ulong __msg_cbytes;
2658 abi_ulong msg_qnum;
2659 abi_ulong msg_qbytes;
2660 abi_ulong msg_lspid;
2661 abi_ulong msg_lrpid;
2662 abi_ulong __unused4;
2663 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002664};
2665
bellard579a97f2007-11-11 14:26:47 +00002666static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2667 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002668{
2669 struct target_msqid_ds *target_md;
2670
bellard579a97f2007-11-11 14:26:47 +00002671 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2672 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002673 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2674 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002675 host_md->msg_stime = tswapal(target_md->msg_stime);
2676 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2677 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2678 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2679 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2680 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2681 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2682 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002683 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002684 return 0;
ths1bc012f2007-06-03 14:27:49 +00002685}
2686
bellard579a97f2007-11-11 14:26:47 +00002687static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2688 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002689{
2690 struct target_msqid_ds *target_md;
2691
bellard579a97f2007-11-11 14:26:47 +00002692 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2693 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002694 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2695 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002696 target_md->msg_stime = tswapal(host_md->msg_stime);
2697 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2698 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2699 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2700 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2701 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2702 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2703 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002704 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002705 return 0;
ths1bc012f2007-06-03 14:27:49 +00002706}
2707
aurel321c54ff92008-10-13 21:08:44 +00002708struct target_msginfo {
2709 int msgpool;
2710 int msgmap;
2711 int msgmax;
2712 int msgmnb;
2713 int msgmni;
2714 int msgssz;
2715 int msgtql;
2716 unsigned short int msgseg;
2717};
2718
2719static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2720 struct msginfo *host_msginfo)
2721{
2722 struct target_msginfo *target_msginfo;
2723 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2724 return -TARGET_EFAULT;
2725 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2726 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2727 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2728 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2729 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2730 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2731 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2732 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2733 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002734 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002735}
2736
2737static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002738{
2739 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002740 struct msginfo msginfo;
2741 abi_long ret = -TARGET_EINVAL;
2742
2743 cmd &= 0xff;
2744
2745 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002746 case IPC_STAT:
2747 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002748 case MSG_STAT:
2749 if (target_to_host_msqid_ds(&dsarg,ptr))
2750 return -TARGET_EFAULT;
2751 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2752 if (host_to_target_msqid_ds(ptr,&dsarg))
2753 return -TARGET_EFAULT;
2754 break;
2755 case IPC_RMID:
2756 ret = get_errno(msgctl(msgid, cmd, NULL));
2757 break;
2758 case IPC_INFO:
2759 case MSG_INFO:
2760 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2761 if (host_to_target_msginfo(ptr, &msginfo))
2762 return -TARGET_EFAULT;
2763 break;
ths1bc012f2007-06-03 14:27:49 +00002764 }
aurel321c54ff92008-10-13 21:08:44 +00002765
ths1bc012f2007-06-03 14:27:49 +00002766 return ret;
2767}
2768
2769struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002770 abi_long mtype;
2771 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002772};
2773
blueswir1992f48a2007-10-14 16:27:31 +00002774static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2775 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002776{
2777 struct target_msgbuf *target_mb;
2778 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002779 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002780
bellard579a97f2007-11-11 14:26:47 +00002781 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2782 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002783 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002784 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002785 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002786 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2787 free(host_mb);
2788 unlock_user_struct(target_mb, msgp, 0);
2789
2790 return ret;
2791}
2792
blueswir1992f48a2007-10-14 16:27:31 +00002793static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002794 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002795 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002796{
2797 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002798 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002799 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002800 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002801
bellard579a97f2007-11-11 14:26:47 +00002802 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2803 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002804
Jim Meyering0d07fe42012-08-22 13:55:53 +02002805 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002806 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002807
bellard579a97f2007-11-11 14:26:47 +00002808 if (ret > 0) {
2809 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2810 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2811 if (!target_mtext) {
2812 ret = -TARGET_EFAULT;
2813 goto end;
2814 }
aurel321c54ff92008-10-13 21:08:44 +00002815 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002816 unlock_user(target_mtext, target_mtext_addr, ret);
2817 }
aurel321c54ff92008-10-13 21:08:44 +00002818
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002819 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002820
bellard579a97f2007-11-11 14:26:47 +00002821end:
2822 if (target_mb)
2823 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002824 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002825 return ret;
2826}
2827
Riku Voipio88a8c982009-04-03 10:42:00 +03002828static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2829 abi_ulong target_addr)
2830{
2831 struct target_shmid_ds *target_sd;
2832
2833 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2834 return -TARGET_EFAULT;
2835 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2836 return -TARGET_EFAULT;
2837 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2838 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2839 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2840 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2841 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2842 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2843 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2844 unlock_user_struct(target_sd, target_addr, 0);
2845 return 0;
2846}
2847
2848static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2849 struct shmid_ds *host_sd)
2850{
2851 struct target_shmid_ds *target_sd;
2852
2853 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2854 return -TARGET_EFAULT;
2855 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2856 return -TARGET_EFAULT;
2857 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2858 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2859 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2860 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2861 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2862 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2863 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2864 unlock_user_struct(target_sd, target_addr, 1);
2865 return 0;
2866}
2867
2868struct target_shminfo {
2869 abi_ulong shmmax;
2870 abi_ulong shmmin;
2871 abi_ulong shmmni;
2872 abi_ulong shmseg;
2873 abi_ulong shmall;
2874};
2875
2876static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2877 struct shminfo *host_shminfo)
2878{
2879 struct target_shminfo *target_shminfo;
2880 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2881 return -TARGET_EFAULT;
2882 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2883 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2884 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2885 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2886 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2887 unlock_user_struct(target_shminfo, target_addr, 1);
2888 return 0;
2889}
2890
2891struct target_shm_info {
2892 int used_ids;
2893 abi_ulong shm_tot;
2894 abi_ulong shm_rss;
2895 abi_ulong shm_swp;
2896 abi_ulong swap_attempts;
2897 abi_ulong swap_successes;
2898};
2899
2900static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2901 struct shm_info *host_shm_info)
2902{
2903 struct target_shm_info *target_shm_info;
2904 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2905 return -TARGET_EFAULT;
2906 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2907 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2908 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2909 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2910 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2911 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2912 unlock_user_struct(target_shm_info, target_addr, 1);
2913 return 0;
2914}
2915
2916static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2917{
2918 struct shmid_ds dsarg;
2919 struct shminfo shminfo;
2920 struct shm_info shm_info;
2921 abi_long ret = -TARGET_EINVAL;
2922
2923 cmd &= 0xff;
2924
2925 switch(cmd) {
2926 case IPC_STAT:
2927 case IPC_SET:
2928 case SHM_STAT:
2929 if (target_to_host_shmid_ds(&dsarg, buf))
2930 return -TARGET_EFAULT;
2931 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2932 if (host_to_target_shmid_ds(buf, &dsarg))
2933 return -TARGET_EFAULT;
2934 break;
2935 case IPC_INFO:
2936 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2937 if (host_to_target_shminfo(buf, &shminfo))
2938 return -TARGET_EFAULT;
2939 break;
2940 case SHM_INFO:
2941 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2942 if (host_to_target_shm_info(buf, &shm_info))
2943 return -TARGET_EFAULT;
2944 break;
2945 case IPC_RMID:
2946 case SHM_LOCK:
2947 case SHM_UNLOCK:
2948 ret = get_errno(shmctl(shmid, cmd, NULL));
2949 break;
2950 }
2951
2952 return ret;
2953}
2954
2955static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2956{
2957 abi_long raddr;
2958 void *host_raddr;
2959 struct shmid_ds shm_info;
2960 int i,ret;
2961
2962 /* find out the length of the shared memory segment */
2963 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
2964 if (is_error(ret)) {
2965 /* can't get length, bail out */
2966 return ret;
2967 }
2968
2969 mmap_lock();
2970
2971 if (shmaddr)
2972 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
2973 else {
2974 abi_ulong mmap_start;
2975
2976 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
2977
2978 if (mmap_start == -1) {
2979 errno = ENOMEM;
2980 host_raddr = (void *)-1;
2981 } else
2982 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
2983 }
2984
2985 if (host_raddr == (void *)-1) {
2986 mmap_unlock();
2987 return get_errno((long)host_raddr);
2988 }
2989 raddr=h2g((unsigned long)host_raddr);
2990
2991 page_set_flags(raddr, raddr + shm_info.shm_segsz,
2992 PAGE_VALID | PAGE_READ |
2993 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
2994
2995 for (i = 0; i < N_SHM_REGIONS; i++) {
2996 if (shm_regions[i].start == 0) {
2997 shm_regions[i].start = raddr;
2998 shm_regions[i].size = shm_info.shm_segsz;
2999 break;
3000 }
3001 }
3002
3003 mmap_unlock();
3004 return raddr;
3005
3006}
3007
3008static inline abi_long do_shmdt(abi_ulong shmaddr)
3009{
3010 int i;
3011
3012 for (i = 0; i < N_SHM_REGIONS; ++i) {
3013 if (shm_regions[i].start == shmaddr) {
3014 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003015 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003016 break;
3017 }
3018 }
3019
3020 return get_errno(shmdt(g2h(shmaddr)));
3021}
3022
aurel321c54ff92008-10-13 21:08:44 +00003023#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003024/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003025/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003026static abi_long do_ipc(unsigned int call, int first,
3027 int second, int third,
3028 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003029{
3030 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003031 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003032
3033 version = call >> 16;
3034 call &= 0xffff;
3035
3036 switch (call) {
thsfa294812007-02-02 22:05:00 +00003037 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003038 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003039 break;
3040
3041 case IPCOP_semget:
3042 ret = get_errno(semget(first, second, third));
3043 break;
3044
3045 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003046 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003047 break;
thsd96372e2007-02-02 22:05:44 +00003048
aurel321c54ff92008-10-13 21:08:44 +00003049 case IPCOP_msgget:
3050 ret = get_errno(msgget(first, second));
3051 break;
thsd96372e2007-02-02 22:05:44 +00003052
aurel321c54ff92008-10-13 21:08:44 +00003053 case IPCOP_msgsnd:
3054 ret = do_msgsnd(first, ptr, second, third);
3055 break;
thsd96372e2007-02-02 22:05:44 +00003056
aurel321c54ff92008-10-13 21:08:44 +00003057 case IPCOP_msgctl:
3058 ret = do_msgctl(first, second, ptr);
3059 break;
thsd96372e2007-02-02 22:05:44 +00003060
aurel321c54ff92008-10-13 21:08:44 +00003061 case IPCOP_msgrcv:
3062 switch (version) {
3063 case 0:
3064 {
3065 struct target_ipc_kludge {
3066 abi_long msgp;
3067 abi_long msgtyp;
3068 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003069
aurel321c54ff92008-10-13 21:08:44 +00003070 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3071 ret = -TARGET_EFAULT;
3072 break;
ths1bc012f2007-06-03 14:27:49 +00003073 }
aurel321c54ff92008-10-13 21:08:44 +00003074
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003075 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003076
3077 unlock_user_struct(tmp, ptr, 0);
3078 break;
3079 }
3080 default:
3081 ret = do_msgrcv(first, ptr, second, fifth, third);
3082 }
3083 break;
thsd96372e2007-02-02 22:05:44 +00003084
bellard8853f862004-02-22 14:57:26 +00003085 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003086 switch (version) {
3087 default:
bellard5a4a8982007-11-11 17:39:18 +00003088 {
3089 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003090 raddr = do_shmat(first, ptr, second);
3091 if (is_error(raddr))
3092 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003093 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003094 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003095 break;
3096 }
3097 case 1:
3098 ret = -TARGET_EINVAL;
3099 break;
bellard5a4a8982007-11-11 17:39:18 +00003100 }
bellard8853f862004-02-22 14:57:26 +00003101 break;
3102 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003103 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003104 break;
3105
3106 case IPCOP_shmget:
3107 /* IPC_* flag values are the same on all linux platforms */
3108 ret = get_errno(shmget(first, second, third));
3109 break;
3110
3111 /* IPC_* and SHM_* command values are the same on all linux platforms */
3112 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003113 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003114 break;
3115 default:
j_mayer32407102007-09-26 23:01:49 +00003116 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003117 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003118 break;
3119 }
3120 return ret;
3121}
j_mayer32407102007-09-26 23:01:49 +00003122#endif
bellard8853f862004-02-22 14:57:26 +00003123
bellard31e31b82003-02-18 22:55:36 +00003124/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003125
Blue Swirl001faf32009-05-13 17:53:17 +00003126#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003127#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3128enum {
3129#include "syscall_types.h"
3130};
3131#undef STRUCT
3132#undef STRUCT_SPECIAL
3133
Blue Swirl001faf32009-05-13 17:53:17 +00003134#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003135#define STRUCT_SPECIAL(name)
3136#include "syscall_types.h"
3137#undef STRUCT
3138#undef STRUCT_SPECIAL
3139
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003140typedef struct IOCTLEntry IOCTLEntry;
3141
3142typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3143 int fd, abi_long cmd, abi_long arg);
3144
3145struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003146 unsigned int target_cmd;
3147 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003148 const char *name;
3149 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003150 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003151 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003152};
bellard31e31b82003-02-18 22:55:36 +00003153
3154#define IOC_R 0x0001
3155#define IOC_W 0x0002
3156#define IOC_RW (IOC_R | IOC_W)
3157
3158#define MAX_STRUCT_SIZE 4096
3159
Peter Maydelldace20d2011-01-10 13:11:24 +00003160#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003161/* So fiemap access checks don't overflow on 32 bit systems.
3162 * This is very slightly smaller than the limit imposed by
3163 * the underlying kernel.
3164 */
3165#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3166 / sizeof(struct fiemap_extent))
3167
3168static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3169 int fd, abi_long cmd, abi_long arg)
3170{
3171 /* The parameter for this ioctl is a struct fiemap followed
3172 * by an array of struct fiemap_extent whose size is set
3173 * in fiemap->fm_extent_count. The array is filled in by the
3174 * ioctl.
3175 */
3176 int target_size_in, target_size_out;
3177 struct fiemap *fm;
3178 const argtype *arg_type = ie->arg_type;
3179 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3180 void *argptr, *p;
3181 abi_long ret;
3182 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3183 uint32_t outbufsz;
3184 int free_fm = 0;
3185
3186 assert(arg_type[0] == TYPE_PTR);
3187 assert(ie->access == IOC_RW);
3188 arg_type++;
3189 target_size_in = thunk_type_size(arg_type, 0);
3190 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3191 if (!argptr) {
3192 return -TARGET_EFAULT;
3193 }
3194 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3195 unlock_user(argptr, arg, 0);
3196 fm = (struct fiemap *)buf_temp;
3197 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3198 return -TARGET_EINVAL;
3199 }
3200
3201 outbufsz = sizeof (*fm) +
3202 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3203
3204 if (outbufsz > MAX_STRUCT_SIZE) {
3205 /* We can't fit all the extents into the fixed size buffer.
3206 * Allocate one that is large enough and use it instead.
3207 */
3208 fm = malloc(outbufsz);
3209 if (!fm) {
3210 return -TARGET_ENOMEM;
3211 }
3212 memcpy(fm, buf_temp, sizeof(struct fiemap));
3213 free_fm = 1;
3214 }
3215 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3216 if (!is_error(ret)) {
3217 target_size_out = target_size_in;
3218 /* An extent_count of 0 means we were only counting the extents
3219 * so there are no structs to copy
3220 */
3221 if (fm->fm_extent_count != 0) {
3222 target_size_out += fm->fm_mapped_extents * extent_size;
3223 }
3224 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3225 if (!argptr) {
3226 ret = -TARGET_EFAULT;
3227 } else {
3228 /* Convert the struct fiemap */
3229 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3230 if (fm->fm_extent_count != 0) {
3231 p = argptr + target_size_in;
3232 /* ...and then all the struct fiemap_extents */
3233 for (i = 0; i < fm->fm_mapped_extents; i++) {
3234 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3235 THUNK_TARGET);
3236 p += extent_size;
3237 }
3238 }
3239 unlock_user(argptr, arg, target_size_out);
3240 }
3241 }
3242 if (free_fm) {
3243 free(fm);
3244 }
3245 return ret;
3246}
Peter Maydelldace20d2011-01-10 13:11:24 +00003247#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003248
Laurent Vivier059c2f22011-03-30 00:12:12 +02003249static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3250 int fd, abi_long cmd, abi_long arg)
3251{
3252 const argtype *arg_type = ie->arg_type;
3253 int target_size;
3254 void *argptr;
3255 int ret;
3256 struct ifconf *host_ifconf;
3257 uint32_t outbufsz;
3258 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3259 int target_ifreq_size;
3260 int nb_ifreq;
3261 int free_buf = 0;
3262 int i;
3263 int target_ifc_len;
3264 abi_long target_ifc_buf;
3265 int host_ifc_len;
3266 char *host_ifc_buf;
3267
3268 assert(arg_type[0] == TYPE_PTR);
3269 assert(ie->access == IOC_RW);
3270
3271 arg_type++;
3272 target_size = thunk_type_size(arg_type, 0);
3273
3274 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3275 if (!argptr)
3276 return -TARGET_EFAULT;
3277 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3278 unlock_user(argptr, arg, 0);
3279
3280 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3281 target_ifc_len = host_ifconf->ifc_len;
3282 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3283
3284 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3285 nb_ifreq = target_ifc_len / target_ifreq_size;
3286 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3287
3288 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3289 if (outbufsz > MAX_STRUCT_SIZE) {
3290 /* We can't fit all the extents into the fixed size buffer.
3291 * Allocate one that is large enough and use it instead.
3292 */
3293 host_ifconf = malloc(outbufsz);
3294 if (!host_ifconf) {
3295 return -TARGET_ENOMEM;
3296 }
3297 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3298 free_buf = 1;
3299 }
3300 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3301
3302 host_ifconf->ifc_len = host_ifc_len;
3303 host_ifconf->ifc_buf = host_ifc_buf;
3304
3305 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3306 if (!is_error(ret)) {
3307 /* convert host ifc_len to target ifc_len */
3308
3309 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3310 target_ifc_len = nb_ifreq * target_ifreq_size;
3311 host_ifconf->ifc_len = target_ifc_len;
3312
3313 /* restore target ifc_buf */
3314
3315 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3316
3317 /* copy struct ifconf to target user */
3318
3319 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3320 if (!argptr)
3321 return -TARGET_EFAULT;
3322 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3323 unlock_user(argptr, arg, target_size);
3324
3325 /* copy ifreq[] to target user */
3326
3327 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3328 for (i = 0; i < nb_ifreq ; i++) {
3329 thunk_convert(argptr + i * target_ifreq_size,
3330 host_ifc_buf + i * sizeof(struct ifreq),
3331 ifreq_arg_type, THUNK_TARGET);
3332 }
3333 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3334 }
3335
3336 if (free_buf) {
3337 free(host_ifconf);
3338 }
3339
3340 return ret;
3341}
3342
Alexander Graf56e904e2012-01-31 18:42:06 +01003343static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3344 abi_long cmd, abi_long arg)
3345{
3346 void *argptr;
3347 struct dm_ioctl *host_dm;
3348 abi_long guest_data;
3349 uint32_t guest_data_size;
3350 int target_size;
3351 const argtype *arg_type = ie->arg_type;
3352 abi_long ret;
3353 void *big_buf = NULL;
3354 char *host_data;
3355
3356 arg_type++;
3357 target_size = thunk_type_size(arg_type, 0);
3358 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3359 if (!argptr) {
3360 ret = -TARGET_EFAULT;
3361 goto out;
3362 }
3363 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3364 unlock_user(argptr, arg, 0);
3365
3366 /* buf_temp is too small, so fetch things into a bigger buffer */
3367 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3368 memcpy(big_buf, buf_temp, target_size);
3369 buf_temp = big_buf;
3370 host_dm = big_buf;
3371
3372 guest_data = arg + host_dm->data_start;
3373 if ((guest_data - arg) < 0) {
3374 ret = -EINVAL;
3375 goto out;
3376 }
3377 guest_data_size = host_dm->data_size - host_dm->data_start;
3378 host_data = (char*)host_dm + host_dm->data_start;
3379
3380 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3381 switch (ie->host_cmd) {
3382 case DM_REMOVE_ALL:
3383 case DM_LIST_DEVICES:
3384 case DM_DEV_CREATE:
3385 case DM_DEV_REMOVE:
3386 case DM_DEV_SUSPEND:
3387 case DM_DEV_STATUS:
3388 case DM_DEV_WAIT:
3389 case DM_TABLE_STATUS:
3390 case DM_TABLE_CLEAR:
3391 case DM_TABLE_DEPS:
3392 case DM_LIST_VERSIONS:
3393 /* no input data */
3394 break;
3395 case DM_DEV_RENAME:
3396 case DM_DEV_SET_GEOMETRY:
3397 /* data contains only strings */
3398 memcpy(host_data, argptr, guest_data_size);
3399 break;
3400 case DM_TARGET_MSG:
3401 memcpy(host_data, argptr, guest_data_size);
3402 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3403 break;
3404 case DM_TABLE_LOAD:
3405 {
3406 void *gspec = argptr;
3407 void *cur_data = host_data;
3408 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3409 int spec_size = thunk_type_size(arg_type, 0);
3410 int i;
3411
3412 for (i = 0; i < host_dm->target_count; i++) {
3413 struct dm_target_spec *spec = cur_data;
3414 uint32_t next;
3415 int slen;
3416
3417 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3418 slen = strlen((char*)gspec + spec_size) + 1;
3419 next = spec->next;
3420 spec->next = sizeof(*spec) + slen;
3421 strcpy((char*)&spec[1], gspec + spec_size);
3422 gspec += next;
3423 cur_data += spec->next;
3424 }
3425 break;
3426 }
3427 default:
3428 ret = -TARGET_EINVAL;
3429 goto out;
3430 }
3431 unlock_user(argptr, guest_data, 0);
3432
3433 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3434 if (!is_error(ret)) {
3435 guest_data = arg + host_dm->data_start;
3436 guest_data_size = host_dm->data_size - host_dm->data_start;
3437 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3438 switch (ie->host_cmd) {
3439 case DM_REMOVE_ALL:
3440 case DM_DEV_CREATE:
3441 case DM_DEV_REMOVE:
3442 case DM_DEV_RENAME:
3443 case DM_DEV_SUSPEND:
3444 case DM_DEV_STATUS:
3445 case DM_TABLE_LOAD:
3446 case DM_TABLE_CLEAR:
3447 case DM_TARGET_MSG:
3448 case DM_DEV_SET_GEOMETRY:
3449 /* no return data */
3450 break;
3451 case DM_LIST_DEVICES:
3452 {
3453 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3454 uint32_t remaining_data = guest_data_size;
3455 void *cur_data = argptr;
3456 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3457 int nl_size = 12; /* can't use thunk_size due to alignment */
3458
3459 while (1) {
3460 uint32_t next = nl->next;
3461 if (next) {
3462 nl->next = nl_size + (strlen(nl->name) + 1);
3463 }
3464 if (remaining_data < nl->next) {
3465 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3466 break;
3467 }
3468 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3469 strcpy(cur_data + nl_size, nl->name);
3470 cur_data += nl->next;
3471 remaining_data -= nl->next;
3472 if (!next) {
3473 break;
3474 }
3475 nl = (void*)nl + next;
3476 }
3477 break;
3478 }
3479 case DM_DEV_WAIT:
3480 case DM_TABLE_STATUS:
3481 {
3482 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3483 void *cur_data = argptr;
3484 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3485 int spec_size = thunk_type_size(arg_type, 0);
3486 int i;
3487
3488 for (i = 0; i < host_dm->target_count; i++) {
3489 uint32_t next = spec->next;
3490 int slen = strlen((char*)&spec[1]) + 1;
3491 spec->next = (cur_data - argptr) + spec_size + slen;
3492 if (guest_data_size < spec->next) {
3493 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3494 break;
3495 }
3496 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3497 strcpy(cur_data + spec_size, (char*)&spec[1]);
3498 cur_data = argptr + spec->next;
3499 spec = (void*)host_dm + host_dm->data_start + next;
3500 }
3501 break;
3502 }
3503 case DM_TABLE_DEPS:
3504 {
3505 void *hdata = (void*)host_dm + host_dm->data_start;
3506 int count = *(uint32_t*)hdata;
3507 uint64_t *hdev = hdata + 8;
3508 uint64_t *gdev = argptr + 8;
3509 int i;
3510
3511 *(uint32_t*)argptr = tswap32(count);
3512 for (i = 0; i < count; i++) {
3513 *gdev = tswap64(*hdev);
3514 gdev++;
3515 hdev++;
3516 }
3517 break;
3518 }
3519 case DM_LIST_VERSIONS:
3520 {
3521 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3522 uint32_t remaining_data = guest_data_size;
3523 void *cur_data = argptr;
3524 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3525 int vers_size = thunk_type_size(arg_type, 0);
3526
3527 while (1) {
3528 uint32_t next = vers->next;
3529 if (next) {
3530 vers->next = vers_size + (strlen(vers->name) + 1);
3531 }
3532 if (remaining_data < vers->next) {
3533 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3534 break;
3535 }
3536 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3537 strcpy(cur_data + vers_size, vers->name);
3538 cur_data += vers->next;
3539 remaining_data -= vers->next;
3540 if (!next) {
3541 break;
3542 }
3543 vers = (void*)vers + next;
3544 }
3545 break;
3546 }
3547 default:
3548 ret = -TARGET_EINVAL;
3549 goto out;
3550 }
3551 unlock_user(argptr, guest_data, guest_data_size);
3552
3553 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3554 if (!argptr) {
3555 ret = -TARGET_EFAULT;
3556 goto out;
3557 }
3558 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3559 unlock_user(argptr, arg, target_size);
3560 }
3561out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003562 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003563 return ret;
3564}
3565
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003566static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3567 int fd, abi_long cmd, abi_long arg)
3568{
3569 const argtype *arg_type = ie->arg_type;
3570 const StructEntry *se;
3571 const argtype *field_types;
3572 const int *dst_offsets, *src_offsets;
3573 int target_size;
3574 void *argptr;
3575 abi_ulong *target_rt_dev_ptr;
3576 unsigned long *host_rt_dev_ptr;
3577 abi_long ret;
3578 int i;
3579
3580 assert(ie->access == IOC_W);
3581 assert(*arg_type == TYPE_PTR);
3582 arg_type++;
3583 assert(*arg_type == TYPE_STRUCT);
3584 target_size = thunk_type_size(arg_type, 0);
3585 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3586 if (!argptr) {
3587 return -TARGET_EFAULT;
3588 }
3589 arg_type++;
3590 assert(*arg_type == (int)STRUCT_rtentry);
3591 se = struct_entries + *arg_type++;
3592 assert(se->convert[0] == NULL);
3593 /* convert struct here to be able to catch rt_dev string */
3594 field_types = se->field_types;
3595 dst_offsets = se->field_offsets[THUNK_HOST];
3596 src_offsets = se->field_offsets[THUNK_TARGET];
3597 for (i = 0; i < se->nb_fields; i++) {
3598 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3599 assert(*field_types == TYPE_PTRVOID);
3600 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3601 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3602 if (*target_rt_dev_ptr != 0) {
3603 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3604 tswapal(*target_rt_dev_ptr));
3605 if (!*host_rt_dev_ptr) {
3606 unlock_user(argptr, arg, 0);
3607 return -TARGET_EFAULT;
3608 }
3609 } else {
3610 *host_rt_dev_ptr = 0;
3611 }
3612 field_types++;
3613 continue;
3614 }
3615 field_types = thunk_convert(buf_temp + dst_offsets[i],
3616 argptr + src_offsets[i],
3617 field_types, THUNK_HOST);
3618 }
3619 unlock_user(argptr, arg, 0);
3620
3621 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3622 if (*host_rt_dev_ptr != 0) {
3623 unlock_user((void *)*host_rt_dev_ptr,
3624 *target_rt_dev_ptr, 0);
3625 }
3626 return ret;
3627}
3628
blueswir19f106a72008-10-05 10:52:52 +00003629static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003630#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003631 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3632#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3633 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003634#include "ioctls.h"
3635 { 0, 0, },
3636};
3637
pbrook53a59602006-03-25 19:31:22 +00003638/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003639/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003640static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003641{
3642 const IOCTLEntry *ie;
3643 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003644 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003645 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003646 int target_size;
3647 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003648
3649 ie = ioctl_entries;
3650 for(;;) {
3651 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003652 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003653 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003654 }
3655 if (ie->target_cmd == cmd)
3656 break;
3657 ie++;
3658 }
3659 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003660#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003661 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003662#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003663 if (ie->do_ioctl) {
3664 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3665 }
3666
bellard31e31b82003-02-18 22:55:36 +00003667 switch(arg_type[0]) {
3668 case TYPE_NULL:
3669 /* no argument */
3670 ret = get_errno(ioctl(fd, ie->host_cmd));
3671 break;
3672 case TYPE_PTRVOID:
3673 case TYPE_INT:
3674 /* int argment */
3675 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3676 break;
3677 case TYPE_PTR:
3678 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003679 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003680 switch(ie->access) {
3681 case IOC_R:
3682 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3683 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003684 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3685 if (!argptr)
3686 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003687 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3688 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003689 }
3690 break;
3691 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003692 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3693 if (!argptr)
3694 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003695 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3696 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003697 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3698 break;
3699 default:
3700 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003701 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3702 if (!argptr)
3703 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003704 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3705 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003706 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3707 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003708 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3709 if (!argptr)
3710 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003711 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3712 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003713 }
3714 break;
3715 }
3716 break;
3717 default:
j_mayer32407102007-09-26 23:01:49 +00003718 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3719 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003720 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003721 break;
3722 }
3723 return ret;
3724}
3725
blueswir1b39bc502008-10-05 10:51:10 +00003726static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003727 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3728 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3729 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3730 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3731 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3732 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3733 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3734 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3735 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3736 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3737 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3738 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3739 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3740 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3741 { 0, 0, 0, 0 }
3742};
3743
blueswir1b39bc502008-10-05 10:51:10 +00003744static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003745 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3746 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3747 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3748 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3749 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3750 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3751 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3752 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3753 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3754 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3755 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3756 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3757 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3758 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3759 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3760 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3761 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3762 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3763 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3764 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3765 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3766 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3767 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3768 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3769 { 0, 0, 0, 0 }
3770};
3771
blueswir1b39bc502008-10-05 10:51:10 +00003772static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003773 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3774 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3775 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3776 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3777 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3778 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3779 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3780 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3781 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3782 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3783 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3784 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3785 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3786 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3787 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3788 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3789 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3790 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3791 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3792 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3793 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3794 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3795 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3796 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3797 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3798 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3799 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3800 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3801 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3802 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3803 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3804 { 0, 0, 0, 0 }
3805};
3806
blueswir1b39bc502008-10-05 10:51:10 +00003807static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003808 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3809 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3810 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3811 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3812 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3813 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3814 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3815 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3816 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3817 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3818 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3819 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3820 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3821 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3822 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3823 { 0, 0, 0, 0 }
3824};
3825
3826static void target_to_host_termios (void *dst, const void *src)
3827{
3828 struct host_termios *host = dst;
3829 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003830
ths5fafdf22007-09-16 21:08:06 +00003831 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003832 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003833 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003834 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003835 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003836 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003837 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003838 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3839 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003840
Arnaud Patard44607122009-04-21 17:39:08 +03003841 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003842 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3843 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003844 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003845 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003846 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003847 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003848 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003849 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003850 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003851 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3852 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003853 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3854 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3855 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3856 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3857 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003858 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003859}
ths3b46e622007-09-17 08:09:54 +00003860
bellard31e31b82003-02-18 22:55:36 +00003861static void host_to_target_termios (void *dst, const void *src)
3862{
3863 struct target_termios *target = dst;
3864 const struct host_termios *host = src;
3865
ths5fafdf22007-09-16 21:08:06 +00003866 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003867 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003868 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003869 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003870 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003871 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003872 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003873 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3874 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003875
Arnaud Patard44607122009-04-21 17:39:08 +03003876 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003877 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3878 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3879 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3880 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3881 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3882 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3883 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3884 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3885 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3886 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3887 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3888 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3889 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3890 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3891 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3892 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3893 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3894}
3895
blueswir18e853dc2008-10-05 10:49:32 +00003896static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003897 .convert = { host_to_target_termios, target_to_host_termios },
3898 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3899 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3900};
3901
bellard5286db72003-06-05 00:57:30 +00003902static bitmask_transtbl mmap_flags_tbl[] = {
3903 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3904 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3905 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3906 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3907 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3908 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3909 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3910 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01003911 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
3912 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00003913 { 0, 0, 0, 0 }
3914};
3915
bellard2ab83ea2003-06-15 19:56:46 +00003916#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003917
3918/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003919static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003920
bellard03acab62007-11-11 14:57:14 +00003921static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003922{
3923 int size;
pbrook53a59602006-03-25 19:31:22 +00003924 void *p;
bellard6dbad632003-03-16 18:05:05 +00003925
3926 if (!ldt_table)
3927 return 0;
3928 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3929 if (size > bytecount)
3930 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003931 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3932 if (!p)
bellard03acab62007-11-11 14:57:14 +00003933 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003934 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003935 memcpy(p, ldt_table, size);
3936 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003937 return size;
3938}
3939
3940/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003941static abi_long write_ldt(CPUX86State *env,
3942 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003943{
3944 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003945 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003946 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003947 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003948 uint32_t *lp, entry_1, entry_2;
3949
3950 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003951 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003952 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003953 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003954 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003955 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003956 ldt_info.limit = tswap32(target_ldt_info->limit);
3957 ldt_info.flags = tswap32(target_ldt_info->flags);
3958 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003959
bellard6dbad632003-03-16 18:05:05 +00003960 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003961 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003962 seg_32bit = ldt_info.flags & 1;
3963 contents = (ldt_info.flags >> 1) & 3;
3964 read_exec_only = (ldt_info.flags >> 3) & 1;
3965 limit_in_pages = (ldt_info.flags >> 4) & 1;
3966 seg_not_present = (ldt_info.flags >> 5) & 1;
3967 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003968#ifdef TARGET_ABI32
3969 lm = 0;
3970#else
3971 lm = (ldt_info.flags >> 7) & 1;
3972#endif
bellard6dbad632003-03-16 18:05:05 +00003973 if (contents == 3) {
3974 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003975 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003976 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003977 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003978 }
3979 /* allocate the LDT */
3980 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003981 env->ldt.base = target_mmap(0,
3982 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3983 PROT_READ|PROT_WRITE,
3984 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3985 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003986 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003987 memset(g2h(env->ldt.base), 0,
3988 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003989 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003990 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003991 }
3992
3993 /* NOTE: same code as Linux kernel */
3994 /* Allow LDTs to be cleared by the user. */
3995 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3996 if (oldmode ||
3997 (contents == 0 &&
3998 read_exec_only == 1 &&
3999 seg_32bit == 0 &&
4000 limit_in_pages == 0 &&
4001 seg_not_present == 1 &&
4002 useable == 0 )) {
4003 entry_1 = 0;
4004 entry_2 = 0;
4005 goto install;
4006 }
4007 }
ths3b46e622007-09-17 08:09:54 +00004008
bellard6dbad632003-03-16 18:05:05 +00004009 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4010 (ldt_info.limit & 0x0ffff);
4011 entry_2 = (ldt_info.base_addr & 0xff000000) |
4012 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4013 (ldt_info.limit & 0xf0000) |
4014 ((read_exec_only ^ 1) << 9) |
4015 (contents << 10) |
4016 ((seg_not_present ^ 1) << 15) |
4017 (seg_32bit << 22) |
4018 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004019 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004020 0x7000;
4021 if (!oldmode)
4022 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004023
bellard6dbad632003-03-16 18:05:05 +00004024 /* Install the new entry ... */
4025install:
4026 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4027 lp[0] = tswap32(entry_1);
4028 lp[1] = tswap32(entry_2);
4029 return 0;
4030}
4031
4032/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004033static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4034 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004035{
bellard03acab62007-11-11 14:57:14 +00004036 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004037
bellard6dbad632003-03-16 18:05:05 +00004038 switch (func) {
4039 case 0:
4040 ret = read_ldt(ptr, bytecount);
4041 break;
4042 case 1:
4043 ret = write_ldt(env, ptr, bytecount, 1);
4044 break;
4045 case 0x11:
4046 ret = write_ldt(env, ptr, bytecount, 0);
4047 break;
bellard03acab62007-11-11 14:57:14 +00004048 default:
4049 ret = -TARGET_ENOSYS;
4050 break;
bellard6dbad632003-03-16 18:05:05 +00004051 }
4052 return ret;
4053}
bellard1b6b0292003-03-22 17:31:38 +00004054
blueswir14583f582008-08-24 10:35:55 +00004055#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004056abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004057{
4058 uint64_t *gdt_table = g2h(env->gdt.base);
4059 struct target_modify_ldt_ldt_s ldt_info;
4060 struct target_modify_ldt_ldt_s *target_ldt_info;
4061 int seg_32bit, contents, read_exec_only, limit_in_pages;
4062 int seg_not_present, useable, lm;
4063 uint32_t *lp, entry_1, entry_2;
4064 int i;
4065
4066 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4067 if (!target_ldt_info)
4068 return -TARGET_EFAULT;
4069 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004070 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004071 ldt_info.limit = tswap32(target_ldt_info->limit);
4072 ldt_info.flags = tswap32(target_ldt_info->flags);
4073 if (ldt_info.entry_number == -1) {
4074 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4075 if (gdt_table[i] == 0) {
4076 ldt_info.entry_number = i;
4077 target_ldt_info->entry_number = tswap32(i);
4078 break;
4079 }
4080 }
4081 }
4082 unlock_user_struct(target_ldt_info, ptr, 1);
4083
4084 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4085 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4086 return -TARGET_EINVAL;
4087 seg_32bit = ldt_info.flags & 1;
4088 contents = (ldt_info.flags >> 1) & 3;
4089 read_exec_only = (ldt_info.flags >> 3) & 1;
4090 limit_in_pages = (ldt_info.flags >> 4) & 1;
4091 seg_not_present = (ldt_info.flags >> 5) & 1;
4092 useable = (ldt_info.flags >> 6) & 1;
4093#ifdef TARGET_ABI32
4094 lm = 0;
4095#else
4096 lm = (ldt_info.flags >> 7) & 1;
4097#endif
4098
4099 if (contents == 3) {
4100 if (seg_not_present == 0)
4101 return -TARGET_EINVAL;
4102 }
4103
4104 /* NOTE: same code as Linux kernel */
4105 /* Allow LDTs to be cleared by the user. */
4106 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4107 if ((contents == 0 &&
4108 read_exec_only == 1 &&
4109 seg_32bit == 0 &&
4110 limit_in_pages == 0 &&
4111 seg_not_present == 1 &&
4112 useable == 0 )) {
4113 entry_1 = 0;
4114 entry_2 = 0;
4115 goto install;
4116 }
4117 }
4118
4119 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4120 (ldt_info.limit & 0x0ffff);
4121 entry_2 = (ldt_info.base_addr & 0xff000000) |
4122 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4123 (ldt_info.limit & 0xf0000) |
4124 ((read_exec_only ^ 1) << 9) |
4125 (contents << 10) |
4126 ((seg_not_present ^ 1) << 15) |
4127 (seg_32bit << 22) |
4128 (limit_in_pages << 23) |
4129 (useable << 20) |
4130 (lm << 21) |
4131 0x7000;
4132
4133 /* Install the new entry ... */
4134install:
4135 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4136 lp[0] = tswap32(entry_1);
4137 lp[1] = tswap32(entry_2);
4138 return 0;
4139}
4140
blueswir18fcd3692008-08-17 20:26:25 +00004141static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004142{
4143 struct target_modify_ldt_ldt_s *target_ldt_info;
4144 uint64_t *gdt_table = g2h(env->gdt.base);
4145 uint32_t base_addr, limit, flags;
4146 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4147 int seg_not_present, useable, lm;
4148 uint32_t *lp, entry_1, entry_2;
4149
4150 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4151 if (!target_ldt_info)
4152 return -TARGET_EFAULT;
4153 idx = tswap32(target_ldt_info->entry_number);
4154 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4155 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4156 unlock_user_struct(target_ldt_info, ptr, 1);
4157 return -TARGET_EINVAL;
4158 }
4159 lp = (uint32_t *)(gdt_table + idx);
4160 entry_1 = tswap32(lp[0]);
4161 entry_2 = tswap32(lp[1]);
4162
4163 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4164 contents = (entry_2 >> 10) & 3;
4165 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4166 seg_32bit = (entry_2 >> 22) & 1;
4167 limit_in_pages = (entry_2 >> 23) & 1;
4168 useable = (entry_2 >> 20) & 1;
4169#ifdef TARGET_ABI32
4170 lm = 0;
4171#else
4172 lm = (entry_2 >> 21) & 1;
4173#endif
4174 flags = (seg_32bit << 0) | (contents << 1) |
4175 (read_exec_only << 3) | (limit_in_pages << 4) |
4176 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4177 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4178 base_addr = (entry_1 >> 16) |
4179 (entry_2 & 0xff000000) |
4180 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004181 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004182 target_ldt_info->limit = tswap32(limit);
4183 target_ldt_info->flags = tswap32(flags);
4184 unlock_user_struct(target_ldt_info, ptr, 1);
4185 return 0;
4186}
blueswir14583f582008-08-24 10:35:55 +00004187#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004188
bellardd2fd1af2007-11-14 18:08:56 +00004189#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004190abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004191{
Juan Quintela1add8692011-06-16 17:37:09 +01004192 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004193 abi_ulong val;
4194 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004195
bellardd2fd1af2007-11-14 18:08:56 +00004196 switch(code) {
4197 case TARGET_ARCH_SET_GS:
4198 case TARGET_ARCH_SET_FS:
4199 if (code == TARGET_ARCH_SET_GS)
4200 idx = R_GS;
4201 else
4202 idx = R_FS;
4203 cpu_x86_load_seg(env, idx, 0);
4204 env->segs[idx].base = addr;
4205 break;
4206 case TARGET_ARCH_GET_GS:
4207 case TARGET_ARCH_GET_FS:
4208 if (code == TARGET_ARCH_GET_GS)
4209 idx = R_GS;
4210 else
4211 idx = R_FS;
4212 val = env->segs[idx].base;
4213 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004214 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004215 break;
4216 default:
4217 ret = -TARGET_EINVAL;
4218 break;
4219 }
Juan Quintela1add8692011-06-16 17:37:09 +01004220 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004221}
4222#endif
4223
bellard2ab83ea2003-06-15 19:56:46 +00004224#endif /* defined(TARGET_I386) */
4225
Riku Voipio05098a92011-03-04 15:27:29 +02004226#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004227
pbrookd865bab2008-06-07 22:12:17 +00004228
4229static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4230typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004231 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004232 pthread_mutex_t mutex;
4233 pthread_cond_t cond;
4234 pthread_t thread;
4235 uint32_t tid;
4236 abi_ulong child_tidptr;
4237 abi_ulong parent_tidptr;
4238 sigset_t sigmask;
4239} new_thread_info;
4240
4241static void *clone_func(void *arg)
4242{
4243 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004244 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004245 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004246 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004247
4248 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004249 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004250 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004251 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004252 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004253 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004254 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004255 if (info->child_tidptr)
4256 put_user_u32(info->tid, info->child_tidptr);
4257 if (info->parent_tidptr)
4258 put_user_u32(info->tid, info->parent_tidptr);
4259 /* Enable signals. */
4260 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4261 /* Signal to the parent that we're ready. */
4262 pthread_mutex_lock(&info->mutex);
4263 pthread_cond_broadcast(&info->cond);
4264 pthread_mutex_unlock(&info->mutex);
4265 /* Wait until the parent has finshed initializing the tls state. */
4266 pthread_mutex_lock(&clone_lock);
4267 pthread_mutex_unlock(&clone_lock);
4268 cpu_loop(env);
4269 /* never exits */
4270 return NULL;
4271}
bellard1b6b0292003-03-22 17:31:38 +00004272
ths0da46a62007-10-20 20:23:07 +00004273/* do_fork() Must return host values and target errnos (unlike most
4274 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004275static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004276 abi_ulong parent_tidptr, target_ulong newtls,
4277 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004278{
Andreas Färber0429a972013-08-26 18:14:44 +02004279 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004280 int ret;
bellard5cd43932003-03-29 16:54:36 +00004281 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004282 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004283 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004284 unsigned int nptl_flags;
4285 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004286
balrog436d1242008-09-21 02:39:45 +00004287 /* Emulate vfork() with fork() */
4288 if (flags & CLONE_VFORK)
4289 flags &= ~(CLONE_VFORK | CLONE_VM);
4290
bellard1b6b0292003-03-22 17:31:38 +00004291 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004292 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004293 new_thread_info info;
4294 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004295
Anthony Liguori7267c092011-08-20 22:09:37 -05004296 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004297 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004298 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004299 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004300 /* Init regs that differ from the parent. */
4301 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004302 new_cpu = ENV_GET_CPU(new_env);
4303 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004304 ts->bprm = parent_ts->bprm;
4305 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004306 nptl_flags = flags;
4307 flags &= ~CLONE_NPTL_FLAGS2;
4308
pbrookc2764712009-03-07 15:24:59 +00004309 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4310 ts->child_tidptr = child_tidptr;
4311 }
4312
pbrookd865bab2008-06-07 22:12:17 +00004313 if (nptl_flags & CLONE_SETTLS)
4314 cpu_set_tls (new_env, newtls);
4315
4316 /* Grab a mutex so that thread setup appears atomic. */
4317 pthread_mutex_lock(&clone_lock);
4318
4319 memset(&info, 0, sizeof(info));
4320 pthread_mutex_init(&info.mutex, NULL);
4321 pthread_mutex_lock(&info.mutex);
4322 pthread_cond_init(&info.cond, NULL);
4323 info.env = new_env;
4324 if (nptl_flags & CLONE_CHILD_SETTID)
4325 info.child_tidptr = child_tidptr;
4326 if (nptl_flags & CLONE_PARENT_SETTID)
4327 info.parent_tidptr = parent_tidptr;
4328
4329 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004330 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4331 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004332 /* It is not safe to deliver signals until the child has finished
4333 initializing, so temporarily block all signals. */
4334 sigfillset(&sigmask);
4335 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4336
4337 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004338 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004339
4340 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4341 pthread_attr_destroy(&attr);
4342 if (ret == 0) {
4343 /* Wait for the child to initialize. */
4344 pthread_cond_wait(&info.cond, &info.mutex);
4345 ret = info.tid;
4346 if (flags & CLONE_PARENT_SETTID)
4347 put_user_u32(ret, parent_tidptr);
4348 } else {
4349 ret = -1;
4350 }
4351 pthread_mutex_unlock(&info.mutex);
4352 pthread_cond_destroy(&info.cond);
4353 pthread_mutex_destroy(&info.mutex);
4354 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004355 } else {
4356 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004357 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004358 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004359 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004360 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004361 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004362 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004363 cpu_clone_regs(env, newsp);
4364 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004365 /* There is a race condition here. The parent process could
4366 theoretically read the TID in the child process before the child
4367 tid is set. This would require using either ptrace
4368 (not implemented) or having *_tidptr to point at a shared memory
4369 mapping. We can't repeat the spinlock hack used above because
4370 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004371 if (flags & CLONE_CHILD_SETTID)
4372 put_user_u32(gettid(), child_tidptr);
4373 if (flags & CLONE_PARENT_SETTID)
4374 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004375 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004376 if (flags & CLONE_SETTLS)
4377 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004378 if (flags & CLONE_CHILD_CLEARTID)
4379 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004380 } else {
4381 fork_end(0);
4382 }
bellard1b6b0292003-03-22 17:31:38 +00004383 }
4384 return ret;
4385}
4386
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004387/* warning : doesn't handle linux specific flags... */
4388static int target_to_host_fcntl_cmd(int cmd)
4389{
4390 switch(cmd) {
4391 case TARGET_F_DUPFD:
4392 case TARGET_F_GETFD:
4393 case TARGET_F_SETFD:
4394 case TARGET_F_GETFL:
4395 case TARGET_F_SETFL:
4396 return cmd;
4397 case TARGET_F_GETLK:
4398 return F_GETLK;
4399 case TARGET_F_SETLK:
4400 return F_SETLK;
4401 case TARGET_F_SETLKW:
4402 return F_SETLKW;
4403 case TARGET_F_GETOWN:
4404 return F_GETOWN;
4405 case TARGET_F_SETOWN:
4406 return F_SETOWN;
4407 case TARGET_F_GETSIG:
4408 return F_GETSIG;
4409 case TARGET_F_SETSIG:
4410 return F_SETSIG;
4411#if TARGET_ABI_BITS == 32
4412 case TARGET_F_GETLK64:
4413 return F_GETLK64;
4414 case TARGET_F_SETLK64:
4415 return F_SETLK64;
4416 case TARGET_F_SETLKW64:
4417 return F_SETLKW64;
4418#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004419 case TARGET_F_SETLEASE:
4420 return F_SETLEASE;
4421 case TARGET_F_GETLEASE:
4422 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004423#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004424 case TARGET_F_DUPFD_CLOEXEC:
4425 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004426#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004427 case TARGET_F_NOTIFY:
4428 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004429#ifdef F_GETOWN_EX
4430 case TARGET_F_GETOWN_EX:
4431 return F_GETOWN_EX;
4432#endif
4433#ifdef F_SETOWN_EX
4434 case TARGET_F_SETOWN_EX:
4435 return F_SETOWN_EX;
4436#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004437 default:
4438 return -TARGET_EINVAL;
4439 }
4440 return -TARGET_EINVAL;
4441}
4442
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004443#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4444static const bitmask_transtbl flock_tbl[] = {
4445 TRANSTBL_CONVERT(F_RDLCK),
4446 TRANSTBL_CONVERT(F_WRLCK),
4447 TRANSTBL_CONVERT(F_UNLCK),
4448 TRANSTBL_CONVERT(F_EXLCK),
4449 TRANSTBL_CONVERT(F_SHLCK),
4450 { 0, 0, 0, 0 }
4451};
4452
blueswir1992f48a2007-10-14 16:27:31 +00004453static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004454{
4455 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004456 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004457 struct flock64 fl64;
4458 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004459#ifdef F_GETOWN_EX
4460 struct f_owner_ex fox;
4461 struct target_f_owner_ex *target_fox;
4462#endif
blueswir1992f48a2007-10-14 16:27:31 +00004463 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004464 int host_cmd = target_to_host_fcntl_cmd(cmd);
4465
4466 if (host_cmd == -TARGET_EINVAL)
4467 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004468
bellard7775e9e2003-05-14 22:46:48 +00004469 switch(cmd) {
4470 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004471 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4472 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004473 fl.l_type =
4474 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004475 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004476 fl.l_start = tswapal(target_fl->l_start);
4477 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004478 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004479 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004480 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004481 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004482 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4483 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004484 target_fl->l_type =
4485 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004486 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004487 target_fl->l_start = tswapal(fl.l_start);
4488 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004489 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004490 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004491 }
4492 break;
ths3b46e622007-09-17 08:09:54 +00004493
bellard7775e9e2003-05-14 22:46:48 +00004494 case TARGET_F_SETLK:
4495 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004496 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4497 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004498 fl.l_type =
4499 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004500 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004501 fl.l_start = tswapal(target_fl->l_start);
4502 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004503 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004504 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004505 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004506 break;
ths3b46e622007-09-17 08:09:54 +00004507
bellard7775e9e2003-05-14 22:46:48 +00004508 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004509 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4510 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004511 fl64.l_type =
4512 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004513 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004514 fl64.l_start = tswap64(target_fl64->l_start);
4515 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004516 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004517 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004518 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004519 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004520 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4521 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004522 target_fl64->l_type =
4523 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004524 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004525 target_fl64->l_start = tswap64(fl64.l_start);
4526 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004527 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004528 unlock_user_struct(target_fl64, arg, 1);
4529 }
bellard9ee1fa22007-11-11 15:11:19 +00004530 break;
bellard7775e9e2003-05-14 22:46:48 +00004531 case TARGET_F_SETLK64:
4532 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004533 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4534 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004535 fl64.l_type =
4536 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004537 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004538 fl64.l_start = tswap64(target_fl64->l_start);
4539 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004540 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004541 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004542 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004543 break;
4544
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004545 case TARGET_F_GETFL:
4546 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004547 if (ret >= 0) {
4548 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4549 }
bellardffa65c32004-01-04 23:57:22 +00004550 break;
4551
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004552 case TARGET_F_SETFL:
4553 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4554 break;
4555
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004556#ifdef F_GETOWN_EX
4557 case TARGET_F_GETOWN_EX:
4558 ret = get_errno(fcntl(fd, host_cmd, &fox));
4559 if (ret >= 0) {
4560 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4561 return -TARGET_EFAULT;
4562 target_fox->type = tswap32(fox.type);
4563 target_fox->pid = tswap32(fox.pid);
4564 unlock_user_struct(target_fox, arg, 1);
4565 }
4566 break;
4567#endif
4568
4569#ifdef F_SETOWN_EX
4570 case TARGET_F_SETOWN_EX:
4571 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4572 return -TARGET_EFAULT;
4573 fox.type = tswap32(target_fox->type);
4574 fox.pid = tswap32(target_fox->pid);
4575 unlock_user_struct(target_fox, arg, 0);
4576 ret = get_errno(fcntl(fd, host_cmd, &fox));
4577 break;
4578#endif
4579
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004580 case TARGET_F_SETOWN:
4581 case TARGET_F_GETOWN:
4582 case TARGET_F_SETSIG:
4583 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004584 case TARGET_F_SETLEASE:
4585 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004586 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004587 break;
4588
bellard7775e9e2003-05-14 22:46:48 +00004589 default:
bellard9ee1fa22007-11-11 15:11:19 +00004590 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004591 break;
4592 }
4593 return ret;
4594}
4595
bellard67867302003-11-23 17:05:30 +00004596#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004597
bellard67867302003-11-23 17:05:30 +00004598static inline int high2lowuid(int uid)
4599{
4600 if (uid > 65535)
4601 return 65534;
4602 else
4603 return uid;
4604}
4605
4606static inline int high2lowgid(int gid)
4607{
4608 if (gid > 65535)
4609 return 65534;
4610 else
4611 return gid;
4612}
4613
4614static inline int low2highuid(int uid)
4615{
4616 if ((int16_t)uid == -1)
4617 return -1;
4618 else
4619 return uid;
4620}
4621
4622static inline int low2highgid(int gid)
4623{
4624 if ((int16_t)gid == -1)
4625 return -1;
4626 else
4627 return gid;
4628}
Riku Voipio0c866a72011-04-18 15:23:06 +03004629static inline int tswapid(int id)
4630{
4631 return tswap16(id);
4632}
Peter Maydell76ca3102014-03-02 19:36:41 +00004633
4634#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4635
Riku Voipio0c866a72011-04-18 15:23:06 +03004636#else /* !USE_UID16 */
4637static inline int high2lowuid(int uid)
4638{
4639 return uid;
4640}
4641static inline int high2lowgid(int gid)
4642{
4643 return gid;
4644}
4645static inline int low2highuid(int uid)
4646{
4647 return uid;
4648}
4649static inline int low2highgid(int gid)
4650{
4651 return gid;
4652}
4653static inline int tswapid(int id)
4654{
4655 return tswap32(id);
4656}
Peter Maydell76ca3102014-03-02 19:36:41 +00004657
4658#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4659
bellard67867302003-11-23 17:05:30 +00004660#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004661
bellard31e31b82003-02-18 22:55:36 +00004662void syscall_init(void)
4663{
bellard2ab83ea2003-06-15 19:56:46 +00004664 IOCTLEntry *ie;
4665 const argtype *arg_type;
4666 int size;
thsb92c47c2007-11-01 00:07:38 +00004667 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004668
Blue Swirl001faf32009-05-13 17:53:17 +00004669#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004670#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004671#include "syscall_types.h"
4672#undef STRUCT
4673#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004674
Peter Maydelldd6e9572012-07-23 08:07:22 +00004675 /* Build target_to_host_errno_table[] table from
4676 * host_to_target_errno_table[]. */
4677 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4678 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4679 }
4680
bellard2ab83ea2003-06-15 19:56:46 +00004681 /* we patch the ioctl size if necessary. We rely on the fact that
4682 no ioctl has all the bits at '1' in the size field */
4683 ie = ioctl_entries;
4684 while (ie->target_cmd != 0) {
4685 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4686 TARGET_IOC_SIZEMASK) {
4687 arg_type = ie->arg_type;
4688 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004689 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004690 ie->target_cmd);
4691 exit(1);
4692 }
4693 arg_type++;
4694 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004695 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004696 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4697 (size << TARGET_IOC_SIZESHIFT);
4698 }
thsb92c47c2007-11-01 00:07:38 +00004699
bellard2ab83ea2003-06-15 19:56:46 +00004700 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004701#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4702 (defined(__x86_64__) && defined(TARGET_X86_64))
4703 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4704 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4705 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004706 }
4707#endif
4708 ie++;
4709 }
bellard31e31b82003-02-18 22:55:36 +00004710}
bellardc573ff62004-01-04 15:51:36 +00004711
blueswir1992f48a2007-10-14 16:27:31 +00004712#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004713static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4714{
thsaf325d32008-06-10 15:29:15 +00004715#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004716 return ((uint64_t)word0 << 32) | word1;
4717#else
4718 return ((uint64_t)word1 << 32) | word0;
4719#endif
4720}
blueswir1992f48a2007-10-14 16:27:31 +00004721#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004722static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4723{
4724 return word0;
4725}
blueswir1992f48a2007-10-14 16:27:31 +00004726#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004727
4728#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004729static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4730 abi_long arg2,
4731 abi_long arg3,
4732 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004733{
Riku Voipio48e515d2011-07-12 15:40:51 +03004734 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004735 arg2 = arg3;
4736 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004737 }
pbrookce4defa2006-02-09 16:49:55 +00004738 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4739}
4740#endif
4741
4742#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004743static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4744 abi_long arg2,
4745 abi_long arg3,
4746 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004747{
Riku Voipio48e515d2011-07-12 15:40:51 +03004748 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004749 arg2 = arg3;
4750 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004751 }
pbrookce4defa2006-02-09 16:49:55 +00004752 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4753}
4754#endif
4755
bellard579a97f2007-11-11 14:26:47 +00004756static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4757 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004758{
4759 struct target_timespec *target_ts;
4760
bellard579a97f2007-11-11 14:26:47 +00004761 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4762 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004763 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4764 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004765 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004766 return 0;
pbrook53a59602006-03-25 19:31:22 +00004767}
4768
bellard579a97f2007-11-11 14:26:47 +00004769static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4770 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004771{
4772 struct target_timespec *target_ts;
4773
bellard579a97f2007-11-11 14:26:47 +00004774 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4775 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004776 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4777 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004778 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004779 return 0;
pbrook53a59602006-03-25 19:31:22 +00004780}
4781
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004782static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4783 abi_ulong target_addr)
4784{
4785 struct target_itimerspec *target_itspec;
4786
4787 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4788 return -TARGET_EFAULT;
4789 }
4790
4791 host_itspec->it_interval.tv_sec =
4792 tswapal(target_itspec->it_interval.tv_sec);
4793 host_itspec->it_interval.tv_nsec =
4794 tswapal(target_itspec->it_interval.tv_nsec);
4795 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4796 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4797
4798 unlock_user_struct(target_itspec, target_addr, 1);
4799 return 0;
4800}
4801
4802static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4803 struct itimerspec *host_its)
4804{
4805 struct target_itimerspec *target_itspec;
4806
4807 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4808 return -TARGET_EFAULT;
4809 }
4810
4811 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4812 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4813
4814 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4815 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4816
4817 unlock_user_struct(target_itspec, target_addr, 0);
4818 return 0;
4819}
4820
aurel329d33b762009-04-08 23:07:05 +00004821#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004822static inline abi_long host_to_target_stat64(void *cpu_env,
4823 abi_ulong target_addr,
4824 struct stat *host_st)
4825{
Alexander Graf09701192013-09-03 20:12:15 +01004826#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004827 if (((CPUARMState *)cpu_env)->eabi) {
4828 struct target_eabi_stat64 *target_st;
4829
4830 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4831 return -TARGET_EFAULT;
4832 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4833 __put_user(host_st->st_dev, &target_st->st_dev);
4834 __put_user(host_st->st_ino, &target_st->st_ino);
4835#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4836 __put_user(host_st->st_ino, &target_st->__st_ino);
4837#endif
4838 __put_user(host_st->st_mode, &target_st->st_mode);
4839 __put_user(host_st->st_nlink, &target_st->st_nlink);
4840 __put_user(host_st->st_uid, &target_st->st_uid);
4841 __put_user(host_st->st_gid, &target_st->st_gid);
4842 __put_user(host_st->st_rdev, &target_st->st_rdev);
4843 __put_user(host_st->st_size, &target_st->st_size);
4844 __put_user(host_st->st_blksize, &target_st->st_blksize);
4845 __put_user(host_st->st_blocks, &target_st->st_blocks);
4846 __put_user(host_st->st_atime, &target_st->target_st_atime);
4847 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4848 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4849 unlock_user_struct(target_st, target_addr, 1);
4850 } else
4851#endif
4852 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004853#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004854 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004855#else
4856 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004857#endif
balrog6a24a772008-09-20 02:23:36 +00004858
4859 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4860 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004861 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004862 __put_user(host_st->st_dev, &target_st->st_dev);
4863 __put_user(host_st->st_ino, &target_st->st_ino);
4864#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4865 __put_user(host_st->st_ino, &target_st->__st_ino);
4866#endif
4867 __put_user(host_st->st_mode, &target_st->st_mode);
4868 __put_user(host_st->st_nlink, &target_st->st_nlink);
4869 __put_user(host_st->st_uid, &target_st->st_uid);
4870 __put_user(host_st->st_gid, &target_st->st_gid);
4871 __put_user(host_st->st_rdev, &target_st->st_rdev);
4872 /* XXX: better use of kernel struct */
4873 __put_user(host_st->st_size, &target_st->st_size);
4874 __put_user(host_st->st_blksize, &target_st->st_blksize);
4875 __put_user(host_st->st_blocks, &target_st->st_blocks);
4876 __put_user(host_st->st_atime, &target_st->target_st_atime);
4877 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4878 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4879 unlock_user_struct(target_st, target_addr, 1);
4880 }
4881
4882 return 0;
4883}
4884#endif
4885
pbrookbd0c5662008-05-29 14:34:11 +00004886/* ??? Using host futex calls even when target atomic operations
4887 are not really atomic probably breaks things. However implementing
4888 futexes locally would make futexes shared between multiple processes
4889 tricky. However they're probably useless because guest atomic
4890 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004891static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4892 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004893{
4894 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004895 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004896
4897 /* ??? We assume FUTEX_* constants are the same on both host
4898 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004899#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004900 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004901#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004902 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004903#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004904 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004905 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004906 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004907 if (timeout) {
4908 pts = &ts;
4909 target_to_host_timespec(pts, timeout);
4910 } else {
4911 pts = NULL;
4912 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004913 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004914 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004915 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004916 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004917 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004918 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004919 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004920 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004921 case FUTEX_WAKE_OP:
4922 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4923 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4924 But the prototype takes a `struct timespec *'; insert casts
4925 to satisfy the compiler. We do not need to tswap TIMEOUT
4926 since it's not compared to guest memory. */
4927 pts = (struct timespec *)(uintptr_t) timeout;
4928 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4929 g2h(uaddr2),
4930 (base_op == FUTEX_CMP_REQUEUE
4931 ? tswap32(val3)
4932 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004933 default:
4934 return -TARGET_ENOSYS;
4935 }
4936}
pbrookbd0c5662008-05-29 14:34:11 +00004937
pbrook1d9d8b52009-04-16 15:17:02 +00004938/* Map host to target signal numbers for the wait family of syscalls.
4939 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004940int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004941{
4942 if (WIFSIGNALED(status)) {
4943 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4944 }
4945 if (WIFSTOPPED(status)) {
4946 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4947 | (status & 0xff);
4948 }
4949 return status;
4950}
4951
Alexander Graf36c08d42011-11-02 20:23:24 +01004952static int open_self_maps(void *cpu_env, int fd)
4953{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004954#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber0429a972013-08-26 18:14:44 +02004955 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
4956 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004957#endif
4958 FILE *fp;
4959 char *line = NULL;
4960 size_t len = 0;
4961 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004962
Alexander Graf1a49ef22012-05-01 16:30:28 +01004963 fp = fopen("/proc/self/maps", "r");
4964 if (fp == NULL) {
4965 return -EACCES;
4966 }
4967
4968 while ((read = getline(&line, &len, fp)) != -1) {
4969 int fields, dev_maj, dev_min, inode;
4970 uint64_t min, max, offset;
4971 char flag_r, flag_w, flag_x, flag_p;
4972 char path[512] = "";
4973 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4974 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4975 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4976
4977 if ((fields < 10) || (fields > 11)) {
4978 continue;
4979 }
4980 if (!strncmp(path, "[stack]", 7)) {
4981 continue;
4982 }
4983 if (h2g_valid(min) && h2g_valid(max)) {
4984 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02004985 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01004986 h2g(min), h2g(max), flag_r, flag_w,
4987 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02004988 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01004989 }
4990 }
4991
4992 free(line);
4993 fclose(fp);
4994
4995#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01004996 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4997 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02004998 (unsigned long long)(ts->info->start_stack +
4999 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005000 (unsigned long long)0);
5001#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005002
5003 return 0;
5004}
5005
Alexander Graf480b8e72011-11-02 20:23:25 +01005006static int open_self_stat(void *cpu_env, int fd)
5007{
Andreas Färber0429a972013-08-26 18:14:44 +02005008 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5009 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005010 abi_ulong start_stack = ts->info->start_stack;
5011 int i;
5012
5013 for (i = 0; i < 44; i++) {
5014 char buf[128];
5015 int len;
5016 uint64_t val = 0;
5017
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005018 if (i == 0) {
5019 /* pid */
5020 val = getpid();
5021 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5022 } else if (i == 1) {
5023 /* app name */
5024 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5025 } else if (i == 27) {
5026 /* stack bottom */
5027 val = start_stack;
5028 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5029 } else {
5030 /* for the rest, there is MasterCard */
5031 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005032 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005033
Alexander Graf480b8e72011-11-02 20:23:25 +01005034 len = strlen(buf);
5035 if (write(fd, buf, len) != len) {
5036 return -1;
5037 }
5038 }
5039
5040 return 0;
5041}
5042
Alexander Graf257450e2011-11-02 20:23:26 +01005043static int open_self_auxv(void *cpu_env, int fd)
5044{
Andreas Färber0429a972013-08-26 18:14:44 +02005045 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5046 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005047 abi_ulong auxv = ts->info->saved_auxv;
5048 abi_ulong len = ts->info->auxv_len;
5049 char *ptr;
5050
5051 /*
5052 * Auxiliary vector is stored in target process stack.
5053 * read in whole auxv vector and copy it to file
5054 */
5055 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5056 if (ptr != NULL) {
5057 while (len > 0) {
5058 ssize_t r;
5059 r = write(fd, ptr, len);
5060 if (r <= 0) {
5061 break;
5062 }
5063 len -= r;
5064 ptr += r;
5065 }
5066 lseek(fd, 0, SEEK_SET);
5067 unlock_user(ptr, auxv, len);
5068 }
5069
5070 return 0;
5071}
5072
Andreas Schwab463d8e72013-07-02 14:04:12 +01005073static int is_proc_myself(const char *filename, const char *entry)
5074{
5075 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5076 filename += strlen("/proc/");
5077 if (!strncmp(filename, "self/", strlen("self/"))) {
5078 filename += strlen("self/");
5079 } else if (*filename >= '1' && *filename <= '9') {
5080 char myself[80];
5081 snprintf(myself, sizeof(myself), "%d/", getpid());
5082 if (!strncmp(filename, myself, strlen(myself))) {
5083 filename += strlen(myself);
5084 } else {
5085 return 0;
5086 }
5087 } else {
5088 return 0;
5089 }
5090 if (!strcmp(filename, entry)) {
5091 return 1;
5092 }
5093 }
5094 return 0;
5095}
5096
Laurent Vivierde6b9932013-08-30 01:46:40 +02005097#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5098static int is_proc(const char *filename, const char *entry)
5099{
5100 return strcmp(filename, entry) == 0;
5101}
5102
5103static int open_net_route(void *cpu_env, int fd)
5104{
5105 FILE *fp;
5106 char *line = NULL;
5107 size_t len = 0;
5108 ssize_t read;
5109
5110 fp = fopen("/proc/net/route", "r");
5111 if (fp == NULL) {
5112 return -EACCES;
5113 }
5114
5115 /* read header */
5116
5117 read = getline(&line, &len, fp);
5118 dprintf(fd, "%s", line);
5119
5120 /* read routes */
5121
5122 while ((read = getline(&line, &len, fp)) != -1) {
5123 char iface[16];
5124 uint32_t dest, gw, mask;
5125 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5126 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5127 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5128 &mask, &mtu, &window, &irtt);
5129 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5130 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5131 metric, tswap32(mask), mtu, window, irtt);
5132 }
5133
5134 free(line);
5135 fclose(fp);
5136
5137 return 0;
5138}
5139#endif
5140
Alexander Graf3be14d02011-11-02 20:23:23 +01005141static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5142{
5143 struct fake_open {
5144 const char *filename;
5145 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005146 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005147 };
5148 const struct fake_open *fake_open;
5149 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005150 { "maps", open_self_maps, is_proc_myself },
5151 { "stat", open_self_stat, is_proc_myself },
5152 { "auxv", open_self_auxv, is_proc_myself },
5153#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5154 { "/proc/net/route", open_net_route, is_proc },
5155#endif
5156 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005157 };
5158
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005159 if (is_proc_myself(pathname, "exe")) {
5160 int execfd = qemu_getauxval(AT_EXECFD);
5161 return execfd ? execfd : get_errno(open(exec_path, flags, mode));
5162 }
5163
Alexander Graf3be14d02011-11-02 20:23:23 +01005164 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005165 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005166 break;
5167 }
5168 }
5169
5170 if (fake_open->filename) {
5171 const char *tmpdir;
5172 char filename[PATH_MAX];
5173 int fd, r;
5174
5175 /* create temporary file to map stat to */
5176 tmpdir = getenv("TMPDIR");
5177 if (!tmpdir)
5178 tmpdir = "/tmp";
5179 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5180 fd = mkstemp(filename);
5181 if (fd < 0) {
5182 return fd;
5183 }
5184 unlink(filename);
5185
5186 if ((r = fake_open->fill(cpu_env, fd))) {
5187 close(fd);
5188 return r;
5189 }
5190 lseek(fd, 0, SEEK_SET);
5191
5192 return fd;
5193 }
5194
5195 return get_errno(open(path(pathname), flags, mode));
5196}
5197
ths0da46a62007-10-20 20:23:07 +00005198/* do_syscall() should always have a single exit point at the end so
5199 that actions, such as logging of syscall results, can be performed.
5200 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005201abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5202 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005203 abi_long arg5, abi_long arg6, abi_long arg7,
5204 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005205{
Andreas Färber182735e2013-05-29 22:29:20 +02005206 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005207 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005208 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005209 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005210 void *p;
ths3b46e622007-09-17 08:09:54 +00005211
bellard72f03902003-02-18 23:33:18 +00005212#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005213 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005214#endif
thsb92c47c2007-11-01 00:07:38 +00005215 if(do_strace)
5216 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5217
bellard31e31b82003-02-18 22:55:36 +00005218 switch(num) {
5219 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005220 /* In old applications this may be used to implement _exit(2).
5221 However in threaded applictions it is used for thread termination,
5222 and _exit_group is used for application termination.
5223 Do thread termination if we have more then one thread. */
5224 /* FIXME: This probably breaks if a signal arrives. We should probably
5225 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005226 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005227 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005228
Andreas Färber9b056fc2013-06-24 23:53:10 +02005229 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005230 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005231 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005232 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005233 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005234 if (ts->child_tidptr) {
5235 put_user_u32(0, ts->child_tidptr);
5236 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5237 NULL, NULL, 0);
5238 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005239 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005240 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005241 g_free(ts);
5242 pthread_exit(NULL);
5243 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005244#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005245 _mcleanup();
5246#endif
bellarde9009672005-04-26 20:42:36 +00005247 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005248 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005249 ret = 0; /* avoid warning */
5250 break;
5251 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005252 if (arg3 == 0)
5253 ret = 0;
5254 else {
5255 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5256 goto efault;
5257 ret = get_errno(read(arg1, p, arg3));
5258 unlock_user(p, arg2, ret);
5259 }
bellard31e31b82003-02-18 22:55:36 +00005260 break;
5261 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005262 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5263 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005264 ret = get_errno(write(arg1, p, arg3));
5265 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005266 break;
5267 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005268 if (!(p = lock_user_string(arg1)))
5269 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005270 ret = get_errno(do_open(cpu_env, p,
5271 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5272 arg3));
pbrook53a59602006-03-25 19:31:22 +00005273 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005274 break;
ths82424832007-09-24 09:21:55 +00005275#if defined(TARGET_NR_openat) && defined(__NR_openat)
5276 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005277 if (!(p = lock_user_string(arg2)))
5278 goto efault;
5279 ret = get_errno(sys_openat(arg1,
5280 path(p),
5281 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5282 arg4));
5283 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005284 break;
5285#endif
bellard31e31b82003-02-18 22:55:36 +00005286 case TARGET_NR_close:
5287 ret = get_errno(close(arg1));
5288 break;
5289 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005290 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005291 break;
5292 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005293 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005294 break;
thse5febef2007-04-01 18:31:35 +00005295#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005296 case TARGET_NR_waitpid:
5297 {
pbrook53a59602006-03-25 19:31:22 +00005298 int status;
5299 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005300 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005301 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005302 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005303 }
5304 break;
thse5febef2007-04-01 18:31:35 +00005305#endif
pbrookf0cbb612008-05-30 18:20:05 +00005306#ifdef TARGET_NR_waitid
5307 case TARGET_NR_waitid:
5308 {
5309 siginfo_t info;
5310 info.si_pid = 0;
5311 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5312 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005313 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005314 goto efault;
5315 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005316 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005317 }
5318 }
5319 break;
5320#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005321#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005322 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005323 if (!(p = lock_user_string(arg1)))
5324 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005325 ret = get_errno(creat(p, arg2));
5326 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005327 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005328#endif
bellard31e31b82003-02-18 22:55:36 +00005329 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005330 {
5331 void * p2;
5332 p = lock_user_string(arg1);
5333 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005334 if (!p || !p2)
5335 ret = -TARGET_EFAULT;
5336 else
5337 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005338 unlock_user(p2, arg2, 0);
5339 unlock_user(p, arg1, 0);
5340 }
bellard31e31b82003-02-18 22:55:36 +00005341 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005342#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005343 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005344 {
5345 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005346 if (!arg2 || !arg4)
5347 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005348 p = lock_user_string(arg2);
5349 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005350 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005351 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005352 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005353 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005354 unlock_user(p, arg2, 0);
5355 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005356 }
5357 break;
5358#endif
bellard31e31b82003-02-18 22:55:36 +00005359 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005360 if (!(p = lock_user_string(arg1)))
5361 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005362 ret = get_errno(unlink(p));
5363 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005364 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005365#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005366 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005367 if (!(p = lock_user_string(arg2)))
5368 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005369 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005370 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005371 break;
balrogb7d35e62007-12-12 00:40:24 +00005372#endif
bellard31e31b82003-02-18 22:55:36 +00005373 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005374 {
5375 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005376 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005377 abi_ulong gp;
5378 abi_ulong guest_argp;
5379 abi_ulong guest_envp;
5380 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005381 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005382 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005383
bellardf7341ff2003-03-30 21:00:25 +00005384 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005385 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005386 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005387 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005388 goto efault;
ths03aa1972007-12-02 06:28:08 +00005389 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005390 break;
bellard7854b052003-03-29 17:22:23 +00005391 argc++;
bellard2f619692007-11-16 10:46:05 +00005392 }
bellardf7341ff2003-03-30 21:00:25 +00005393 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005394 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005395 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005396 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005397 goto efault;
ths03aa1972007-12-02 06:28:08 +00005398 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005399 break;
bellard7854b052003-03-29 17:22:23 +00005400 envc++;
bellard2f619692007-11-16 10:46:05 +00005401 }
bellard7854b052003-03-29 17:22:23 +00005402
bellardf7341ff2003-03-30 21:00:25 +00005403 argp = alloca((argc + 1) * sizeof(void *));
5404 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005405
pbrookda94d262008-05-30 18:24:00 +00005406 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005407 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005408 if (get_user_ual(addr, gp))
5409 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005410 if (!addr)
5411 break;
bellard2f619692007-11-16 10:46:05 +00005412 if (!(*q = lock_user_string(addr)))
5413 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005414 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005415 }
bellardf7341ff2003-03-30 21:00:25 +00005416 *q = NULL;
5417
pbrookda94d262008-05-30 18:24:00 +00005418 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005419 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005420 if (get_user_ual(addr, gp))
5421 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005422 if (!addr)
5423 break;
bellard2f619692007-11-16 10:46:05 +00005424 if (!(*q = lock_user_string(addr)))
5425 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005426 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005427 }
bellardf7341ff2003-03-30 21:00:25 +00005428 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005429
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005430 /* This case will not be caught by the host's execve() if its
5431 page size is bigger than the target's. */
5432 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5433 ret = -TARGET_E2BIG;
5434 goto execve_end;
5435 }
bellard2f619692007-11-16 10:46:05 +00005436 if (!(p = lock_user_string(arg1)))
5437 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005438 ret = get_errno(execve(p, argp, envp));
5439 unlock_user(p, arg1, 0);
5440
bellard2f619692007-11-16 10:46:05 +00005441 goto execve_end;
5442
5443 execve_efault:
5444 ret = -TARGET_EFAULT;
5445
5446 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005447 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005448 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005449 if (get_user_ual(addr, gp)
5450 || !addr)
5451 break;
pbrook53a59602006-03-25 19:31:22 +00005452 unlock_user(*q, addr, 0);
5453 }
5454 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005455 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005456 if (get_user_ual(addr, gp)
5457 || !addr)
5458 break;
pbrook53a59602006-03-25 19:31:22 +00005459 unlock_user(*q, addr, 0);
5460 }
bellard7854b052003-03-29 17:22:23 +00005461 }
bellard31e31b82003-02-18 22:55:36 +00005462 break;
5463 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005464 if (!(p = lock_user_string(arg1)))
5465 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005466 ret = get_errno(chdir(p));
5467 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005468 break;
bellarda315a142005-01-30 22:59:18 +00005469#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005470 case TARGET_NR_time:
5471 {
pbrook53a59602006-03-25 19:31:22 +00005472 time_t host_time;
5473 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005474 if (!is_error(ret)
5475 && arg1
5476 && put_user_sal(host_time, arg1))
5477 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005478 }
5479 break;
bellarda315a142005-01-30 22:59:18 +00005480#endif
bellard31e31b82003-02-18 22:55:36 +00005481 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005482 if (!(p = lock_user_string(arg1)))
5483 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005484 ret = get_errno(mknod(p, arg2, arg3));
5485 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005486 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005487#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005488 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005489 if (!(p = lock_user_string(arg2)))
5490 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005491 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005492 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005493 break;
5494#endif
bellard31e31b82003-02-18 22:55:36 +00005495 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005496 if (!(p = lock_user_string(arg1)))
5497 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005498 ret = get_errno(chmod(p, arg2));
5499 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005500 break;
bellardebc05482003-09-30 21:08:41 +00005501#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005502 case TARGET_NR_break:
5503 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005504#endif
5505#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005506 case TARGET_NR_oldstat:
5507 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005508#endif
bellard31e31b82003-02-18 22:55:36 +00005509 case TARGET_NR_lseek:
5510 ret = get_errno(lseek(arg1, arg2, arg3));
5511 break;
Richard Henderson92317332010-05-03 10:07:53 -07005512#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5513 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005514 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005515 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005516 ret = get_errno(getpid());
5517 break;
Richard Henderson92317332010-05-03 10:07:53 -07005518#endif
5519#ifdef TARGET_NR_getpid
5520 case TARGET_NR_getpid:
5521 ret = get_errno(getpid());
5522 break;
5523#endif
bellard31e31b82003-02-18 22:55:36 +00005524 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005525 {
5526 /* need to look at the data field */
5527 void *p2, *p3;
5528 p = lock_user_string(arg1);
5529 p2 = lock_user_string(arg2);
5530 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005531 if (!p || !p2 || !p3)
5532 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005533 else {
bellard579a97f2007-11-11 14:26:47 +00005534 /* FIXME - arg5 should be locked, but it isn't clear how to
5535 * do that since it's not guaranteed to be a NULL-terminated
5536 * string.
5537 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005538 if ( ! arg5 )
5539 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5540 else
5541 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5542 }
bellard579a97f2007-11-11 14:26:47 +00005543 unlock_user(p, arg1, 0);
5544 unlock_user(p2, arg2, 0);
5545 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005546 break;
5547 }
thse5febef2007-04-01 18:31:35 +00005548#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005549 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005550 if (!(p = lock_user_string(arg1)))
5551 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005552 ret = get_errno(umount(p));
5553 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005554 break;
thse5febef2007-04-01 18:31:35 +00005555#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005556#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005557 case TARGET_NR_stime:
5558 {
pbrook53a59602006-03-25 19:31:22 +00005559 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005560 if (get_user_sal(host_time, arg1))
5561 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005562 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005563 }
5564 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005565#endif
bellard31e31b82003-02-18 22:55:36 +00005566 case TARGET_NR_ptrace:
5567 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005568#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005569 case TARGET_NR_alarm:
5570 ret = alarm(arg1);
5571 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005572#endif
bellardebc05482003-09-30 21:08:41 +00005573#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005574 case TARGET_NR_oldfstat:
5575 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005576#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005577#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005578 case TARGET_NR_pause:
5579 ret = get_errno(pause());
5580 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005581#endif
thse5febef2007-04-01 18:31:35 +00005582#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005583 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005584 {
pbrook53a59602006-03-25 19:31:22 +00005585 struct utimbuf tbuf, *host_tbuf;
5586 struct target_utimbuf *target_tbuf;
5587 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005588 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5589 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005590 tbuf.actime = tswapal(target_tbuf->actime);
5591 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005592 unlock_user_struct(target_tbuf, arg2, 0);
5593 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005594 } else {
pbrook53a59602006-03-25 19:31:22 +00005595 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005596 }
bellard579a97f2007-11-11 14:26:47 +00005597 if (!(p = lock_user_string(arg1)))
5598 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005599 ret = get_errno(utime(p, host_tbuf));
5600 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005601 }
5602 break;
thse5febef2007-04-01 18:31:35 +00005603#endif
bellard978a66f2004-12-06 22:58:05 +00005604 case TARGET_NR_utimes:
5605 {
bellard978a66f2004-12-06 22:58:05 +00005606 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005607 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005608 if (copy_from_user_timeval(&tv[0], arg2)
5609 || copy_from_user_timeval(&tv[1],
5610 arg2 + sizeof(struct target_timeval)))
5611 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005612 tvp = tv;
5613 } else {
5614 tvp = NULL;
5615 }
bellard579a97f2007-11-11 14:26:47 +00005616 if (!(p = lock_user_string(arg1)))
5617 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005618 ret = get_errno(utimes(p, tvp));
5619 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005620 }
5621 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005622#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005623 case TARGET_NR_futimesat:
5624 {
5625 struct timeval *tvp, tv[2];
5626 if (arg3) {
5627 if (copy_from_user_timeval(&tv[0], arg3)
5628 || copy_from_user_timeval(&tv[1],
5629 arg3 + sizeof(struct target_timeval)))
5630 goto efault;
5631 tvp = tv;
5632 } else {
5633 tvp = NULL;
5634 }
5635 if (!(p = lock_user_string(arg2)))
5636 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005637 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005638 unlock_user(p, arg2, 0);
5639 }
5640 break;
5641#endif
bellardebc05482003-09-30 21:08:41 +00005642#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005643 case TARGET_NR_stty:
5644 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005645#endif
5646#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005647 case TARGET_NR_gtty:
5648 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005649#endif
bellard31e31b82003-02-18 22:55:36 +00005650 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005651 if (!(p = lock_user_string(arg1)))
5652 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005653 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005654 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005655 break;
ths92a34c12007-09-24 09:27:49 +00005656#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5657 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005658 if (!(p = lock_user_string(arg2)))
5659 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005660 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005661 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005662 break;
5663#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005664#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005665 case TARGET_NR_nice:
5666 ret = get_errno(nice(arg1));
5667 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005668#endif
bellardebc05482003-09-30 21:08:41 +00005669#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005670 case TARGET_NR_ftime:
5671 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005672#endif
bellard31e31b82003-02-18 22:55:36 +00005673 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005674 sync();
5675 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005676 break;
5677 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005678 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005679 break;
5680 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005681 {
5682 void *p2;
5683 p = lock_user_string(arg1);
5684 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005685 if (!p || !p2)
5686 ret = -TARGET_EFAULT;
5687 else
5688 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005689 unlock_user(p2, arg2, 0);
5690 unlock_user(p, arg1, 0);
5691 }
bellard31e31b82003-02-18 22:55:36 +00005692 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005693#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005694 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005695 {
bellard579a97f2007-11-11 14:26:47 +00005696 void *p2;
ths722183f2007-09-24 09:24:37 +00005697 p = lock_user_string(arg2);
5698 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005699 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005700 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005701 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005702 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005703 unlock_user(p2, arg4, 0);
5704 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005705 }
5706 break;
5707#endif
bellard31e31b82003-02-18 22:55:36 +00005708 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005709 if (!(p = lock_user_string(arg1)))
5710 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005711 ret = get_errno(mkdir(p, arg2));
5712 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005713 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005714#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005715 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005716 if (!(p = lock_user_string(arg2)))
5717 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005718 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005719 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005720 break;
5721#endif
bellard31e31b82003-02-18 22:55:36 +00005722 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005723 if (!(p = lock_user_string(arg1)))
5724 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005725 ret = get_errno(rmdir(p));
5726 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005727 break;
5728 case TARGET_NR_dup:
5729 ret = get_errno(dup(arg1));
5730 break;
5731 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005732 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005733 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005734#ifdef TARGET_NR_pipe2
5735 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005736 ret = do_pipe(cpu_env, arg1,
5737 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005738 break;
5739#endif
bellard31e31b82003-02-18 22:55:36 +00005740 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005741 {
pbrook53a59602006-03-25 19:31:22 +00005742 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005743 struct tms tms;
5744 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005745 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005746 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5747 if (!tmsp)
5748 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005749 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5750 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5751 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5752 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005753 }
bellardc596ed12003-07-13 17:32:31 +00005754 if (!is_error(ret))
5755 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005756 }
5757 break;
bellardebc05482003-09-30 21:08:41 +00005758#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005759 case TARGET_NR_prof:
5760 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005761#endif
thse5febef2007-04-01 18:31:35 +00005762#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005763 case TARGET_NR_signal:
5764 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005765#endif
bellard31e31b82003-02-18 22:55:36 +00005766 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005767 if (arg1 == 0) {
5768 ret = get_errno(acct(NULL));
5769 } else {
5770 if (!(p = lock_user_string(arg1)))
5771 goto efault;
5772 ret = get_errno(acct(path(p)));
5773 unlock_user(p, arg1, 0);
5774 }
pbrook24836682006-04-16 14:14:53 +00005775 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005776#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005777 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005778 if (!(p = lock_user_string(arg1)))
5779 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005780 ret = get_errno(umount2(p, arg2));
5781 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005782 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005783#endif
bellardebc05482003-09-30 21:08:41 +00005784#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005785 case TARGET_NR_lock:
5786 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005787#endif
bellard31e31b82003-02-18 22:55:36 +00005788 case TARGET_NR_ioctl:
5789 ret = do_ioctl(arg1, arg2, arg3);
5790 break;
5791 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005792 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005793 break;
bellardebc05482003-09-30 21:08:41 +00005794#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005795 case TARGET_NR_mpx:
5796 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005797#endif
bellard31e31b82003-02-18 22:55:36 +00005798 case TARGET_NR_setpgid:
5799 ret = get_errno(setpgid(arg1, arg2));
5800 break;
bellardebc05482003-09-30 21:08:41 +00005801#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005802 case TARGET_NR_ulimit:
5803 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005804#endif
5805#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005806 case TARGET_NR_oldolduname:
5807 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005808#endif
bellard31e31b82003-02-18 22:55:36 +00005809 case TARGET_NR_umask:
5810 ret = get_errno(umask(arg1));
5811 break;
5812 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005813 if (!(p = lock_user_string(arg1)))
5814 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005815 ret = get_errno(chroot(p));
5816 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005817 break;
5818 case TARGET_NR_ustat:
5819 goto unimplemented;
5820 case TARGET_NR_dup2:
5821 ret = get_errno(dup2(arg1, arg2));
5822 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005823#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5824 case TARGET_NR_dup3:
5825 ret = get_errno(dup3(arg1, arg2, arg3));
5826 break;
5827#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005828#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005829 case TARGET_NR_getppid:
5830 ret = get_errno(getppid());
5831 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005832#endif
bellard31e31b82003-02-18 22:55:36 +00005833 case TARGET_NR_getpgrp:
5834 ret = get_errno(getpgrp());
5835 break;
5836 case TARGET_NR_setsid:
5837 ret = get_errno(setsid());
5838 break;
thse5febef2007-04-01 18:31:35 +00005839#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005840 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005841 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005842#if defined(TARGET_ALPHA)
5843 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005844 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005845 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005846 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5847 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005848 act._sa_handler = old_act->_sa_handler;
5849 target_siginitset(&act.sa_mask, old_act->sa_mask);
5850 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005851 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005852 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005853 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005854 }
5855 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005856 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005857 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5858 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005859 old_act->_sa_handler = oact._sa_handler;
5860 old_act->sa_mask = oact.sa_mask.sig[0];
5861 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005862 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005863 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005864#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005865 struct target_sigaction act, oact, *pact, *old_act;
5866
5867 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005868 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5869 goto efault;
bellard106ec872006-06-27 21:08:10 +00005870 act._sa_handler = old_act->_sa_handler;
5871 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5872 act.sa_flags = old_act->sa_flags;
5873 unlock_user_struct(old_act, arg2, 0);
5874 pact = &act;
5875 } else {
5876 pact = NULL;
5877 }
5878
5879 ret = get_errno(do_sigaction(arg1, pact, &oact));
5880
5881 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005882 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5883 goto efault;
bellard106ec872006-06-27 21:08:10 +00005884 old_act->_sa_handler = oact._sa_handler;
5885 old_act->sa_flags = oact.sa_flags;
5886 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5887 old_act->sa_mask.sig[1] = 0;
5888 old_act->sa_mask.sig[2] = 0;
5889 old_act->sa_mask.sig[3] = 0;
5890 unlock_user_struct(old_act, arg3, 1);
5891 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005892#else
5893 struct target_old_sigaction *old_act;
5894 struct target_sigaction act, oact, *pact;
5895 if (arg2) {
5896 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5897 goto efault;
5898 act._sa_handler = old_act->_sa_handler;
5899 target_siginitset(&act.sa_mask, old_act->sa_mask);
5900 act.sa_flags = old_act->sa_flags;
5901 act.sa_restorer = old_act->sa_restorer;
5902 unlock_user_struct(old_act, arg2, 0);
5903 pact = &act;
5904 } else {
5905 pact = NULL;
5906 }
5907 ret = get_errno(do_sigaction(arg1, pact, &oact));
5908 if (!is_error(ret) && arg3) {
5909 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5910 goto efault;
5911 old_act->_sa_handler = oact._sa_handler;
5912 old_act->sa_mask = oact.sa_mask.sig[0];
5913 old_act->sa_flags = oact.sa_flags;
5914 old_act->sa_restorer = oact.sa_restorer;
5915 unlock_user_struct(old_act, arg3, 1);
5916 }
ths388bb212007-05-13 13:58:00 +00005917#endif
bellard31e31b82003-02-18 22:55:36 +00005918 }
5919 break;
thse5febef2007-04-01 18:31:35 +00005920#endif
bellard66fb9762003-03-23 01:06:05 +00005921 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005922 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005923#if defined(TARGET_ALPHA)
5924 struct target_sigaction act, oact, *pact = 0;
5925 struct target_rt_sigaction *rt_act;
5926 /* ??? arg4 == sizeof(sigset_t). */
5927 if (arg2) {
5928 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5929 goto efault;
5930 act._sa_handler = rt_act->_sa_handler;
5931 act.sa_mask = rt_act->sa_mask;
5932 act.sa_flags = rt_act->sa_flags;
5933 act.sa_restorer = arg5;
5934 unlock_user_struct(rt_act, arg2, 0);
5935 pact = &act;
5936 }
5937 ret = get_errno(do_sigaction(arg1, pact, &oact));
5938 if (!is_error(ret) && arg3) {
5939 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5940 goto efault;
5941 rt_act->_sa_handler = oact._sa_handler;
5942 rt_act->sa_mask = oact.sa_mask;
5943 rt_act->sa_flags = oact.sa_flags;
5944 unlock_user_struct(rt_act, arg3, 1);
5945 }
5946#else
pbrook53a59602006-03-25 19:31:22 +00005947 struct target_sigaction *act;
5948 struct target_sigaction *oact;
5949
bellard579a97f2007-11-11 14:26:47 +00005950 if (arg2) {
5951 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5952 goto efault;
5953 } else
pbrook53a59602006-03-25 19:31:22 +00005954 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005955 if (arg3) {
5956 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5957 ret = -TARGET_EFAULT;
5958 goto rt_sigaction_fail;
5959 }
5960 } else
pbrook53a59602006-03-25 19:31:22 +00005961 oact = NULL;
5962 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005963 rt_sigaction_fail:
5964 if (act)
pbrook53a59602006-03-25 19:31:22 +00005965 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005966 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005967 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005968#endif
pbrook53a59602006-03-25 19:31:22 +00005969 }
bellard66fb9762003-03-23 01:06:05 +00005970 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005971#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005972 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005973 {
5974 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005975 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00005976 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00005977 host_to_target_old_sigset(&target_set, &cur_set);
5978 ret = target_set;
5979 }
5980 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005981#endif
5982#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005983 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005984 {
5985 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005986 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00005987 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00005988 target_to_host_old_sigset(&set, &target_set);
5989 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005990 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00005991 host_to_target_old_sigset(&target_set, &oset);
5992 ret = target_set;
5993 }
5994 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005995#endif
thse5febef2007-04-01 18:31:35 +00005996#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005997 case TARGET_NR_sigprocmask:
5998 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005999#if defined(TARGET_ALPHA)
6000 sigset_t set, oldset;
6001 abi_ulong mask;
6002 int how;
6003
6004 switch (arg1) {
6005 case TARGET_SIG_BLOCK:
6006 how = SIG_BLOCK;
6007 break;
6008 case TARGET_SIG_UNBLOCK:
6009 how = SIG_UNBLOCK;
6010 break;
6011 case TARGET_SIG_SETMASK:
6012 how = SIG_SETMASK;
6013 break;
6014 default:
6015 ret = -TARGET_EINVAL;
6016 goto fail;
6017 }
6018 mask = arg2;
6019 target_to_host_old_sigset(&set, &mask);
6020
Alex Barcelo1c275922014-03-14 14:36:55 +00006021 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006022 if (!is_error(ret)) {
6023 host_to_target_old_sigset(&mask, &oldset);
6024 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006025 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006026 }
6027#else
bellard66fb9762003-03-23 01:06:05 +00006028 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006029 int how;
ths3b46e622007-09-17 08:09:54 +00006030
pbrook53a59602006-03-25 19:31:22 +00006031 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006032 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006033 case TARGET_SIG_BLOCK:
6034 how = SIG_BLOCK;
6035 break;
6036 case TARGET_SIG_UNBLOCK:
6037 how = SIG_UNBLOCK;
6038 break;
6039 case TARGET_SIG_SETMASK:
6040 how = SIG_SETMASK;
6041 break;
6042 default:
ths0da46a62007-10-20 20:23:07 +00006043 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006044 goto fail;
6045 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006046 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006047 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006048 target_to_host_old_sigset(&set, p);
6049 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006050 set_ptr = &set;
6051 } else {
6052 how = 0;
6053 set_ptr = NULL;
6054 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006055 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006056 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006057 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006058 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006059 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006060 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006061 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006062#endif
bellard66fb9762003-03-23 01:06:05 +00006063 }
6064 break;
thse5febef2007-04-01 18:31:35 +00006065#endif
bellard66fb9762003-03-23 01:06:05 +00006066 case TARGET_NR_rt_sigprocmask:
6067 {
6068 int how = arg1;
6069 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006070
pbrook53a59602006-03-25 19:31:22 +00006071 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006072 switch(how) {
6073 case TARGET_SIG_BLOCK:
6074 how = SIG_BLOCK;
6075 break;
6076 case TARGET_SIG_UNBLOCK:
6077 how = SIG_UNBLOCK;
6078 break;
6079 case TARGET_SIG_SETMASK:
6080 how = SIG_SETMASK;
6081 break;
6082 default:
ths0da46a62007-10-20 20:23:07 +00006083 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006084 goto fail;
6085 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006086 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006087 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006088 target_to_host_sigset(&set, p);
6089 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006090 set_ptr = &set;
6091 } else {
6092 how = 0;
6093 set_ptr = NULL;
6094 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006095 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006096 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006097 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006098 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006099 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006100 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006101 }
6102 }
6103 break;
thse5febef2007-04-01 18:31:35 +00006104#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006105 case TARGET_NR_sigpending:
6106 {
6107 sigset_t set;
6108 ret = get_errno(sigpending(&set));
6109 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006110 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006111 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006112 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006113 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006114 }
6115 }
6116 break;
thse5febef2007-04-01 18:31:35 +00006117#endif
bellard66fb9762003-03-23 01:06:05 +00006118 case TARGET_NR_rt_sigpending:
6119 {
6120 sigset_t set;
6121 ret = get_errno(sigpending(&set));
6122 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006123 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006124 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006125 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006126 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006127 }
6128 }
6129 break;
thse5febef2007-04-01 18:31:35 +00006130#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006131 case TARGET_NR_sigsuspend:
6132 {
6133 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006134#if defined(TARGET_ALPHA)
6135 abi_ulong mask = arg1;
6136 target_to_host_old_sigset(&set, &mask);
6137#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006138 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006139 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006140 target_to_host_old_sigset(&set, p);
6141 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006142#endif
bellard66fb9762003-03-23 01:06:05 +00006143 ret = get_errno(sigsuspend(&set));
6144 }
6145 break;
thse5febef2007-04-01 18:31:35 +00006146#endif
bellard66fb9762003-03-23 01:06:05 +00006147 case TARGET_NR_rt_sigsuspend:
6148 {
6149 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006150 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006151 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006152 target_to_host_sigset(&set, p);
6153 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006154 ret = get_errno(sigsuspend(&set));
6155 }
6156 break;
6157 case TARGET_NR_rt_sigtimedwait:
6158 {
bellard66fb9762003-03-23 01:06:05 +00006159 sigset_t set;
6160 struct timespec uts, *puts;
6161 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006162
Anthony Liguoric227f092009-10-01 16:12:16 -05006163 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006164 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006165 target_to_host_sigset(&set, p);
6166 unlock_user(p, arg1, 0);
6167 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006168 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006169 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006170 } else {
6171 puts = NULL;
6172 }
6173 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006174 if (!is_error(ret)) {
6175 if (arg2) {
6176 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6177 0);
6178 if (!p) {
6179 goto efault;
6180 }
6181 host_to_target_siginfo(p, &uinfo);
6182 unlock_user(p, arg2, sizeof(target_siginfo_t));
6183 }
6184 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006185 }
6186 }
6187 break;
6188 case TARGET_NR_rt_sigqueueinfo:
6189 {
6190 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006191 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006192 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006193 target_to_host_siginfo(&uinfo, p);
6194 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006195 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6196 }
6197 break;
thse5febef2007-04-01 18:31:35 +00006198#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006199 case TARGET_NR_sigreturn:
6200 /* NOTE: ret is eax, so not transcoding must be done */
6201 ret = do_sigreturn(cpu_env);
6202 break;
thse5febef2007-04-01 18:31:35 +00006203#endif
bellard66fb9762003-03-23 01:06:05 +00006204 case TARGET_NR_rt_sigreturn:
6205 /* NOTE: ret is eax, so not transcoding must be done */
6206 ret = do_rt_sigreturn(cpu_env);
6207 break;
bellard31e31b82003-02-18 22:55:36 +00006208 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006209 if (!(p = lock_user_string(arg1)))
6210 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006211 ret = get_errno(sethostname(p, arg2));
6212 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006213 break;
6214 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006215 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006216 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006217 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006218 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006219 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6220 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006221 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6222 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006223 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006224 ret = get_errno(setrlimit(resource, &rlim));
6225 }
6226 break;
bellard31e31b82003-02-18 22:55:36 +00006227 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006228 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006229 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006230 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006231 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006232
bellard9de5e442003-03-23 16:49:39 +00006233 ret = get_errno(getrlimit(resource, &rlim));
6234 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006235 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6236 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006237 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6238 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006239 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006240 }
6241 }
6242 break;
bellard31e31b82003-02-18 22:55:36 +00006243 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006244 {
6245 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006246 ret = get_errno(getrusage(arg1, &rusage));
6247 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006248 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006249 }
6250 }
6251 break;
bellard31e31b82003-02-18 22:55:36 +00006252 case TARGET_NR_gettimeofday:
6253 {
bellard31e31b82003-02-18 22:55:36 +00006254 struct timeval tv;
6255 ret = get_errno(gettimeofday(&tv, NULL));
6256 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006257 if (copy_to_user_timeval(arg1, &tv))
6258 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006259 }
6260 }
6261 break;
6262 case TARGET_NR_settimeofday:
6263 {
bellard31e31b82003-02-18 22:55:36 +00006264 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006265 if (copy_from_user_timeval(&tv, arg1))
6266 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006267 ret = get_errno(settimeofday(&tv, NULL));
6268 }
6269 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006270#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006271 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006272#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6273 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6274#else
bellardf2674e32003-07-09 12:26:09 +00006275 {
pbrook53a59602006-03-25 19:31:22 +00006276 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006277 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006278 long nsel;
6279
bellard579a97f2007-11-11 14:26:47 +00006280 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6281 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006282 nsel = tswapal(sel->n);
6283 inp = tswapal(sel->inp);
6284 outp = tswapal(sel->outp);
6285 exp = tswapal(sel->exp);
6286 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006287 unlock_user_struct(sel, arg1, 0);
6288 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006289 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006290#endif
bellardf2674e32003-07-09 12:26:09 +00006291 break;
bellard048f6b42005-11-26 18:47:20 +00006292#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006293#ifdef TARGET_NR_pselect6
6294 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006295 {
6296 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6297 fd_set rfds, wfds, efds;
6298 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6299 struct timespec ts, *ts_ptr;
6300
6301 /*
6302 * The 6th arg is actually two args smashed together,
6303 * so we cannot use the C library.
6304 */
6305 sigset_t set;
6306 struct {
6307 sigset_t *set;
6308 size_t size;
6309 } sig, *sig_ptr;
6310
6311 abi_ulong arg_sigset, arg_sigsize, *arg7;
6312 target_sigset_t *target_sigset;
6313
6314 n = arg1;
6315 rfd_addr = arg2;
6316 wfd_addr = arg3;
6317 efd_addr = arg4;
6318 ts_addr = arg5;
6319
6320 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6321 if (ret) {
6322 goto fail;
6323 }
6324 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6325 if (ret) {
6326 goto fail;
6327 }
6328 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6329 if (ret) {
6330 goto fail;
6331 }
6332
6333 /*
6334 * This takes a timespec, and not a timeval, so we cannot
6335 * use the do_select() helper ...
6336 */
6337 if (ts_addr) {
6338 if (target_to_host_timespec(&ts, ts_addr)) {
6339 goto efault;
6340 }
6341 ts_ptr = &ts;
6342 } else {
6343 ts_ptr = NULL;
6344 }
6345
6346 /* Extract the two packed args for the sigset */
6347 if (arg6) {
6348 sig_ptr = &sig;
6349 sig.size = _NSIG / 8;
6350
6351 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6352 if (!arg7) {
6353 goto efault;
6354 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006355 arg_sigset = tswapal(arg7[0]);
6356 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006357 unlock_user(arg7, arg6, 0);
6358
6359 if (arg_sigset) {
6360 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006361 if (arg_sigsize != sizeof(*target_sigset)) {
6362 /* Like the kernel, we enforce correct size sigsets */
6363 ret = -TARGET_EINVAL;
6364 goto fail;
6365 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006366 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6367 sizeof(*target_sigset), 1);
6368 if (!target_sigset) {
6369 goto efault;
6370 }
6371 target_to_host_sigset(&set, target_sigset);
6372 unlock_user(target_sigset, arg_sigset, 0);
6373 } else {
6374 sig.set = NULL;
6375 }
6376 } else {
6377 sig_ptr = NULL;
6378 }
6379
6380 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6381 ts_ptr, sig_ptr));
6382
6383 if (!is_error(ret)) {
6384 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6385 goto efault;
6386 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6387 goto efault;
6388 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6389 goto efault;
6390
6391 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6392 goto efault;
6393 }
6394 }
6395 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006396#endif
bellard31e31b82003-02-18 22:55:36 +00006397 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006398 {
6399 void *p2;
6400 p = lock_user_string(arg1);
6401 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006402 if (!p || !p2)
6403 ret = -TARGET_EFAULT;
6404 else
6405 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006406 unlock_user(p2, arg2, 0);
6407 unlock_user(p, arg1, 0);
6408 }
bellard31e31b82003-02-18 22:55:36 +00006409 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006410#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006411 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006412 {
bellard579a97f2007-11-11 14:26:47 +00006413 void *p2;
thsf0b62432007-09-24 09:25:40 +00006414 p = lock_user_string(arg1);
6415 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006416 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006417 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006418 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006419 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006420 unlock_user(p2, arg3, 0);
6421 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006422 }
6423 break;
6424#endif
bellardebc05482003-09-30 21:08:41 +00006425#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006426 case TARGET_NR_oldlstat:
6427 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006428#endif
bellard31e31b82003-02-18 22:55:36 +00006429 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006430 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006431 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006432 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006433 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006434 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006435 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006436 } else if (is_proc_myself((const char *)p, "exe")) {
6437 char real[PATH_MAX], *temp;
6438 temp = realpath(exec_path, real);
6439 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6440 snprintf((char *)p2, arg3, "%s", real);
6441 } else {
6442 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006443 }
pbrook53a59602006-03-25 19:31:22 +00006444 unlock_user(p2, arg2, ret);
6445 unlock_user(p, arg1, 0);
6446 }
bellard31e31b82003-02-18 22:55:36 +00006447 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006448#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006449 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006450 {
bellard579a97f2007-11-11 14:26:47 +00006451 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006452 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006453 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006454 if (!p || !p2) {
6455 ret = -TARGET_EFAULT;
6456 } else if (is_proc_myself((const char *)p, "exe")) {
6457 char real[PATH_MAX], *temp;
6458 temp = realpath(exec_path, real);
6459 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6460 snprintf((char *)p2, arg4, "%s", real);
6461 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006462 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006463 }
bellard579a97f2007-11-11 14:26:47 +00006464 unlock_user(p2, arg3, ret);
6465 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006466 }
6467 break;
6468#endif
thse5febef2007-04-01 18:31:35 +00006469#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006470 case TARGET_NR_uselib:
6471 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006472#endif
6473#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006474 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006475 if (!(p = lock_user_string(arg1)))
6476 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006477 ret = get_errno(swapon(p, arg2));
6478 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006479 break;
thse5febef2007-04-01 18:31:35 +00006480#endif
bellard31e31b82003-02-18 22:55:36 +00006481 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006482 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6483 /* arg4 must be ignored in all other cases */
6484 p = lock_user_string(arg4);
6485 if (!p) {
6486 goto efault;
6487 }
6488 ret = get_errno(reboot(arg1, arg2, arg3, p));
6489 unlock_user(p, arg4, 0);
6490 } else {
6491 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6492 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006493 break;
thse5febef2007-04-01 18:31:35 +00006494#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006495 case TARGET_NR_readdir:
6496 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006497#endif
6498#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006499 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006500#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6501 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006502 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6503 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006504 {
blueswir1992f48a2007-10-14 16:27:31 +00006505 abi_ulong *v;
6506 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006507 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6508 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006509 v1 = tswapal(v[0]);
6510 v2 = tswapal(v[1]);
6511 v3 = tswapal(v[2]);
6512 v4 = tswapal(v[3]);
6513 v5 = tswapal(v[4]);
6514 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006515 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006516 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006517 target_to_host_bitmask(v4, mmap_flags_tbl),
6518 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006519 }
bellard31e31b82003-02-18 22:55:36 +00006520#else
ths5fafdf22007-09-16 21:08:06 +00006521 ret = get_errno(target_mmap(arg1, arg2, arg3,
6522 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006523 arg5,
6524 arg6));
bellard31e31b82003-02-18 22:55:36 +00006525#endif
bellard6fb883e2003-07-09 17:12:39 +00006526 break;
thse5febef2007-04-01 18:31:35 +00006527#endif
bellarda315a142005-01-30 22:59:18 +00006528#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006529 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006530#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006531#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006532#endif
ths5fafdf22007-09-16 21:08:06 +00006533 ret = get_errno(target_mmap(arg1, arg2, arg3,
6534 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006535 arg5,
bellardc573ff62004-01-04 15:51:36 +00006536 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006537 break;
bellarda315a142005-01-30 22:59:18 +00006538#endif
bellard31e31b82003-02-18 22:55:36 +00006539 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006540 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006541 break;
bellard9de5e442003-03-23 16:49:39 +00006542 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006543 {
Andreas Färber0429a972013-08-26 18:14:44 +02006544 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006545 /* Special hack to detect libc making the stack executable. */
6546 if ((arg3 & PROT_GROWSDOWN)
6547 && arg1 >= ts->info->stack_limit
6548 && arg1 <= ts->info->start_stack) {
6549 arg3 &= ~PROT_GROWSDOWN;
6550 arg2 = arg2 + arg1 - ts->info->stack_limit;
6551 arg1 = ts->info->stack_limit;
6552 }
6553 }
bellard54936002003-05-13 00:25:15 +00006554 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006555 break;
thse5febef2007-04-01 18:31:35 +00006556#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006557 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006558 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006559 break;
thse5febef2007-04-01 18:31:35 +00006560#endif
pbrook53a59602006-03-25 19:31:22 +00006561 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006562#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006563 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006564 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006565 break;
thse5febef2007-04-01 18:31:35 +00006566#endif
6567#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006568 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006569 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006570 break;
thse5febef2007-04-01 18:31:35 +00006571#endif
6572#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006573 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006574 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006575 break;
thse5febef2007-04-01 18:31:35 +00006576#endif
6577#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006578 case TARGET_NR_mlockall:
6579 ret = get_errno(mlockall(arg1));
6580 break;
thse5febef2007-04-01 18:31:35 +00006581#endif
6582#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006583 case TARGET_NR_munlockall:
6584 ret = get_errno(munlockall());
6585 break;
thse5febef2007-04-01 18:31:35 +00006586#endif
bellard31e31b82003-02-18 22:55:36 +00006587 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006588 if (!(p = lock_user_string(arg1)))
6589 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006590 ret = get_errno(truncate(p, arg2));
6591 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006592 break;
6593 case TARGET_NR_ftruncate:
6594 ret = get_errno(ftruncate(arg1, arg2));
6595 break;
6596 case TARGET_NR_fchmod:
6597 ret = get_errno(fchmod(arg1, arg2));
6598 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006599#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006600 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006601 if (!(p = lock_user_string(arg2)))
6602 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006603 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006604 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006605 break;
6606#endif
bellard31e31b82003-02-18 22:55:36 +00006607 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006608 /* Note that negative values are valid for getpriority, so we must
6609 differentiate based on errno settings. */
6610 errno = 0;
6611 ret = getpriority(arg1, arg2);
6612 if (ret == -1 && errno != 0) {
6613 ret = -host_to_target_errno(errno);
6614 break;
6615 }
6616#ifdef TARGET_ALPHA
6617 /* Return value is the unbiased priority. Signal no error. */
6618 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6619#else
6620 /* Return value is a biased priority to avoid negative numbers. */
6621 ret = 20 - ret;
6622#endif
bellard31e31b82003-02-18 22:55:36 +00006623 break;
6624 case TARGET_NR_setpriority:
6625 ret = get_errno(setpriority(arg1, arg2, arg3));
6626 break;
bellardebc05482003-09-30 21:08:41 +00006627#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006628 case TARGET_NR_profil:
6629 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006630#endif
bellard31e31b82003-02-18 22:55:36 +00006631 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006632 if (!(p = lock_user_string(arg1)))
6633 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006634 ret = get_errno(statfs(path(p), &stfs));
6635 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006636 convert_statfs:
6637 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006638 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006639
bellard579a97f2007-11-11 14:26:47 +00006640 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6641 goto efault;
6642 __put_user(stfs.f_type, &target_stfs->f_type);
6643 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6644 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6645 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6646 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6647 __put_user(stfs.f_files, &target_stfs->f_files);
6648 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6649 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6650 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6651 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006652 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6653 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006654 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006655 }
6656 break;
6657 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006658 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006659 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006660#ifdef TARGET_NR_statfs64
6661 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006662 if (!(p = lock_user_string(arg1)))
6663 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006664 ret = get_errno(statfs(path(p), &stfs));
6665 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006666 convert_statfs64:
6667 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006668 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006669
bellard579a97f2007-11-11 14:26:47 +00006670 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6671 goto efault;
6672 __put_user(stfs.f_type, &target_stfs->f_type);
6673 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6674 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6675 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6676 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6677 __put_user(stfs.f_files, &target_stfs->f_files);
6678 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6679 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6680 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6681 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006682 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6683 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006684 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006685 }
6686 break;
6687 case TARGET_NR_fstatfs64:
6688 ret = get_errno(fstatfs(arg1, &stfs));
6689 goto convert_statfs64;
6690#endif
bellardebc05482003-09-30 21:08:41 +00006691#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006692 case TARGET_NR_ioperm:
6693 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006694#endif
thse5febef2007-04-01 18:31:35 +00006695#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006696 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006697 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006698 break;
thse5febef2007-04-01 18:31:35 +00006699#endif
bellard3532fa72006-06-24 15:06:03 +00006700#ifdef TARGET_NR_accept
6701 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006702 ret = do_accept4(arg1, arg2, arg3, 0);
6703 break;
6704#endif
6705#ifdef TARGET_NR_accept4
6706 case TARGET_NR_accept4:
6707#ifdef CONFIG_ACCEPT4
6708 ret = do_accept4(arg1, arg2, arg3, arg4);
6709#else
6710 goto unimplemented;
6711#endif
bellard3532fa72006-06-24 15:06:03 +00006712 break;
6713#endif
6714#ifdef TARGET_NR_bind
6715 case TARGET_NR_bind:
6716 ret = do_bind(arg1, arg2, arg3);
6717 break;
6718#endif
6719#ifdef TARGET_NR_connect
6720 case TARGET_NR_connect:
6721 ret = do_connect(arg1, arg2, arg3);
6722 break;
6723#endif
6724#ifdef TARGET_NR_getpeername
6725 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006726 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006727 break;
6728#endif
6729#ifdef TARGET_NR_getsockname
6730 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006731 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006732 break;
6733#endif
6734#ifdef TARGET_NR_getsockopt
6735 case TARGET_NR_getsockopt:
6736 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6737 break;
6738#endif
6739#ifdef TARGET_NR_listen
6740 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006741 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006742 break;
6743#endif
6744#ifdef TARGET_NR_recv
6745 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006746 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006747 break;
6748#endif
6749#ifdef TARGET_NR_recvfrom
6750 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006751 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006752 break;
6753#endif
6754#ifdef TARGET_NR_recvmsg
6755 case TARGET_NR_recvmsg:
6756 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6757 break;
6758#endif
6759#ifdef TARGET_NR_send
6760 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006761 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006762 break;
6763#endif
6764#ifdef TARGET_NR_sendmsg
6765 case TARGET_NR_sendmsg:
6766 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6767 break;
6768#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006769#ifdef TARGET_NR_sendmmsg
6770 case TARGET_NR_sendmmsg:
6771 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6772 break;
6773 case TARGET_NR_recvmmsg:
6774 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6775 break;
6776#endif
bellard3532fa72006-06-24 15:06:03 +00006777#ifdef TARGET_NR_sendto
6778 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006779 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006780 break;
6781#endif
6782#ifdef TARGET_NR_shutdown
6783 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006784 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006785 break;
6786#endif
6787#ifdef TARGET_NR_socket
6788 case TARGET_NR_socket:
6789 ret = do_socket(arg1, arg2, arg3);
6790 break;
6791#endif
6792#ifdef TARGET_NR_socketpair
6793 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006794 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006795 break;
6796#endif
6797#ifdef TARGET_NR_setsockopt
6798 case TARGET_NR_setsockopt:
6799 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6800 break;
6801#endif
ths7494b0f2007-02-11 18:26:53 +00006802
bellard31e31b82003-02-18 22:55:36 +00006803 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006804 if (!(p = lock_user_string(arg2)))
6805 goto efault;
thse5574482007-02-11 20:03:13 +00006806 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6807 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006808 break;
6809
bellard31e31b82003-02-18 22:55:36 +00006810 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006811 {
bellard66fb9762003-03-23 01:06:05 +00006812 struct itimerval value, ovalue, *pvalue;
6813
pbrook53a59602006-03-25 19:31:22 +00006814 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006815 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006816 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6817 || copy_from_user_timeval(&pvalue->it_value,
6818 arg2 + sizeof(struct target_timeval)))
6819 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006820 } else {
6821 pvalue = NULL;
6822 }
6823 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006824 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006825 if (copy_to_user_timeval(arg3,
6826 &ovalue.it_interval)
6827 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6828 &ovalue.it_value))
6829 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006830 }
6831 }
6832 break;
bellard31e31b82003-02-18 22:55:36 +00006833 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006834 {
bellard66fb9762003-03-23 01:06:05 +00006835 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006836
bellard66fb9762003-03-23 01:06:05 +00006837 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006838 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006839 if (copy_to_user_timeval(arg2,
6840 &value.it_interval)
6841 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6842 &value.it_value))
6843 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006844 }
6845 }
6846 break;
bellard31e31b82003-02-18 22:55:36 +00006847 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006848 if (!(p = lock_user_string(arg1)))
6849 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006850 ret = get_errno(stat(path(p), &st));
6851 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006852 goto do_stat;
6853 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006854 if (!(p = lock_user_string(arg1)))
6855 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006856 ret = get_errno(lstat(path(p), &st));
6857 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006858 goto do_stat;
6859 case TARGET_NR_fstat:
6860 {
6861 ret = get_errno(fstat(arg1, &st));
6862 do_stat:
6863 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006864 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006865
bellard579a97f2007-11-11 14:26:47 +00006866 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6867 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006868 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006869 __put_user(st.st_dev, &target_st->st_dev);
6870 __put_user(st.st_ino, &target_st->st_ino);
6871 __put_user(st.st_mode, &target_st->st_mode);
6872 __put_user(st.st_uid, &target_st->st_uid);
6873 __put_user(st.st_gid, &target_st->st_gid);
6874 __put_user(st.st_nlink, &target_st->st_nlink);
6875 __put_user(st.st_rdev, &target_st->st_rdev);
6876 __put_user(st.st_size, &target_st->st_size);
6877 __put_user(st.st_blksize, &target_st->st_blksize);
6878 __put_user(st.st_blocks, &target_st->st_blocks);
6879 __put_user(st.st_atime, &target_st->target_st_atime);
6880 __put_user(st.st_mtime, &target_st->target_st_mtime);
6881 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006882 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006883 }
6884 }
6885 break;
bellardebc05482003-09-30 21:08:41 +00006886#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006887 case TARGET_NR_olduname:
6888 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006889#endif
6890#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006891 case TARGET_NR_iopl:
6892 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006893#endif
bellard31e31b82003-02-18 22:55:36 +00006894 case TARGET_NR_vhangup:
6895 ret = get_errno(vhangup());
6896 break;
bellardebc05482003-09-30 21:08:41 +00006897#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006898 case TARGET_NR_idle:
6899 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006900#endif
bellard42ad6ae2005-01-03 22:48:11 +00006901#ifdef TARGET_NR_syscall
6902 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006903 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6904 arg6, arg7, arg8, 0);
6905 break;
bellard42ad6ae2005-01-03 22:48:11 +00006906#endif
bellard31e31b82003-02-18 22:55:36 +00006907 case TARGET_NR_wait4:
6908 {
6909 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006910 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006911 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006912 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02006913 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00006914 if (target_rusage)
6915 rusage_ptr = &rusage;
6916 else
6917 rusage_ptr = NULL;
6918 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6919 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006920 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006921 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006922 if (put_user_s32(status, status_ptr))
6923 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006924 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02006925 if (target_rusage) {
6926 rusage_err = host_to_target_rusage(target_rusage, &rusage);
6927 if (rusage_err) {
6928 ret = rusage_err;
6929 }
6930 }
bellard31e31b82003-02-18 22:55:36 +00006931 }
6932 }
6933 break;
thse5febef2007-04-01 18:31:35 +00006934#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006935 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006936 if (!(p = lock_user_string(arg1)))
6937 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006938 ret = get_errno(swapoff(p));
6939 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006940 break;
thse5febef2007-04-01 18:31:35 +00006941#endif
bellard31e31b82003-02-18 22:55:36 +00006942 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006943 {
pbrook53a59602006-03-25 19:31:22 +00006944 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006945 struct sysinfo value;
6946 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006947 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006948 {
bellard579a97f2007-11-11 14:26:47 +00006949 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6950 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006951 __put_user(value.uptime, &target_value->uptime);
6952 __put_user(value.loads[0], &target_value->loads[0]);
6953 __put_user(value.loads[1], &target_value->loads[1]);
6954 __put_user(value.loads[2], &target_value->loads[2]);
6955 __put_user(value.totalram, &target_value->totalram);
6956 __put_user(value.freeram, &target_value->freeram);
6957 __put_user(value.sharedram, &target_value->sharedram);
6958 __put_user(value.bufferram, &target_value->bufferram);
6959 __put_user(value.totalswap, &target_value->totalswap);
6960 __put_user(value.freeswap, &target_value->freeswap);
6961 __put_user(value.procs, &target_value->procs);
6962 __put_user(value.totalhigh, &target_value->totalhigh);
6963 __put_user(value.freehigh, &target_value->freehigh);
6964 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006965 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006966 }
6967 }
6968 break;
thse5febef2007-04-01 18:31:35 +00006969#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006970 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006971 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6972 break;
thse5febef2007-04-01 18:31:35 +00006973#endif
aurel32e5289082009-04-18 16:16:12 +00006974#ifdef TARGET_NR_semget
6975 case TARGET_NR_semget:
6976 ret = get_errno(semget(arg1, arg2, arg3));
6977 break;
6978#endif
6979#ifdef TARGET_NR_semop
6980 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00006981 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00006982 break;
6983#endif
6984#ifdef TARGET_NR_semctl
6985 case TARGET_NR_semctl:
6986 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6987 break;
6988#endif
aurel32eeb438c2008-10-13 21:08:55 +00006989#ifdef TARGET_NR_msgctl
6990 case TARGET_NR_msgctl:
6991 ret = do_msgctl(arg1, arg2, arg3);
6992 break;
6993#endif
6994#ifdef TARGET_NR_msgget
6995 case TARGET_NR_msgget:
6996 ret = get_errno(msgget(arg1, arg2));
6997 break;
6998#endif
6999#ifdef TARGET_NR_msgrcv
7000 case TARGET_NR_msgrcv:
7001 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7002 break;
7003#endif
7004#ifdef TARGET_NR_msgsnd
7005 case TARGET_NR_msgsnd:
7006 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7007 break;
7008#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007009#ifdef TARGET_NR_shmget
7010 case TARGET_NR_shmget:
7011 ret = get_errno(shmget(arg1, arg2, arg3));
7012 break;
7013#endif
7014#ifdef TARGET_NR_shmctl
7015 case TARGET_NR_shmctl:
7016 ret = do_shmctl(arg1, arg2, arg3);
7017 break;
7018#endif
7019#ifdef TARGET_NR_shmat
7020 case TARGET_NR_shmat:
7021 ret = do_shmat(arg1, arg2, arg3);
7022 break;
7023#endif
7024#ifdef TARGET_NR_shmdt
7025 case TARGET_NR_shmdt:
7026 ret = do_shmdt(arg1);
7027 break;
7028#endif
bellard31e31b82003-02-18 22:55:36 +00007029 case TARGET_NR_fsync:
7030 ret = get_errno(fsync(arg1));
7031 break;
bellard31e31b82003-02-18 22:55:36 +00007032 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007033 /* Linux manages to have three different orderings for its
7034 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7035 * match the kernel's CONFIG_CLONE_* settings.
7036 * Microblaze is further special in that it uses a sixth
7037 * implicit argument to clone for the TLS pointer.
7038 */
7039#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007040 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007041#elif defined(TARGET_CLONE_BACKWARDS)
7042 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7043#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007044 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007045#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007046 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007047#endif
bellard1b6b0292003-03-22 17:31:38 +00007048 break;
bellardec86b0f2003-04-11 00:15:04 +00007049#ifdef __NR_exit_group
7050 /* new thread calls */
7051 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007052#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007053 _mcleanup();
7054#endif
bellarde9009672005-04-26 20:42:36 +00007055 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007056 ret = get_errno(exit_group(arg1));
7057 break;
7058#endif
bellard31e31b82003-02-18 22:55:36 +00007059 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007060 if (!(p = lock_user_string(arg1)))
7061 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007062 ret = get_errno(setdomainname(p, arg2));
7063 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007064 break;
7065 case TARGET_NR_uname:
7066 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007067 {
7068 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007069
bellard579a97f2007-11-11 14:26:47 +00007070 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7071 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007072 ret = get_errno(sys_uname(buf));
7073 if (!is_error(ret)) {
7074 /* Overrite the native machine name with whatever is being
7075 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007076 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007077 /* Allow the user to override the reported release. */
7078 if (qemu_uname_release && *qemu_uname_release)
7079 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007080 }
pbrook53a59602006-03-25 19:31:22 +00007081 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007082 }
bellard31e31b82003-02-18 22:55:36 +00007083 break;
bellard6dbad632003-03-16 18:05:05 +00007084#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007085 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007086 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007087 break;
j_mayer84409dd2007-04-06 08:56:50 +00007088#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007089 case TARGET_NR_vm86old:
7090 goto unimplemented;
7091 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007092 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007093 break;
7094#endif
j_mayer84409dd2007-04-06 08:56:50 +00007095#endif
bellard31e31b82003-02-18 22:55:36 +00007096 case TARGET_NR_adjtimex:
7097 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007098#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007099 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007100#endif
bellard31e31b82003-02-18 22:55:36 +00007101 case TARGET_NR_init_module:
7102 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007103#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007104 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007105#endif
bellard31e31b82003-02-18 22:55:36 +00007106 goto unimplemented;
7107 case TARGET_NR_quotactl:
7108 goto unimplemented;
7109 case TARGET_NR_getpgid:
7110 ret = get_errno(getpgid(arg1));
7111 break;
7112 case TARGET_NR_fchdir:
7113 ret = get_errno(fchdir(arg1));
7114 break;
j_mayer84409dd2007-04-06 08:56:50 +00007115#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007116 case TARGET_NR_bdflush:
7117 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007118#endif
thse5febef2007-04-01 18:31:35 +00007119#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007120 case TARGET_NR_sysfs:
7121 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007122#endif
bellard31e31b82003-02-18 22:55:36 +00007123 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007124 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007125 break;
thse5febef2007-04-01 18:31:35 +00007126#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007127 case TARGET_NR_afs_syscall:
7128 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007129#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007130#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007131 case TARGET_NR__llseek:
7132 {
7133 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007134#if !defined(__NR_llseek)
7135 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7136 if (res == -1) {
7137 ret = get_errno(res);
7138 } else {
7139 ret = 0;
7140 }
7141#else
bellard31e31b82003-02-18 22:55:36 +00007142 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007143#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007144 if ((ret == 0) && put_user_s64(res, arg4)) {
7145 goto efault;
7146 }
bellard31e31b82003-02-18 22:55:36 +00007147 }
7148 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007149#endif
bellard31e31b82003-02-18 22:55:36 +00007150 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007151#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007152#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007153 {
pbrook53a59602006-03-25 19:31:22 +00007154 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007155 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007156 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007157
7158 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007159 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007160 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007161 goto fail;
7162 }
ths3b46e622007-09-17 08:09:54 +00007163
bellard4add45b2003-06-05 01:52:59 +00007164 ret = get_errno(sys_getdents(arg1, dirp, count));
7165 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007166 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007167 struct target_dirent *tde;
7168 int len = ret;
7169 int reclen, treclen;
7170 int count1, tnamelen;
7171
7172 count1 = 0;
7173 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007174 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7175 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007176 tde = target_dirp;
7177 while (len > 0) {
7178 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007179 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7180 assert(tnamelen >= 0);
7181 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7182 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007183 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007184 tde->d_ino = tswapal(de->d_ino);
7185 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007186 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007187 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007188 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007189 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007190 count1 += treclen;
7191 }
7192 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007193 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007194 }
7195 free(dirp);
7196 }
7197#else
bellard31e31b82003-02-18 22:55:36 +00007198 {
aurel326556a832008-10-13 21:08:17 +00007199 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007200 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007201
bellard579a97f2007-11-11 14:26:47 +00007202 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7203 goto efault;
bellard72f03902003-02-18 23:33:18 +00007204 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007205 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007206 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007207 int len = ret;
7208 int reclen;
7209 de = dirp;
7210 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007211 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007212 if (reclen > len)
7213 break;
bellard8083a3e2003-03-24 23:12:16 +00007214 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007215 tswapls(&de->d_ino);
7216 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007217 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007218 len -= reclen;
7219 }
7220 }
pbrook53a59602006-03-25 19:31:22 +00007221 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007222 }
bellard4add45b2003-06-05 01:52:59 +00007223#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007224#else
7225 /* Implement getdents in terms of getdents64 */
7226 {
7227 struct linux_dirent64 *dirp;
7228 abi_long count = arg3;
7229
7230 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7231 if (!dirp) {
7232 goto efault;
7233 }
7234 ret = get_errno(sys_getdents64(arg1, dirp, count));
7235 if (!is_error(ret)) {
7236 /* Convert the dirent64 structs to target dirent. We do this
7237 * in-place, since we can guarantee that a target_dirent is no
7238 * larger than a dirent64; however this means we have to be
7239 * careful to read everything before writing in the new format.
7240 */
7241 struct linux_dirent64 *de;
7242 struct target_dirent *tde;
7243 int len = ret;
7244 int tlen = 0;
7245
7246 de = dirp;
7247 tde = (struct target_dirent *)dirp;
7248 while (len > 0) {
7249 int namelen, treclen;
7250 int reclen = de->d_reclen;
7251 uint64_t ino = de->d_ino;
7252 int64_t off = de->d_off;
7253 uint8_t type = de->d_type;
7254
7255 namelen = strlen(de->d_name);
7256 treclen = offsetof(struct target_dirent, d_name)
7257 + namelen + 2;
7258 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7259
7260 memmove(tde->d_name, de->d_name, namelen + 1);
7261 tde->d_ino = tswapal(ino);
7262 tde->d_off = tswapal(off);
7263 tde->d_reclen = tswap16(treclen);
7264 /* The target_dirent type is in what was formerly a padding
7265 * byte at the end of the structure:
7266 */
7267 *(((char *)tde) + treclen - 1) = type;
7268
7269 de = (struct linux_dirent64 *)((char *)de + reclen);
7270 tde = (struct target_dirent *)((char *)tde + treclen);
7271 len -= reclen;
7272 tlen += treclen;
7273 }
7274 ret = tlen;
7275 }
7276 unlock_user(dirp, arg2, ret);
7277 }
7278#endif
bellard31e31b82003-02-18 22:55:36 +00007279 break;
ths3ae43202007-09-16 21:39:48 +00007280#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007281 case TARGET_NR_getdents64:
7282 {
aurel326556a832008-10-13 21:08:17 +00007283 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007284 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007285 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7286 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007287 ret = get_errno(sys_getdents64(arg1, dirp, count));
7288 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007289 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007290 int len = ret;
7291 int reclen;
7292 de = dirp;
7293 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007294 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007295 if (reclen > len)
7296 break;
bellard8083a3e2003-03-24 23:12:16 +00007297 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007298 tswap64s((uint64_t *)&de->d_ino);
7299 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007300 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007301 len -= reclen;
7302 }
7303 }
pbrook53a59602006-03-25 19:31:22 +00007304 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007305 }
7306 break;
bellarda541f292004-04-12 20:39:29 +00007307#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007308#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007309 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007310 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007311 break;
thse5febef2007-04-01 18:31:35 +00007312#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007313#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7314# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007315 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007316# endif
7317# ifdef TARGET_NR_ppoll
7318 case TARGET_NR_ppoll:
7319# endif
bellard9de5e442003-03-23 16:49:39 +00007320 {
pbrook53a59602006-03-25 19:31:22 +00007321 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007322 unsigned int nfds = arg2;
7323 int timeout = arg3;
7324 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007325 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007326
bellard579a97f2007-11-11 14:26:47 +00007327 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7328 if (!target_pfd)
7329 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007330
bellard9de5e442003-03-23 16:49:39 +00007331 pfd = alloca(sizeof(struct pollfd) * nfds);
7332 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007333 pfd[i].fd = tswap32(target_pfd[i].fd);
7334 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007335 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007336
7337# ifdef TARGET_NR_ppoll
7338 if (num == TARGET_NR_ppoll) {
7339 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7340 target_sigset_t *target_set;
7341 sigset_t _set, *set = &_set;
7342
7343 if (arg3) {
7344 if (target_to_host_timespec(timeout_ts, arg3)) {
7345 unlock_user(target_pfd, arg1, 0);
7346 goto efault;
7347 }
7348 } else {
7349 timeout_ts = NULL;
7350 }
7351
7352 if (arg4) {
7353 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7354 if (!target_set) {
7355 unlock_user(target_pfd, arg1, 0);
7356 goto efault;
7357 }
7358 target_to_host_sigset(set, target_set);
7359 } else {
7360 set = NULL;
7361 }
7362
7363 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7364
7365 if (!is_error(ret) && arg3) {
7366 host_to_target_timespec(arg3, timeout_ts);
7367 }
7368 if (arg4) {
7369 unlock_user(target_set, arg4, 0);
7370 }
7371 } else
7372# endif
7373 ret = get_errno(poll(pfd, nfds, timeout));
7374
bellard9de5e442003-03-23 16:49:39 +00007375 if (!is_error(ret)) {
7376 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007377 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007378 }
7379 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007380 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007381 }
7382 break;
thse5febef2007-04-01 18:31:35 +00007383#endif
bellard31e31b82003-02-18 22:55:36 +00007384 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007385 /* NOTE: the flock constant seems to be the same for every
7386 Linux platform */
7387 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007388 break;
7389 case TARGET_NR_readv:
7390 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007391 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7392 if (vec != NULL) {
7393 ret = get_errno(readv(arg1, vec, arg3));
7394 unlock_iovec(vec, arg2, arg3, 1);
7395 } else {
7396 ret = -host_to_target_errno(errno);
7397 }
bellard31e31b82003-02-18 22:55:36 +00007398 }
7399 break;
7400 case TARGET_NR_writev:
7401 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007402 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7403 if (vec != NULL) {
7404 ret = get_errno(writev(arg1, vec, arg3));
7405 unlock_iovec(vec, arg2, arg3, 0);
7406 } else {
7407 ret = -host_to_target_errno(errno);
7408 }
bellard31e31b82003-02-18 22:55:36 +00007409 }
7410 break;
7411 case TARGET_NR_getsid:
7412 ret = get_errno(getsid(arg1));
7413 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007414#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007415 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007416 ret = get_errno(fdatasync(arg1));
7417 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007418#endif
bellard31e31b82003-02-18 22:55:36 +00007419 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007420 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007421 return value. */
ths0da46a62007-10-20 20:23:07 +00007422 ret = -TARGET_ENOTDIR;
7423 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007424 case TARGET_NR_sched_getaffinity:
7425 {
7426 unsigned int mask_size;
7427 unsigned long *mask;
7428
7429 /*
7430 * sched_getaffinity needs multiples of ulong, so need to take
7431 * care of mismatches between target ulong and host ulong sizes.
7432 */
7433 if (arg2 & (sizeof(abi_ulong) - 1)) {
7434 ret = -TARGET_EINVAL;
7435 break;
7436 }
7437 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7438
7439 mask = alloca(mask_size);
7440 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7441
7442 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007443 if (ret > arg2) {
7444 /* More data returned than the caller's buffer will fit.
7445 * This only happens if sizeof(abi_long) < sizeof(long)
7446 * and the caller passed us a buffer holding an odd number
7447 * of abi_longs. If the host kernel is actually using the
7448 * extra 4 bytes then fail EINVAL; otherwise we can just
7449 * ignore them and only copy the interesting part.
7450 */
7451 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7452 if (numcpus > arg2 * 8) {
7453 ret = -TARGET_EINVAL;
7454 break;
7455 }
7456 ret = arg2;
7457 }
7458
Mike McCormackcd18f052011-04-18 14:43:36 +09007459 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007460 goto efault;
7461 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007462 }
7463 }
7464 break;
7465 case TARGET_NR_sched_setaffinity:
7466 {
7467 unsigned int mask_size;
7468 unsigned long *mask;
7469
7470 /*
7471 * sched_setaffinity needs multiples of ulong, so need to take
7472 * care of mismatches between target ulong and host ulong sizes.
7473 */
7474 if (arg2 & (sizeof(abi_ulong) - 1)) {
7475 ret = -TARGET_EINVAL;
7476 break;
7477 }
7478 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7479
7480 mask = alloca(mask_size);
7481 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7482 goto efault;
7483 }
7484 memcpy(mask, p, arg2);
7485 unlock_user_struct(p, arg2, 0);
7486
7487 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7488 }
7489 break;
bellard31e31b82003-02-18 22:55:36 +00007490 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007491 {
pbrook53a59602006-03-25 19:31:22 +00007492 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007493 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007494
bellard579a97f2007-11-11 14:26:47 +00007495 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7496 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007497 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007498 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007499 ret = get_errno(sched_setparam(arg1, &schp));
7500 }
7501 break;
bellard31e31b82003-02-18 22:55:36 +00007502 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007503 {
pbrook53a59602006-03-25 19:31:22 +00007504 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007505 struct sched_param schp;
7506 ret = get_errno(sched_getparam(arg1, &schp));
7507 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007508 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7509 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007510 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007511 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007512 }
7513 }
7514 break;
bellard31e31b82003-02-18 22:55:36 +00007515 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007516 {
pbrook53a59602006-03-25 19:31:22 +00007517 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007518 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007519 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7520 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007521 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007522 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007523 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7524 }
7525 break;
bellard31e31b82003-02-18 22:55:36 +00007526 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007527 ret = get_errno(sched_getscheduler(arg1));
7528 break;
bellard31e31b82003-02-18 22:55:36 +00007529 case TARGET_NR_sched_yield:
7530 ret = get_errno(sched_yield());
7531 break;
7532 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007533 ret = get_errno(sched_get_priority_max(arg1));
7534 break;
bellard31e31b82003-02-18 22:55:36 +00007535 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007536 ret = get_errno(sched_get_priority_min(arg1));
7537 break;
bellard31e31b82003-02-18 22:55:36 +00007538 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007539 {
bellard5cd43932003-03-29 16:54:36 +00007540 struct timespec ts;
7541 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7542 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007543 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007544 }
7545 }
7546 break;
bellard31e31b82003-02-18 22:55:36 +00007547 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007548 {
bellard1b6b0292003-03-22 17:31:38 +00007549 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007550 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007551 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007552 if (is_error(ret) && arg2) {
7553 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007554 }
7555 }
7556 break;
thse5febef2007-04-01 18:31:35 +00007557#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007558 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007559 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007560#endif
7561#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007562 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007563 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007564#endif
bellard31e31b82003-02-18 22:55:36 +00007565 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007566 switch (arg1) {
7567 case PR_GET_PDEATHSIG:
7568 {
7569 int deathsig;
7570 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7571 if (!is_error(ret) && arg2
7572 && put_user_ual(deathsig, arg2)) {
7573 goto efault;
thse5574482007-02-11 20:03:13 +00007574 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007575 break;
7576 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007577#ifdef PR_GET_NAME
7578 case PR_GET_NAME:
7579 {
7580 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7581 if (!name) {
7582 goto efault;
7583 }
7584 ret = get_errno(prctl(arg1, (unsigned long)name,
7585 arg3, arg4, arg5));
7586 unlock_user(name, arg2, 16);
7587 break;
7588 }
7589 case PR_SET_NAME:
7590 {
7591 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7592 if (!name) {
7593 goto efault;
7594 }
7595 ret = get_errno(prctl(arg1, (unsigned long)name,
7596 arg3, arg4, arg5));
7597 unlock_user(name, arg2, 0);
7598 break;
7599 }
7600#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007601 default:
7602 /* Most prctl options have no pointer arguments */
7603 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7604 break;
7605 }
ths39b9aae2007-02-11 18:36:44 +00007606 break;
bellardd2fd1af2007-11-14 18:08:56 +00007607#ifdef TARGET_NR_arch_prctl
7608 case TARGET_NR_arch_prctl:
7609#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7610 ret = do_arch_prctl(cpu_env, arg1, arg2);
7611 break;
7612#else
7613 goto unimplemented;
7614#endif
7615#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007616#ifdef TARGET_NR_pread64
7617 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007618 if (regpairs_aligned(cpu_env)) {
7619 arg4 = arg5;
7620 arg5 = arg6;
7621 }
aurel32f2c7ba12008-03-28 22:32:06 +00007622 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7623 goto efault;
7624 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7625 unlock_user(p, arg2, ret);
7626 break;
7627 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007628 if (regpairs_aligned(cpu_env)) {
7629 arg4 = arg5;
7630 arg5 = arg6;
7631 }
aurel32f2c7ba12008-03-28 22:32:06 +00007632 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7633 goto efault;
7634 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7635 unlock_user(p, arg2, 0);
7636 break;
7637#endif
bellard31e31b82003-02-18 22:55:36 +00007638 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007639 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7640 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007641 ret = get_errno(sys_getcwd1(p, arg2));
7642 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007643 break;
7644 case TARGET_NR_capget:
7645 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007646 {
7647 struct target_user_cap_header *target_header;
7648 struct target_user_cap_data *target_data = NULL;
7649 struct __user_cap_header_struct header;
7650 struct __user_cap_data_struct data[2];
7651 struct __user_cap_data_struct *dataptr = NULL;
7652 int i, target_datalen;
7653 int data_items = 1;
7654
7655 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7656 goto efault;
7657 }
7658 header.version = tswap32(target_header->version);
7659 header.pid = tswap32(target_header->pid);
7660
Peter Maydellec864872014-03-19 16:07:30 +00007661 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007662 /* Version 2 and up takes pointer to two user_data structs */
7663 data_items = 2;
7664 }
7665
7666 target_datalen = sizeof(*target_data) * data_items;
7667
7668 if (arg2) {
7669 if (num == TARGET_NR_capget) {
7670 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7671 } else {
7672 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7673 }
7674 if (!target_data) {
7675 unlock_user_struct(target_header, arg1, 0);
7676 goto efault;
7677 }
7678
7679 if (num == TARGET_NR_capset) {
7680 for (i = 0; i < data_items; i++) {
7681 data[i].effective = tswap32(target_data[i].effective);
7682 data[i].permitted = tswap32(target_data[i].permitted);
7683 data[i].inheritable = tswap32(target_data[i].inheritable);
7684 }
7685 }
7686
7687 dataptr = data;
7688 }
7689
7690 if (num == TARGET_NR_capget) {
7691 ret = get_errno(capget(&header, dataptr));
7692 } else {
7693 ret = get_errno(capset(&header, dataptr));
7694 }
7695
7696 /* The kernel always updates version for both capget and capset */
7697 target_header->version = tswap32(header.version);
7698 unlock_user_struct(target_header, arg1, 1);
7699
7700 if (arg2) {
7701 if (num == TARGET_NR_capget) {
7702 for (i = 0; i < data_items; i++) {
7703 target_data[i].effective = tswap32(data[i].effective);
7704 target_data[i].permitted = tswap32(data[i].permitted);
7705 target_data[i].inheritable = tswap32(data[i].inheritable);
7706 }
7707 unlock_user(target_data, arg2, target_datalen);
7708 } else {
7709 unlock_user(target_data, arg2, 0);
7710 }
7711 }
7712 break;
7713 }
bellard31e31b82003-02-18 22:55:36 +00007714 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007715#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007716 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007717 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007718 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007719 break;
7720#else
bellard5cd43932003-03-29 16:54:36 +00007721 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007722#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007723
7724#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007725 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007726 {
7727 off_t *offp = NULL;
7728 off_t off;
7729 if (arg3) {
7730 ret = get_user_sal(off, arg3);
7731 if (is_error(ret)) {
7732 break;
7733 }
7734 offp = &off;
7735 }
7736 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7737 if (!is_error(ret) && arg3) {
7738 abi_long ret2 = put_user_sal(off, arg3);
7739 if (is_error(ret2)) {
7740 ret = ret2;
7741 }
7742 }
7743 break;
7744 }
7745#ifdef TARGET_NR_sendfile64
7746 case TARGET_NR_sendfile64:
7747 {
7748 off_t *offp = NULL;
7749 off_t off;
7750 if (arg3) {
7751 ret = get_user_s64(off, arg3);
7752 if (is_error(ret)) {
7753 break;
7754 }
7755 offp = &off;
7756 }
7757 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7758 if (!is_error(ret) && arg3) {
7759 abi_long ret2 = put_user_s64(off, arg3);
7760 if (is_error(ret2)) {
7761 ret = ret2;
7762 }
7763 }
7764 break;
7765 }
7766#endif
7767#else
7768 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007769#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007770 case TARGET_NR_sendfile64:
7771#endif
bellard5cd43932003-03-29 16:54:36 +00007772 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007773#endif
7774
bellardebc05482003-09-30 21:08:41 +00007775#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007776 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007777 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007778#endif
7779#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007780 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007781 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007782#endif
bellard048f6b42005-11-26 18:47:20 +00007783#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007784 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007785 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7786 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007787 break;
bellard048f6b42005-11-26 18:47:20 +00007788#endif
bellardebc05482003-09-30 21:08:41 +00007789#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007790 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007791 {
7792 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007793 int resource = target_to_host_resource(arg1);
7794 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007795 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007796 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007797 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7798 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007799 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7800 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007801 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007802 }
7803 break;
7804 }
bellardebc05482003-09-30 21:08:41 +00007805#endif
bellarda315a142005-01-30 22:59:18 +00007806#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007807 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007808 if (!(p = lock_user_string(arg1)))
7809 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007810 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7811 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007812 break;
bellarda315a142005-01-30 22:59:18 +00007813#endif
7814#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007815 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007816 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007817 break;
bellarda315a142005-01-30 22:59:18 +00007818#endif
7819#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007820 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007821 if (!(p = lock_user_string(arg1)))
7822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007823 ret = get_errno(stat(path(p), &st));
7824 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007825 if (!is_error(ret))
7826 ret = host_to_target_stat64(cpu_env, arg2, &st);
7827 break;
bellarda315a142005-01-30 22:59:18 +00007828#endif
7829#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007830 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007831 if (!(p = lock_user_string(arg1)))
7832 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007833 ret = get_errno(lstat(path(p), &st));
7834 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007835 if (!is_error(ret))
7836 ret = host_to_target_stat64(cpu_env, arg2, &st);
7837 break;
bellarda315a142005-01-30 22:59:18 +00007838#endif
7839#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007840 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007841 ret = get_errno(fstat(arg1, &st));
7842 if (!is_error(ret))
7843 ret = host_to_target_stat64(cpu_env, arg2, &st);
7844 break;
bellardec86b0f2003-04-11 00:15:04 +00007845#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007846#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007847#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007848 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007849#endif
7850#ifdef TARGET_NR_newfstatat
7851 case TARGET_NR_newfstatat:
7852#endif
balrog6a24a772008-09-20 02:23:36 +00007853 if (!(p = lock_user_string(arg2)))
7854 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007855 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007856 if (!is_error(ret))
7857 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007858 break;
bellarda315a142005-01-30 22:59:18 +00007859#endif
bellard67867302003-11-23 17:05:30 +00007860 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007861 if (!(p = lock_user_string(arg1)))
7862 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007863 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7864 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007865 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007866#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007867 case TARGET_NR_getuid:
7868 ret = get_errno(high2lowuid(getuid()));
7869 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007870#endif
7871#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007872 case TARGET_NR_getgid:
7873 ret = get_errno(high2lowgid(getgid()));
7874 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007875#endif
7876#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007877 case TARGET_NR_geteuid:
7878 ret = get_errno(high2lowuid(geteuid()));
7879 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007880#endif
7881#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007882 case TARGET_NR_getegid:
7883 ret = get_errno(high2lowgid(getegid()));
7884 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007885#endif
bellard67867302003-11-23 17:05:30 +00007886 case TARGET_NR_setreuid:
7887 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7888 break;
7889 case TARGET_NR_setregid:
7890 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7891 break;
7892 case TARGET_NR_getgroups:
7893 {
7894 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007895 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007896 gid_t *grouplist;
7897 int i;
7898
7899 grouplist = alloca(gidsetsize * sizeof(gid_t));
7900 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007901 if (gidsetsize == 0)
7902 break;
bellard67867302003-11-23 17:05:30 +00007903 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007904 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007905 if (!target_grouplist)
7906 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007907 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007908 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007909 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007910 }
7911 }
7912 break;
7913 case TARGET_NR_setgroups:
7914 {
7915 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007916 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007917 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007918 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007919 if (gidsetsize) {
7920 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007921 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007922 if (!target_grouplist) {
7923 ret = -TARGET_EFAULT;
7924 goto fail;
7925 }
7926 for (i = 0; i < gidsetsize; i++) {
7927 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7928 }
7929 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007930 }
bellard67867302003-11-23 17:05:30 +00007931 ret = get_errno(setgroups(gidsetsize, grouplist));
7932 }
7933 break;
7934 case TARGET_NR_fchown:
7935 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7936 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007937#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007938 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007939 if (!(p = lock_user_string(arg2)))
7940 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007941 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7942 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007943 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007944 break;
7945#endif
bellard67867302003-11-23 17:05:30 +00007946#ifdef TARGET_NR_setresuid
7947 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007948 ret = get_errno(setresuid(low2highuid(arg1),
7949 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007950 low2highuid(arg3)));
7951 break;
7952#endif
7953#ifdef TARGET_NR_getresuid
7954 case TARGET_NR_getresuid:
7955 {
pbrook53a59602006-03-25 19:31:22 +00007956 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007957 ret = get_errno(getresuid(&ruid, &euid, &suid));
7958 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007959 if (put_user_id(high2lowuid(ruid), arg1)
7960 || put_user_id(high2lowuid(euid), arg2)
7961 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00007962 goto efault;
bellard67867302003-11-23 17:05:30 +00007963 }
7964 }
7965 break;
7966#endif
7967#ifdef TARGET_NR_getresgid
7968 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007969 ret = get_errno(setresgid(low2highgid(arg1),
7970 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007971 low2highgid(arg3)));
7972 break;
7973#endif
7974#ifdef TARGET_NR_getresgid
7975 case TARGET_NR_getresgid:
7976 {
pbrook53a59602006-03-25 19:31:22 +00007977 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007978 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7979 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007980 if (put_user_id(high2lowgid(rgid), arg1)
7981 || put_user_id(high2lowgid(egid), arg2)
7982 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00007983 goto efault;
bellard67867302003-11-23 17:05:30 +00007984 }
7985 }
7986 break;
7987#endif
7988 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007989 if (!(p = lock_user_string(arg1)))
7990 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007991 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7992 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007993 break;
7994 case TARGET_NR_setuid:
7995 ret = get_errno(setuid(low2highuid(arg1)));
7996 break;
7997 case TARGET_NR_setgid:
7998 ret = get_errno(setgid(low2highgid(arg1)));
7999 break;
8000 case TARGET_NR_setfsuid:
8001 ret = get_errno(setfsuid(arg1));
8002 break;
8003 case TARGET_NR_setfsgid:
8004 ret = get_errno(setfsgid(arg1));
8005 break;
bellard67867302003-11-23 17:05:30 +00008006
bellarda315a142005-01-30 22:59:18 +00008007#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008008 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008009 if (!(p = lock_user_string(arg1)))
8010 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008011 ret = get_errno(lchown(p, arg2, arg3));
8012 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008013 break;
bellarda315a142005-01-30 22:59:18 +00008014#endif
8015#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008016 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008017 ret = get_errno(getuid());
8018 break;
bellarda315a142005-01-30 22:59:18 +00008019#endif
aurel3264b4d282008-11-14 17:20:15 +00008020
8021#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8022 /* Alpha specific */
8023 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008024 {
8025 uid_t euid;
8026 euid=geteuid();
8027 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8028 }
aurel3264b4d282008-11-14 17:20:15 +00008029 ret = get_errno(getuid());
8030 break;
8031#endif
8032#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8033 /* Alpha specific */
8034 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008035 {
8036 uid_t egid;
8037 egid=getegid();
8038 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8039 }
aurel3264b4d282008-11-14 17:20:15 +00008040 ret = get_errno(getgid());
8041 break;
8042#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008043#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8044 /* Alpha specific */
8045 case TARGET_NR_osf_getsysinfo:
8046 ret = -TARGET_EOPNOTSUPP;
8047 switch (arg1) {
8048 case TARGET_GSI_IEEE_FP_CONTROL:
8049 {
8050 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8051
8052 /* Copied from linux ieee_fpcr_to_swcr. */
8053 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8054 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8055 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8056 | SWCR_TRAP_ENABLE_DZE
8057 | SWCR_TRAP_ENABLE_OVF);
8058 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8059 | SWCR_TRAP_ENABLE_INE);
8060 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8061 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8062
8063 if (put_user_u64 (swcr, arg2))
8064 goto efault;
8065 ret = 0;
8066 }
8067 break;
8068
8069 /* case GSI_IEEE_STATE_AT_SIGNAL:
8070 -- Not implemented in linux kernel.
8071 case GSI_UACPROC:
8072 -- Retrieves current unaligned access state; not much used.
8073 case GSI_PROC_TYPE:
8074 -- Retrieves implver information; surely not used.
8075 case GSI_GET_HWRPB:
8076 -- Grabs a copy of the HWRPB; surely not used.
8077 */
8078 }
8079 break;
8080#endif
8081#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8082 /* Alpha specific */
8083 case TARGET_NR_osf_setsysinfo:
8084 ret = -TARGET_EOPNOTSUPP;
8085 switch (arg1) {
8086 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008087 {
8088 uint64_t swcr, fpcr, orig_fpcr;
8089
Richard Henderson6e06d512012-06-01 09:08:21 -07008090 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008091 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008092 }
8093 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008094 fpcr = orig_fpcr & FPCR_DYN_MASK;
8095
8096 /* Copied from linux ieee_swcr_to_fpcr. */
8097 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8098 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8099 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8100 | SWCR_TRAP_ENABLE_DZE
8101 | SWCR_TRAP_ENABLE_OVF)) << 48;
8102 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8103 | SWCR_TRAP_ENABLE_INE)) << 57;
8104 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8105 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8106
Richard Henderson6e06d512012-06-01 09:08:21 -07008107 cpu_alpha_store_fpcr(cpu_env, fpcr);
8108 ret = 0;
8109 }
8110 break;
8111
8112 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8113 {
8114 uint64_t exc, fpcr, orig_fpcr;
8115 int si_code;
8116
8117 if (get_user_u64(exc, arg2)) {
8118 goto efault;
8119 }
8120
8121 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8122
8123 /* We only add to the exception status here. */
8124 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8125
8126 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008127 ret = 0;
8128
Richard Henderson6e06d512012-06-01 09:08:21 -07008129 /* Old exceptions are not signaled. */
8130 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008131
Richard Henderson6e06d512012-06-01 09:08:21 -07008132 /* If any exceptions set by this call,
8133 and are unmasked, send a signal. */
8134 si_code = 0;
8135 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8136 si_code = TARGET_FPE_FLTRES;
8137 }
8138 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8139 si_code = TARGET_FPE_FLTUND;
8140 }
8141 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8142 si_code = TARGET_FPE_FLTOVF;
8143 }
8144 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8145 si_code = TARGET_FPE_FLTDIV;
8146 }
8147 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8148 si_code = TARGET_FPE_FLTINV;
8149 }
8150 if (si_code != 0) {
8151 target_siginfo_t info;
8152 info.si_signo = SIGFPE;
8153 info.si_errno = 0;
8154 info.si_code = si_code;
8155 info._sifields._sigfault._addr
8156 = ((CPUArchState *)cpu_env)->pc;
8157 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008158 }
8159 }
8160 break;
8161
8162 /* case SSI_NVPAIRS:
8163 -- Used with SSIN_UACPROC to enable unaligned accesses.
8164 case SSI_IEEE_STATE_AT_SIGNAL:
8165 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8166 -- Not implemented in linux kernel
8167 */
8168 }
8169 break;
8170#endif
8171#ifdef TARGET_NR_osf_sigprocmask
8172 /* Alpha specific. */
8173 case TARGET_NR_osf_sigprocmask:
8174 {
8175 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008176 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008177 sigset_t set, oldset;
8178
8179 switch(arg1) {
8180 case TARGET_SIG_BLOCK:
8181 how = SIG_BLOCK;
8182 break;
8183 case TARGET_SIG_UNBLOCK:
8184 how = SIG_UNBLOCK;
8185 break;
8186 case TARGET_SIG_SETMASK:
8187 how = SIG_SETMASK;
8188 break;
8189 default:
8190 ret = -TARGET_EINVAL;
8191 goto fail;
8192 }
8193 mask = arg2;
8194 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008195 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008196 host_to_target_old_sigset(&mask, &oldset);
8197 ret = mask;
8198 }
8199 break;
8200#endif
aurel3264b4d282008-11-14 17:20:15 +00008201
bellarda315a142005-01-30 22:59:18 +00008202#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008203 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008204 ret = get_errno(getgid());
8205 break;
bellarda315a142005-01-30 22:59:18 +00008206#endif
8207#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008208 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008209 ret = get_errno(geteuid());
8210 break;
bellarda315a142005-01-30 22:59:18 +00008211#endif
8212#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008213 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008214 ret = get_errno(getegid());
8215 break;
bellarda315a142005-01-30 22:59:18 +00008216#endif
8217#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008218 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008219 ret = get_errno(setreuid(arg1, arg2));
8220 break;
bellarda315a142005-01-30 22:59:18 +00008221#endif
8222#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008223 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008224 ret = get_errno(setregid(arg1, arg2));
8225 break;
bellarda315a142005-01-30 22:59:18 +00008226#endif
8227#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008228 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008229 {
8230 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008231 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008232 gid_t *grouplist;
8233 int i;
8234
8235 grouplist = alloca(gidsetsize * sizeof(gid_t));
8236 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008237 if (gidsetsize == 0)
8238 break;
bellard99c475a2005-01-31 20:45:13 +00008239 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008240 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8241 if (!target_grouplist) {
8242 ret = -TARGET_EFAULT;
8243 goto fail;
8244 }
balroga2155fc2008-09-20 02:12:08 +00008245 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008246 target_grouplist[i] = tswap32(grouplist[i]);
8247 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008248 }
8249 }
8250 break;
bellarda315a142005-01-30 22:59:18 +00008251#endif
8252#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008253 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008254 {
8255 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008256 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008257 gid_t *grouplist;
8258 int i;
ths3b46e622007-09-17 08:09:54 +00008259
bellard99c475a2005-01-31 20:45:13 +00008260 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008261 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8262 if (!target_grouplist) {
8263 ret = -TARGET_EFAULT;
8264 goto fail;
8265 }
bellard99c475a2005-01-31 20:45:13 +00008266 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008267 grouplist[i] = tswap32(target_grouplist[i]);
8268 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008269 ret = get_errno(setgroups(gidsetsize, grouplist));
8270 }
8271 break;
bellarda315a142005-01-30 22:59:18 +00008272#endif
8273#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008274 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008275 ret = get_errno(fchown(arg1, arg2, arg3));
8276 break;
bellarda315a142005-01-30 22:59:18 +00008277#endif
8278#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008279 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008280 ret = get_errno(setresuid(arg1, arg2, arg3));
8281 break;
bellarda315a142005-01-30 22:59:18 +00008282#endif
8283#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008284 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008285 {
pbrook53a59602006-03-25 19:31:22 +00008286 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008287 ret = get_errno(getresuid(&ruid, &euid, &suid));
8288 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008289 if (put_user_u32(ruid, arg1)
8290 || put_user_u32(euid, arg2)
8291 || put_user_u32(suid, arg3))
8292 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008293 }
8294 }
8295 break;
bellarda315a142005-01-30 22:59:18 +00008296#endif
8297#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008298 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008299 ret = get_errno(setresgid(arg1, arg2, arg3));
8300 break;
bellarda315a142005-01-30 22:59:18 +00008301#endif
8302#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008303 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008304 {
pbrook53a59602006-03-25 19:31:22 +00008305 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008306 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8307 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008308 if (put_user_u32(rgid, arg1)
8309 || put_user_u32(egid, arg2)
8310 || put_user_u32(sgid, arg3))
8311 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008312 }
8313 }
8314 break;
bellarda315a142005-01-30 22:59:18 +00008315#endif
8316#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008318 if (!(p = lock_user_string(arg1)))
8319 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008320 ret = get_errno(chown(p, arg2, arg3));
8321 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008322 break;
bellarda315a142005-01-30 22:59:18 +00008323#endif
8324#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008325 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008326 ret = get_errno(setuid(arg1));
8327 break;
bellarda315a142005-01-30 22:59:18 +00008328#endif
8329#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008330 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008331 ret = get_errno(setgid(arg1));
8332 break;
bellarda315a142005-01-30 22:59:18 +00008333#endif
8334#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008335 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008336 ret = get_errno(setfsuid(arg1));
8337 break;
bellarda315a142005-01-30 22:59:18 +00008338#endif
8339#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008340 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008341 ret = get_errno(setfsgid(arg1));
8342 break;
bellarda315a142005-01-30 22:59:18 +00008343#endif
bellard67867302003-11-23 17:05:30 +00008344
bellard31e31b82003-02-18 22:55:36 +00008345 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008346 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008347#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008348 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008349 {
8350 void *a;
8351 ret = -TARGET_EFAULT;
8352 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8353 goto efault;
8354 if (!(p = lock_user_string(arg3)))
8355 goto mincore_fail;
8356 ret = get_errno(mincore(a, arg2, p));
8357 unlock_user(p, arg3, ret);
8358 mincore_fail:
8359 unlock_user(a, arg1, 0);
8360 }
8361 break;
bellardffa65c32004-01-04 23:57:22 +00008362#endif
aurel32408321b2008-10-01 21:46:32 +00008363#ifdef TARGET_NR_arm_fadvise64_64
8364 case TARGET_NR_arm_fadvise64_64:
8365 {
8366 /*
8367 * arm_fadvise64_64 looks like fadvise64_64 but
8368 * with different argument order
8369 */
8370 abi_long temp;
8371 temp = arg3;
8372 arg3 = arg4;
8373 arg4 = temp;
8374 }
8375#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008376#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008377#ifdef TARGET_NR_fadvise64_64
8378 case TARGET_NR_fadvise64_64:
8379#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008380#ifdef TARGET_NR_fadvise64
8381 case TARGET_NR_fadvise64:
8382#endif
8383#ifdef TARGET_S390X
8384 switch (arg4) {
8385 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8386 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8387 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8388 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8389 default: break;
8390 }
8391#endif
8392 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008393 break;
8394#endif
bellardffa65c32004-01-04 23:57:22 +00008395#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008396 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008397 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008398 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008399 This will break MADV_DONTNEED.
8400 This is a hint, so ignoring and returning success is ok. */
8401 ret = get_errno(0);
8402 break;
bellardffa65c32004-01-04 23:57:22 +00008403#endif
blueswir1992f48a2007-10-14 16:27:31 +00008404#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008405 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008406 {
thsb1e341e2007-03-20 21:50:52 +00008407 int cmd;
bellard77e46722003-04-29 20:39:06 +00008408 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008409 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008410#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008411 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008412#endif
bellard77e46722003-04-29 20:39:06 +00008413
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008414 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008415 if (cmd == -TARGET_EINVAL) {
8416 ret = cmd;
8417 break;
8418 }
thsb1e341e2007-03-20 21:50:52 +00008419
bellard60cd49d2003-03-16 22:53:56 +00008420 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008421 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008422#ifdef TARGET_ARM
8423 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008424 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8425 goto efault;
ths58134272007-03-31 18:59:32 +00008426 fl.l_type = tswap16(target_efl->l_type);
8427 fl.l_whence = tswap16(target_efl->l_whence);
8428 fl.l_start = tswap64(target_efl->l_start);
8429 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008430 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008431 unlock_user_struct(target_efl, arg3, 0);
8432 } else
8433#endif
8434 {
bellard9ee1fa22007-11-11 15:11:19 +00008435 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8436 goto efault;
ths58134272007-03-31 18:59:32 +00008437 fl.l_type = tswap16(target_fl->l_type);
8438 fl.l_whence = tswap16(target_fl->l_whence);
8439 fl.l_start = tswap64(target_fl->l_start);
8440 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008441 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008442 unlock_user_struct(target_fl, arg3, 0);
8443 }
thsb1e341e2007-03-20 21:50:52 +00008444 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008445 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008446#ifdef TARGET_ARM
8447 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008448 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8449 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008450 target_efl->l_type = tswap16(fl.l_type);
8451 target_efl->l_whence = tswap16(fl.l_whence);
8452 target_efl->l_start = tswap64(fl.l_start);
8453 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008454 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008455 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008456 } else
8457#endif
8458 {
bellard9ee1fa22007-11-11 15:11:19 +00008459 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8460 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008461 target_fl->l_type = tswap16(fl.l_type);
8462 target_fl->l_whence = tswap16(fl.l_whence);
8463 target_fl->l_start = tswap64(fl.l_start);
8464 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008465 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008466 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008467 }
bellard77e46722003-04-29 20:39:06 +00008468 }
8469 break;
8470
thsb1e341e2007-03-20 21:50:52 +00008471 case TARGET_F_SETLK64:
8472 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008473#ifdef TARGET_ARM
8474 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008475 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8476 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008477 fl.l_type = tswap16(target_efl->l_type);
8478 fl.l_whence = tswap16(target_efl->l_whence);
8479 fl.l_start = tswap64(target_efl->l_start);
8480 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008481 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008482 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008483 } else
8484#endif
8485 {
bellard9ee1fa22007-11-11 15:11:19 +00008486 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8487 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008488 fl.l_type = tswap16(target_fl->l_type);
8489 fl.l_whence = tswap16(target_fl->l_whence);
8490 fl.l_start = tswap64(target_fl->l_start);
8491 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008492 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008493 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008494 }
thsb1e341e2007-03-20 21:50:52 +00008495 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008496 break;
bellard60cd49d2003-03-16 22:53:56 +00008497 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008498 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008499 break;
8500 }
bellard77e46722003-04-29 20:39:06 +00008501 break;
8502 }
bellard60cd49d2003-03-16 22:53:56 +00008503#endif
ths7d600c82006-12-08 01:32:58 +00008504#ifdef TARGET_NR_cacheflush
8505 case TARGET_NR_cacheflush:
8506 /* self-modifying code is handled automatically, so nothing needed */
8507 ret = 0;
8508 break;
8509#endif
bellardebc05482003-09-30 21:08:41 +00008510#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008511 case TARGET_NR_security:
8512 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008513#endif
bellardc573ff62004-01-04 15:51:36 +00008514#ifdef TARGET_NR_getpagesize
8515 case TARGET_NR_getpagesize:
8516 ret = TARGET_PAGE_SIZE;
8517 break;
8518#endif
bellard31e31b82003-02-18 22:55:36 +00008519 case TARGET_NR_gettid:
8520 ret = get_errno(gettid());
8521 break;
thse5febef2007-04-01 18:31:35 +00008522#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008523 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008524#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008525 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008526 arg2 = arg3;
8527 arg3 = arg4;
8528 arg4 = arg5;
8529 }
aurel322054ac92008-10-13 21:08:07 +00008530 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8531#else
8532 ret = get_errno(readahead(arg1, arg2, arg3));
8533#endif
8534 break;
thse5febef2007-04-01 18:31:35 +00008535#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008536#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008537#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008538 case TARGET_NR_listxattr:
8539 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008540 {
8541 void *p, *b = 0;
8542 if (arg2) {
8543 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8544 if (!b) {
8545 ret = -TARGET_EFAULT;
8546 break;
8547 }
8548 }
8549 p = lock_user_string(arg1);
8550 if (p) {
8551 if (num == TARGET_NR_listxattr) {
8552 ret = get_errno(listxattr(p, b, arg3));
8553 } else {
8554 ret = get_errno(llistxattr(p, b, arg3));
8555 }
8556 } else {
8557 ret = -TARGET_EFAULT;
8558 }
8559 unlock_user(p, arg1, 0);
8560 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008561 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008562 }
8563 case TARGET_NR_flistxattr:
8564 {
8565 void *b = 0;
8566 if (arg2) {
8567 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8568 if (!b) {
8569 ret = -TARGET_EFAULT;
8570 break;
8571 }
8572 }
8573 ret = get_errno(flistxattr(arg1, b, arg3));
8574 unlock_user(b, arg2, arg3);
8575 break;
8576 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008577 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008578 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008579 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008580 void *p, *n, *v = 0;
8581 if (arg3) {
8582 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8583 if (!v) {
8584 ret = -TARGET_EFAULT;
8585 break;
8586 }
8587 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008588 p = lock_user_string(arg1);
8589 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008590 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008591 if (num == TARGET_NR_setxattr) {
8592 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8593 } else {
8594 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8595 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008596 } else {
8597 ret = -TARGET_EFAULT;
8598 }
8599 unlock_user(p, arg1, 0);
8600 unlock_user(n, arg2, 0);
8601 unlock_user(v, arg3, 0);
8602 }
8603 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008604 case TARGET_NR_fsetxattr:
8605 {
8606 void *n, *v = 0;
8607 if (arg3) {
8608 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8609 if (!v) {
8610 ret = -TARGET_EFAULT;
8611 break;
8612 }
8613 }
8614 n = lock_user_string(arg2);
8615 if (n) {
8616 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8617 } else {
8618 ret = -TARGET_EFAULT;
8619 }
8620 unlock_user(n, arg2, 0);
8621 unlock_user(v, arg3, 0);
8622 }
8623 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008624 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008625 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008626 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008627 void *p, *n, *v = 0;
8628 if (arg3) {
8629 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8630 if (!v) {
8631 ret = -TARGET_EFAULT;
8632 break;
8633 }
8634 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008635 p = lock_user_string(arg1);
8636 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008637 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008638 if (num == TARGET_NR_getxattr) {
8639 ret = get_errno(getxattr(p, n, v, arg4));
8640 } else {
8641 ret = get_errno(lgetxattr(p, n, v, arg4));
8642 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008643 } else {
8644 ret = -TARGET_EFAULT;
8645 }
8646 unlock_user(p, arg1, 0);
8647 unlock_user(n, arg2, 0);
8648 unlock_user(v, arg3, arg4);
8649 }
8650 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008651 case TARGET_NR_fgetxattr:
8652 {
8653 void *n, *v = 0;
8654 if (arg3) {
8655 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8656 if (!v) {
8657 ret = -TARGET_EFAULT;
8658 break;
8659 }
8660 }
8661 n = lock_user_string(arg2);
8662 if (n) {
8663 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8664 } else {
8665 ret = -TARGET_EFAULT;
8666 }
8667 unlock_user(n, arg2, 0);
8668 unlock_user(v, arg3, arg4);
8669 }
8670 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008671 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008672 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008673 {
8674 void *p, *n;
8675 p = lock_user_string(arg1);
8676 n = lock_user_string(arg2);
8677 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008678 if (num == TARGET_NR_removexattr) {
8679 ret = get_errno(removexattr(p, n));
8680 } else {
8681 ret = get_errno(lremovexattr(p, n));
8682 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008683 } else {
8684 ret = -TARGET_EFAULT;
8685 }
8686 unlock_user(p, arg1, 0);
8687 unlock_user(n, arg2, 0);
8688 }
8689 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008690 case TARGET_NR_fremovexattr:
8691 {
8692 void *n;
8693 n = lock_user_string(arg2);
8694 if (n) {
8695 ret = get_errno(fremovexattr(arg1, n));
8696 } else {
8697 ret = -TARGET_EFAULT;
8698 }
8699 unlock_user(n, arg2, 0);
8700 }
8701 break;
bellardebc05482003-09-30 21:08:41 +00008702#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008703#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008704#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008705 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008706#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02008707 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00008708 ret = 0;
8709 break;
edgar_iglef967792009-01-07 14:19:38 +00008710#elif defined(TARGET_CRIS)
8711 if (arg1 & 0xff)
8712 ret = -TARGET_EINVAL;
8713 else {
8714 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8715 ret = 0;
8716 }
8717 break;
bellard8d18e892007-11-14 15:18:40 +00008718#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8719 ret = do_set_thread_area(cpu_env, arg1);
8720 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008721#elif defined(TARGET_M68K)
8722 {
Andreas Färber0429a972013-08-26 18:14:44 +02008723 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008724 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008725 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008726 break;
8727 }
ths6f5b89a2007-03-02 20:48:00 +00008728#else
8729 goto unimplemented_nowarn;
8730#endif
8731#endif
8732#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008733 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008734#if defined(TARGET_I386) && defined(TARGET_ABI32)
8735 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008736 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008737#elif defined(TARGET_M68K)
8738 {
Andreas Färber0429a972013-08-26 18:14:44 +02008739 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008740 ret = ts->tp_value;
8741 break;
8742 }
bellard8d18e892007-11-14 15:18:40 +00008743#else
bellard5cd43932003-03-29 16:54:36 +00008744 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008745#endif
bellard8d18e892007-11-14 15:18:40 +00008746#endif
bellard48dc41e2006-06-21 18:15:50 +00008747#ifdef TARGET_NR_getdomainname
8748 case TARGET_NR_getdomainname:
8749 goto unimplemented_nowarn;
8750#endif
ths6f5b89a2007-03-02 20:48:00 +00008751
thsb5906f92007-03-19 13:32:45 +00008752#ifdef TARGET_NR_clock_gettime
8753 case TARGET_NR_clock_gettime:
8754 {
8755 struct timespec ts;
8756 ret = get_errno(clock_gettime(arg1, &ts));
8757 if (!is_error(ret)) {
8758 host_to_target_timespec(arg2, &ts);
8759 }
8760 break;
8761 }
8762#endif
8763#ifdef TARGET_NR_clock_getres
8764 case TARGET_NR_clock_getres:
8765 {
8766 struct timespec ts;
8767 ret = get_errno(clock_getres(arg1, &ts));
8768 if (!is_error(ret)) {
8769 host_to_target_timespec(arg2, &ts);
8770 }
8771 break;
8772 }
8773#endif
pbrook63d76512008-05-29 13:43:29 +00008774#ifdef TARGET_NR_clock_nanosleep
8775 case TARGET_NR_clock_nanosleep:
8776 {
8777 struct timespec ts;
8778 target_to_host_timespec(&ts, arg3);
8779 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8780 if (arg4)
8781 host_to_target_timespec(arg4, &ts);
8782 break;
8783 }
8784#endif
thsb5906f92007-03-19 13:32:45 +00008785
ths6f5b89a2007-03-02 20:48:00 +00008786#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8787 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008788 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8789 break;
ths6f5b89a2007-03-02 20:48:00 +00008790#endif
8791
ths3ae43202007-09-16 21:39:48 +00008792#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008793 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008794 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008795 break;
8796#endif
8797
ths3ae43202007-09-16 21:39:48 +00008798#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008799 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008800 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8801 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008802 break;
8803#endif
8804
ths4f2b1fe2007-06-21 21:57:12 +00008805#ifdef TARGET_NR_set_robust_list
8806 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008807 case TARGET_NR_get_robust_list:
8808 /* The ABI for supporting robust futexes has userspace pass
8809 * the kernel a pointer to a linked list which is updated by
8810 * userspace after the syscall; the list is walked by the kernel
8811 * when the thread exits. Since the linked list in QEMU guest
8812 * memory isn't a valid linked list for the host and we have
8813 * no way to reliably intercept the thread-death event, we can't
8814 * support these. Silently return ENOSYS so that guest userspace
8815 * falls back to a non-robust futex implementation (which should
8816 * be OK except in the corner case of the guest crashing while
8817 * holding a mutex that is shared with another process via
8818 * shared memory).
8819 */
8820 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008821#endif
8822
Peter Maydell1acae9f2013-07-02 14:04:12 +01008823#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00008824 case TARGET_NR_utimensat:
8825 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008826 struct timespec *tsp, ts[2];
8827 if (!arg3) {
8828 tsp = NULL;
8829 } else {
8830 target_to_host_timespec(ts, arg3);
8831 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8832 tsp = ts;
8833 }
ths9007f0e2007-09-25 17:50:37 +00008834 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008835 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008836 else {
bellard579a97f2007-11-11 14:26:47 +00008837 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008838 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008839 goto fail;
8840 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008841 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008842 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008843 }
8844 }
8845 break;
8846#endif
pbrookbd0c5662008-05-29 14:34:11 +00008847 case TARGET_NR_futex:
8848 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8849 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008850#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008851 case TARGET_NR_inotify_init:
8852 ret = get_errno(sys_inotify_init());
8853 break;
8854#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008855#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008856#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8857 case TARGET_NR_inotify_init1:
8858 ret = get_errno(sys_inotify_init1(arg1));
8859 break;
8860#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008861#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008862#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008863 case TARGET_NR_inotify_add_watch:
8864 p = lock_user_string(arg2);
8865 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8866 unlock_user(p, arg2, 0);
8867 break;
8868#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008869#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008870 case TARGET_NR_inotify_rm_watch:
8871 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8872 break;
8873#endif
ths9007f0e2007-09-25 17:50:37 +00008874
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008875#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008876 case TARGET_NR_mq_open:
8877 {
8878 struct mq_attr posix_mq_attr;
8879
8880 p = lock_user_string(arg1 - 1);
8881 if (arg4 != 0)
8882 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8883 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8884 unlock_user (p, arg1, 0);
8885 }
8886 break;
8887
8888 case TARGET_NR_mq_unlink:
8889 p = lock_user_string(arg1 - 1);
8890 ret = get_errno(mq_unlink(p));
8891 unlock_user (p, arg1, 0);
8892 break;
8893
8894 case TARGET_NR_mq_timedsend:
8895 {
8896 struct timespec ts;
8897
8898 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8899 if (arg5 != 0) {
8900 target_to_host_timespec(&ts, arg5);
8901 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8902 host_to_target_timespec(arg5, &ts);
8903 }
8904 else
8905 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8906 unlock_user (p, arg2, arg3);
8907 }
8908 break;
8909
8910 case TARGET_NR_mq_timedreceive:
8911 {
8912 struct timespec ts;
8913 unsigned int prio;
8914
8915 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8916 if (arg5 != 0) {
8917 target_to_host_timespec(&ts, arg5);
8918 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8919 host_to_target_timespec(arg5, &ts);
8920 }
8921 else
8922 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8923 unlock_user (p, arg2, arg3);
8924 if (arg4 != 0)
8925 put_user_u32(prio, arg4);
8926 }
8927 break;
8928
8929 /* Not implemented for now... */
8930/* case TARGET_NR_mq_notify: */
8931/* break; */
8932
8933 case TARGET_NR_mq_getsetattr:
8934 {
8935 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8936 ret = 0;
8937 if (arg3 != 0) {
8938 ret = mq_getattr(arg1, &posix_mq_attr_out);
8939 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8940 }
8941 if (arg2 != 0) {
8942 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8943 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8944 }
8945
8946 }
8947 break;
8948#endif
8949
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308950#ifdef CONFIG_SPLICE
8951#ifdef TARGET_NR_tee
8952 case TARGET_NR_tee:
8953 {
8954 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8955 }
8956 break;
8957#endif
8958#ifdef TARGET_NR_splice
8959 case TARGET_NR_splice:
8960 {
8961 loff_t loff_in, loff_out;
8962 loff_t *ploff_in = NULL, *ploff_out = NULL;
8963 if(arg2) {
8964 get_user_u64(loff_in, arg2);
8965 ploff_in = &loff_in;
8966 }
8967 if(arg4) {
8968 get_user_u64(loff_out, arg2);
8969 ploff_out = &loff_out;
8970 }
8971 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8972 }
8973 break;
8974#endif
8975#ifdef TARGET_NR_vmsplice
8976 case TARGET_NR_vmsplice:
8977 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008978 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8979 if (vec != NULL) {
8980 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8981 unlock_iovec(vec, arg2, arg3, 0);
8982 } else {
8983 ret = -host_to_target_errno(errno);
8984 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308985 }
8986 break;
8987#endif
8988#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008989#ifdef CONFIG_EVENTFD
8990#if defined(TARGET_NR_eventfd)
8991 case TARGET_NR_eventfd:
8992 ret = get_errno(eventfd(arg1, 0));
8993 break;
8994#endif
8995#if defined(TARGET_NR_eventfd2)
8996 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02008997 {
8998 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
8999 if (arg2 & TARGET_O_NONBLOCK) {
9000 host_flags |= O_NONBLOCK;
9001 }
9002 if (arg2 & TARGET_O_CLOEXEC) {
9003 host_flags |= O_CLOEXEC;
9004 }
9005 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009006 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009007 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009008#endif
9009#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009010#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9011 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009012#if TARGET_ABI_BITS == 32
9013 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9014 target_offset64(arg5, arg6)));
9015#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009016 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009017#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009018 break;
9019#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009020#if defined(CONFIG_SYNC_FILE_RANGE)
9021#if defined(TARGET_NR_sync_file_range)
9022 case TARGET_NR_sync_file_range:
9023#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009024#if defined(TARGET_MIPS)
9025 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9026 target_offset64(arg5, arg6), arg7));
9027#else
Peter Maydellc727f472011-01-06 11:05:10 +00009028 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9029 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009030#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009031#else
9032 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9033#endif
9034 break;
9035#endif
9036#if defined(TARGET_NR_sync_file_range2)
9037 case TARGET_NR_sync_file_range2:
9038 /* This is like sync_file_range but the arguments are reordered */
9039#if TARGET_ABI_BITS == 32
9040 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9041 target_offset64(arg5, arg6), arg2));
9042#else
9043 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9044#endif
9045 break;
9046#endif
9047#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009048#if defined(CONFIG_EPOLL)
9049#if defined(TARGET_NR_epoll_create)
9050 case TARGET_NR_epoll_create:
9051 ret = get_errno(epoll_create(arg1));
9052 break;
9053#endif
9054#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9055 case TARGET_NR_epoll_create1:
9056 ret = get_errno(epoll_create1(arg1));
9057 break;
9058#endif
9059#if defined(TARGET_NR_epoll_ctl)
9060 case TARGET_NR_epoll_ctl:
9061 {
9062 struct epoll_event ep;
9063 struct epoll_event *epp = 0;
9064 if (arg4) {
9065 struct target_epoll_event *target_ep;
9066 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9067 goto efault;
9068 }
9069 ep.events = tswap32(target_ep->events);
9070 /* The epoll_data_t union is just opaque data to the kernel,
9071 * so we transfer all 64 bits across and need not worry what
9072 * actual data type it is.
9073 */
9074 ep.data.u64 = tswap64(target_ep->data.u64);
9075 unlock_user_struct(target_ep, arg4, 0);
9076 epp = &ep;
9077 }
9078 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9079 break;
9080 }
9081#endif
9082
9083#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9084#define IMPLEMENT_EPOLL_PWAIT
9085#endif
9086#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9087#if defined(TARGET_NR_epoll_wait)
9088 case TARGET_NR_epoll_wait:
9089#endif
9090#if defined(IMPLEMENT_EPOLL_PWAIT)
9091 case TARGET_NR_epoll_pwait:
9092#endif
9093 {
9094 struct target_epoll_event *target_ep;
9095 struct epoll_event *ep;
9096 int epfd = arg1;
9097 int maxevents = arg3;
9098 int timeout = arg4;
9099
9100 target_ep = lock_user(VERIFY_WRITE, arg2,
9101 maxevents * sizeof(struct target_epoll_event), 1);
9102 if (!target_ep) {
9103 goto efault;
9104 }
9105
9106 ep = alloca(maxevents * sizeof(struct epoll_event));
9107
9108 switch (num) {
9109#if defined(IMPLEMENT_EPOLL_PWAIT)
9110 case TARGET_NR_epoll_pwait:
9111 {
9112 target_sigset_t *target_set;
9113 sigset_t _set, *set = &_set;
9114
9115 if (arg5) {
9116 target_set = lock_user(VERIFY_READ, arg5,
9117 sizeof(target_sigset_t), 1);
9118 if (!target_set) {
9119 unlock_user(target_ep, arg2, 0);
9120 goto efault;
9121 }
9122 target_to_host_sigset(set, target_set);
9123 unlock_user(target_set, arg5, 0);
9124 } else {
9125 set = NULL;
9126 }
9127
9128 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9129 break;
9130 }
9131#endif
9132#if defined(TARGET_NR_epoll_wait)
9133 case TARGET_NR_epoll_wait:
9134 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9135 break;
9136#endif
9137 default:
9138 ret = -TARGET_ENOSYS;
9139 }
9140 if (!is_error(ret)) {
9141 int i;
9142 for (i = 0; i < ret; i++) {
9143 target_ep[i].events = tswap32(ep[i].events);
9144 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9145 }
9146 }
9147 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9148 break;
9149 }
9150#endif
9151#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009152#ifdef TARGET_NR_prlimit64
9153 case TARGET_NR_prlimit64:
9154 {
9155 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9156 struct target_rlimit64 *target_rnew, *target_rold;
9157 struct host_rlimit64 rnew, rold, *rnewp = 0;
9158 if (arg3) {
9159 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9160 goto efault;
9161 }
9162 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9163 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9164 unlock_user_struct(target_rnew, arg3, 0);
9165 rnewp = &rnew;
9166 }
9167
9168 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9169 if (!is_error(ret) && arg4) {
9170 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9171 goto efault;
9172 }
9173 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9174 target_rold->rlim_max = tswap64(rold.rlim_max);
9175 unlock_user_struct(target_rold, arg4, 1);
9176 }
9177 break;
9178 }
9179#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009180#ifdef TARGET_NR_gethostname
9181 case TARGET_NR_gethostname:
9182 {
9183 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9184 if (name) {
9185 ret = get_errno(gethostname(name, arg2));
9186 unlock_user(name, arg1, arg2);
9187 } else {
9188 ret = -TARGET_EFAULT;
9189 }
9190 break;
9191 }
9192#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009193#ifdef TARGET_NR_atomic_cmpxchg_32
9194 case TARGET_NR_atomic_cmpxchg_32:
9195 {
9196 /* should use start_exclusive from main.c */
9197 abi_ulong mem_value;
9198 if (get_user_u32(mem_value, arg6)) {
9199 target_siginfo_t info;
9200 info.si_signo = SIGSEGV;
9201 info.si_errno = 0;
9202 info.si_code = TARGET_SEGV_MAPERR;
9203 info._sifields._sigfault._addr = arg6;
9204 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9205 ret = 0xdeadbeef;
9206
9207 }
9208 if (mem_value == arg2)
9209 put_user_u32(arg1, arg6);
9210 ret = mem_value;
9211 break;
9212 }
9213#endif
9214#ifdef TARGET_NR_atomic_barrier
9215 case TARGET_NR_atomic_barrier:
9216 {
9217 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009218 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009219 break;
9220 }
9221#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009222
9223#ifdef TARGET_NR_timer_create
9224 case TARGET_NR_timer_create:
9225 {
9226 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9227
9228 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9229 struct target_sigevent *ptarget_sevp;
9230 struct target_timer_t *ptarget_timer;
9231
9232 int clkid = arg1;
9233 int timer_index = next_free_host_timer();
9234
9235 if (timer_index < 0) {
9236 ret = -TARGET_EAGAIN;
9237 } else {
9238 timer_t *phtimer = g_posix_timers + timer_index;
9239
9240 if (arg2) {
9241 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9242 goto efault;
9243 }
9244
9245 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9246 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9247
9248 phost_sevp = &host_sevp;
9249 }
9250
9251 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9252 if (ret) {
9253 phtimer = NULL;
9254 } else {
9255 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9256 goto efault;
9257 }
9258 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9259 unlock_user_struct(ptarget_timer, arg3, 1);
9260 }
9261 }
9262 break;
9263 }
9264#endif
9265
9266#ifdef TARGET_NR_timer_settime
9267 case TARGET_NR_timer_settime:
9268 {
9269 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9270 * struct itimerspec * old_value */
9271 arg1 &= 0xffff;
9272 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9273 ret = -TARGET_EINVAL;
9274 } else {
9275 timer_t htimer = g_posix_timers[arg1];
9276 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9277
9278 target_to_host_itimerspec(&hspec_new, arg3);
9279 ret = get_errno(
9280 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9281 host_to_target_itimerspec(arg2, &hspec_old);
9282 }
9283 break;
9284 }
9285#endif
9286
9287#ifdef TARGET_NR_timer_gettime
9288 case TARGET_NR_timer_gettime:
9289 {
9290 /* args: timer_t timerid, struct itimerspec *curr_value */
9291 arg1 &= 0xffff;
9292 if (!arg2) {
9293 return -TARGET_EFAULT;
9294 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9295 ret = -TARGET_EINVAL;
9296 } else {
9297 timer_t htimer = g_posix_timers[arg1];
9298 struct itimerspec hspec;
9299 ret = get_errno(timer_gettime(htimer, &hspec));
9300
9301 if (host_to_target_itimerspec(arg2, &hspec)) {
9302 ret = -TARGET_EFAULT;
9303 }
9304 }
9305 break;
9306 }
9307#endif
9308
9309#ifdef TARGET_NR_timer_getoverrun
9310 case TARGET_NR_timer_getoverrun:
9311 {
9312 /* args: timer_t timerid */
9313 arg1 &= 0xffff;
9314 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9315 ret = -TARGET_EINVAL;
9316 } else {
9317 timer_t htimer = g_posix_timers[arg1];
9318 ret = get_errno(timer_getoverrun(htimer));
9319 }
9320 break;
9321 }
9322#endif
9323
9324#ifdef TARGET_NR_timer_delete
9325 case TARGET_NR_timer_delete:
9326 {
9327 /* args: timer_t timerid */
9328 arg1 &= 0xffff;
9329 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9330 ret = -TARGET_EINVAL;
9331 } else {
9332 timer_t htimer = g_posix_timers[arg1];
9333 ret = get_errno(timer_delete(htimer));
9334 g_posix_timers[arg1] = 0;
9335 }
9336 break;
9337 }
9338#endif
9339
bellard31e31b82003-02-18 22:55:36 +00009340 default:
9341 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009342 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009343#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 +00009344 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009345#endif
ths0da46a62007-10-20 20:23:07 +00009346 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009347 break;
9348 }
bellard579a97f2007-11-11 14:26:47 +00009349fail:
bellardc573ff62004-01-04 15:51:36 +00009350#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009351 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009352#endif
thsb92c47c2007-11-01 00:07:38 +00009353 if(do_strace)
9354 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009355 return ret;
bellard579a97f2007-11-11 14:26:47 +00009356efault:
9357 ret = -TARGET_EFAULT;
9358 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009359}