blob: 6efeeff2bf0e2665b42eea8d70828a791b9a3aee [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)
1859 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
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 },
3911 { 0, 0, 0, 0 }
3912};
3913
bellard2ab83ea2003-06-15 19:56:46 +00003914#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003915
3916/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003917static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003918
bellard03acab62007-11-11 14:57:14 +00003919static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003920{
3921 int size;
pbrook53a59602006-03-25 19:31:22 +00003922 void *p;
bellard6dbad632003-03-16 18:05:05 +00003923
3924 if (!ldt_table)
3925 return 0;
3926 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3927 if (size > bytecount)
3928 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003929 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3930 if (!p)
bellard03acab62007-11-11 14:57:14 +00003931 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003932 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003933 memcpy(p, ldt_table, size);
3934 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003935 return size;
3936}
3937
3938/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003939static abi_long write_ldt(CPUX86State *env,
3940 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003941{
3942 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003943 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003944 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003945 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003946 uint32_t *lp, entry_1, entry_2;
3947
3948 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003949 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003950 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003951 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003952 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003953 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003954 ldt_info.limit = tswap32(target_ldt_info->limit);
3955 ldt_info.flags = tswap32(target_ldt_info->flags);
3956 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003957
bellard6dbad632003-03-16 18:05:05 +00003958 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003959 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003960 seg_32bit = ldt_info.flags & 1;
3961 contents = (ldt_info.flags >> 1) & 3;
3962 read_exec_only = (ldt_info.flags >> 3) & 1;
3963 limit_in_pages = (ldt_info.flags >> 4) & 1;
3964 seg_not_present = (ldt_info.flags >> 5) & 1;
3965 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00003966#ifdef TARGET_ABI32
3967 lm = 0;
3968#else
3969 lm = (ldt_info.flags >> 7) & 1;
3970#endif
bellard6dbad632003-03-16 18:05:05 +00003971 if (contents == 3) {
3972 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00003973 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003974 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00003975 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003976 }
3977 /* allocate the LDT */
3978 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00003979 env->ldt.base = target_mmap(0,
3980 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
3981 PROT_READ|PROT_WRITE,
3982 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3983 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00003984 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00003985 memset(g2h(env->ldt.base), 0,
3986 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00003987 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00003988 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00003989 }
3990
3991 /* NOTE: same code as Linux kernel */
3992 /* Allow LDTs to be cleared by the user. */
3993 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
3994 if (oldmode ||
3995 (contents == 0 &&
3996 read_exec_only == 1 &&
3997 seg_32bit == 0 &&
3998 limit_in_pages == 0 &&
3999 seg_not_present == 1 &&
4000 useable == 0 )) {
4001 entry_1 = 0;
4002 entry_2 = 0;
4003 goto install;
4004 }
4005 }
ths3b46e622007-09-17 08:09:54 +00004006
bellard6dbad632003-03-16 18:05:05 +00004007 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4008 (ldt_info.limit & 0x0ffff);
4009 entry_2 = (ldt_info.base_addr & 0xff000000) |
4010 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4011 (ldt_info.limit & 0xf0000) |
4012 ((read_exec_only ^ 1) << 9) |
4013 (contents << 10) |
4014 ((seg_not_present ^ 1) << 15) |
4015 (seg_32bit << 22) |
4016 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004017 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004018 0x7000;
4019 if (!oldmode)
4020 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004021
bellard6dbad632003-03-16 18:05:05 +00004022 /* Install the new entry ... */
4023install:
4024 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4025 lp[0] = tswap32(entry_1);
4026 lp[1] = tswap32(entry_2);
4027 return 0;
4028}
4029
4030/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004031static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4032 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004033{
bellard03acab62007-11-11 14:57:14 +00004034 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004035
bellard6dbad632003-03-16 18:05:05 +00004036 switch (func) {
4037 case 0:
4038 ret = read_ldt(ptr, bytecount);
4039 break;
4040 case 1:
4041 ret = write_ldt(env, ptr, bytecount, 1);
4042 break;
4043 case 0x11:
4044 ret = write_ldt(env, ptr, bytecount, 0);
4045 break;
bellard03acab62007-11-11 14:57:14 +00004046 default:
4047 ret = -TARGET_ENOSYS;
4048 break;
bellard6dbad632003-03-16 18:05:05 +00004049 }
4050 return ret;
4051}
bellard1b6b0292003-03-22 17:31:38 +00004052
blueswir14583f582008-08-24 10:35:55 +00004053#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004054abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004055{
4056 uint64_t *gdt_table = g2h(env->gdt.base);
4057 struct target_modify_ldt_ldt_s ldt_info;
4058 struct target_modify_ldt_ldt_s *target_ldt_info;
4059 int seg_32bit, contents, read_exec_only, limit_in_pages;
4060 int seg_not_present, useable, lm;
4061 uint32_t *lp, entry_1, entry_2;
4062 int i;
4063
4064 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4065 if (!target_ldt_info)
4066 return -TARGET_EFAULT;
4067 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004068 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004069 ldt_info.limit = tswap32(target_ldt_info->limit);
4070 ldt_info.flags = tswap32(target_ldt_info->flags);
4071 if (ldt_info.entry_number == -1) {
4072 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4073 if (gdt_table[i] == 0) {
4074 ldt_info.entry_number = i;
4075 target_ldt_info->entry_number = tswap32(i);
4076 break;
4077 }
4078 }
4079 }
4080 unlock_user_struct(target_ldt_info, ptr, 1);
4081
4082 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4083 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4084 return -TARGET_EINVAL;
4085 seg_32bit = ldt_info.flags & 1;
4086 contents = (ldt_info.flags >> 1) & 3;
4087 read_exec_only = (ldt_info.flags >> 3) & 1;
4088 limit_in_pages = (ldt_info.flags >> 4) & 1;
4089 seg_not_present = (ldt_info.flags >> 5) & 1;
4090 useable = (ldt_info.flags >> 6) & 1;
4091#ifdef TARGET_ABI32
4092 lm = 0;
4093#else
4094 lm = (ldt_info.flags >> 7) & 1;
4095#endif
4096
4097 if (contents == 3) {
4098 if (seg_not_present == 0)
4099 return -TARGET_EINVAL;
4100 }
4101
4102 /* NOTE: same code as Linux kernel */
4103 /* Allow LDTs to be cleared by the user. */
4104 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4105 if ((contents == 0 &&
4106 read_exec_only == 1 &&
4107 seg_32bit == 0 &&
4108 limit_in_pages == 0 &&
4109 seg_not_present == 1 &&
4110 useable == 0 )) {
4111 entry_1 = 0;
4112 entry_2 = 0;
4113 goto install;
4114 }
4115 }
4116
4117 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4118 (ldt_info.limit & 0x0ffff);
4119 entry_2 = (ldt_info.base_addr & 0xff000000) |
4120 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4121 (ldt_info.limit & 0xf0000) |
4122 ((read_exec_only ^ 1) << 9) |
4123 (contents << 10) |
4124 ((seg_not_present ^ 1) << 15) |
4125 (seg_32bit << 22) |
4126 (limit_in_pages << 23) |
4127 (useable << 20) |
4128 (lm << 21) |
4129 0x7000;
4130
4131 /* Install the new entry ... */
4132install:
4133 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4134 lp[0] = tswap32(entry_1);
4135 lp[1] = tswap32(entry_2);
4136 return 0;
4137}
4138
blueswir18fcd3692008-08-17 20:26:25 +00004139static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004140{
4141 struct target_modify_ldt_ldt_s *target_ldt_info;
4142 uint64_t *gdt_table = g2h(env->gdt.base);
4143 uint32_t base_addr, limit, flags;
4144 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4145 int seg_not_present, useable, lm;
4146 uint32_t *lp, entry_1, entry_2;
4147
4148 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4149 if (!target_ldt_info)
4150 return -TARGET_EFAULT;
4151 idx = tswap32(target_ldt_info->entry_number);
4152 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4153 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4154 unlock_user_struct(target_ldt_info, ptr, 1);
4155 return -TARGET_EINVAL;
4156 }
4157 lp = (uint32_t *)(gdt_table + idx);
4158 entry_1 = tswap32(lp[0]);
4159 entry_2 = tswap32(lp[1]);
4160
4161 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4162 contents = (entry_2 >> 10) & 3;
4163 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4164 seg_32bit = (entry_2 >> 22) & 1;
4165 limit_in_pages = (entry_2 >> 23) & 1;
4166 useable = (entry_2 >> 20) & 1;
4167#ifdef TARGET_ABI32
4168 lm = 0;
4169#else
4170 lm = (entry_2 >> 21) & 1;
4171#endif
4172 flags = (seg_32bit << 0) | (contents << 1) |
4173 (read_exec_only << 3) | (limit_in_pages << 4) |
4174 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4175 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4176 base_addr = (entry_1 >> 16) |
4177 (entry_2 & 0xff000000) |
4178 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004179 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004180 target_ldt_info->limit = tswap32(limit);
4181 target_ldt_info->flags = tswap32(flags);
4182 unlock_user_struct(target_ldt_info, ptr, 1);
4183 return 0;
4184}
blueswir14583f582008-08-24 10:35:55 +00004185#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004186
bellardd2fd1af2007-11-14 18:08:56 +00004187#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004188abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004189{
Juan Quintela1add8692011-06-16 17:37:09 +01004190 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004191 abi_ulong val;
4192 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004193
bellardd2fd1af2007-11-14 18:08:56 +00004194 switch(code) {
4195 case TARGET_ARCH_SET_GS:
4196 case TARGET_ARCH_SET_FS:
4197 if (code == TARGET_ARCH_SET_GS)
4198 idx = R_GS;
4199 else
4200 idx = R_FS;
4201 cpu_x86_load_seg(env, idx, 0);
4202 env->segs[idx].base = addr;
4203 break;
4204 case TARGET_ARCH_GET_GS:
4205 case TARGET_ARCH_GET_FS:
4206 if (code == TARGET_ARCH_GET_GS)
4207 idx = R_GS;
4208 else
4209 idx = R_FS;
4210 val = env->segs[idx].base;
4211 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004212 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004213 break;
4214 default:
4215 ret = -TARGET_EINVAL;
4216 break;
4217 }
Juan Quintela1add8692011-06-16 17:37:09 +01004218 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004219}
4220#endif
4221
bellard2ab83ea2003-06-15 19:56:46 +00004222#endif /* defined(TARGET_I386) */
4223
Riku Voipio05098a92011-03-04 15:27:29 +02004224#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004225
pbrookd865bab2008-06-07 22:12:17 +00004226
4227static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4228typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004229 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004230 pthread_mutex_t mutex;
4231 pthread_cond_t cond;
4232 pthread_t thread;
4233 uint32_t tid;
4234 abi_ulong child_tidptr;
4235 abi_ulong parent_tidptr;
4236 sigset_t sigmask;
4237} new_thread_info;
4238
4239static void *clone_func(void *arg)
4240{
4241 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004242 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004243 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004244 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004245
4246 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004247 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004248 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004249 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004250 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004251 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004252 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004253 if (info->child_tidptr)
4254 put_user_u32(info->tid, info->child_tidptr);
4255 if (info->parent_tidptr)
4256 put_user_u32(info->tid, info->parent_tidptr);
4257 /* Enable signals. */
4258 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4259 /* Signal to the parent that we're ready. */
4260 pthread_mutex_lock(&info->mutex);
4261 pthread_cond_broadcast(&info->cond);
4262 pthread_mutex_unlock(&info->mutex);
4263 /* Wait until the parent has finshed initializing the tls state. */
4264 pthread_mutex_lock(&clone_lock);
4265 pthread_mutex_unlock(&clone_lock);
4266 cpu_loop(env);
4267 /* never exits */
4268 return NULL;
4269}
bellard1b6b0292003-03-22 17:31:38 +00004270
ths0da46a62007-10-20 20:23:07 +00004271/* do_fork() Must return host values and target errnos (unlike most
4272 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004273static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004274 abi_ulong parent_tidptr, target_ulong newtls,
4275 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004276{
Andreas Färber0429a972013-08-26 18:14:44 +02004277 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004278 int ret;
bellard5cd43932003-03-29 16:54:36 +00004279 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004280 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004281 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004282 unsigned int nptl_flags;
4283 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004284
balrog436d1242008-09-21 02:39:45 +00004285 /* Emulate vfork() with fork() */
4286 if (flags & CLONE_VFORK)
4287 flags &= ~(CLONE_VFORK | CLONE_VM);
4288
bellard1b6b0292003-03-22 17:31:38 +00004289 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004290 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004291 new_thread_info info;
4292 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004293
Anthony Liguori7267c092011-08-20 22:09:37 -05004294 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004295 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004296 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004297 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004298 /* Init regs that differ from the parent. */
4299 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004300 new_cpu = ENV_GET_CPU(new_env);
4301 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004302 ts->bprm = parent_ts->bprm;
4303 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004304 nptl_flags = flags;
4305 flags &= ~CLONE_NPTL_FLAGS2;
4306
pbrookc2764712009-03-07 15:24:59 +00004307 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4308 ts->child_tidptr = child_tidptr;
4309 }
4310
pbrookd865bab2008-06-07 22:12:17 +00004311 if (nptl_flags & CLONE_SETTLS)
4312 cpu_set_tls (new_env, newtls);
4313
4314 /* Grab a mutex so that thread setup appears atomic. */
4315 pthread_mutex_lock(&clone_lock);
4316
4317 memset(&info, 0, sizeof(info));
4318 pthread_mutex_init(&info.mutex, NULL);
4319 pthread_mutex_lock(&info.mutex);
4320 pthread_cond_init(&info.cond, NULL);
4321 info.env = new_env;
4322 if (nptl_flags & CLONE_CHILD_SETTID)
4323 info.child_tidptr = child_tidptr;
4324 if (nptl_flags & CLONE_PARENT_SETTID)
4325 info.parent_tidptr = parent_tidptr;
4326
4327 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004328 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4329 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004330 /* It is not safe to deliver signals until the child has finished
4331 initializing, so temporarily block all signals. */
4332 sigfillset(&sigmask);
4333 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4334
4335 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004336 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004337
4338 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4339 pthread_attr_destroy(&attr);
4340 if (ret == 0) {
4341 /* Wait for the child to initialize. */
4342 pthread_cond_wait(&info.cond, &info.mutex);
4343 ret = info.tid;
4344 if (flags & CLONE_PARENT_SETTID)
4345 put_user_u32(ret, parent_tidptr);
4346 } else {
4347 ret = -1;
4348 }
4349 pthread_mutex_unlock(&info.mutex);
4350 pthread_cond_destroy(&info.cond);
4351 pthread_mutex_destroy(&info.mutex);
4352 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004353 } else {
4354 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004355 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004356 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004357 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004358 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004359 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004360 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004361 cpu_clone_regs(env, newsp);
4362 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004363 /* There is a race condition here. The parent process could
4364 theoretically read the TID in the child process before the child
4365 tid is set. This would require using either ptrace
4366 (not implemented) or having *_tidptr to point at a shared memory
4367 mapping. We can't repeat the spinlock hack used above because
4368 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004369 if (flags & CLONE_CHILD_SETTID)
4370 put_user_u32(gettid(), child_tidptr);
4371 if (flags & CLONE_PARENT_SETTID)
4372 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004373 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004374 if (flags & CLONE_SETTLS)
4375 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004376 if (flags & CLONE_CHILD_CLEARTID)
4377 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004378 } else {
4379 fork_end(0);
4380 }
bellard1b6b0292003-03-22 17:31:38 +00004381 }
4382 return ret;
4383}
4384
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004385/* warning : doesn't handle linux specific flags... */
4386static int target_to_host_fcntl_cmd(int cmd)
4387{
4388 switch(cmd) {
4389 case TARGET_F_DUPFD:
4390 case TARGET_F_GETFD:
4391 case TARGET_F_SETFD:
4392 case TARGET_F_GETFL:
4393 case TARGET_F_SETFL:
4394 return cmd;
4395 case TARGET_F_GETLK:
4396 return F_GETLK;
4397 case TARGET_F_SETLK:
4398 return F_SETLK;
4399 case TARGET_F_SETLKW:
4400 return F_SETLKW;
4401 case TARGET_F_GETOWN:
4402 return F_GETOWN;
4403 case TARGET_F_SETOWN:
4404 return F_SETOWN;
4405 case TARGET_F_GETSIG:
4406 return F_GETSIG;
4407 case TARGET_F_SETSIG:
4408 return F_SETSIG;
4409#if TARGET_ABI_BITS == 32
4410 case TARGET_F_GETLK64:
4411 return F_GETLK64;
4412 case TARGET_F_SETLK64:
4413 return F_SETLK64;
4414 case TARGET_F_SETLKW64:
4415 return F_SETLKW64;
4416#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004417 case TARGET_F_SETLEASE:
4418 return F_SETLEASE;
4419 case TARGET_F_GETLEASE:
4420 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004421#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004422 case TARGET_F_DUPFD_CLOEXEC:
4423 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004424#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004425 case TARGET_F_NOTIFY:
4426 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004427#ifdef F_GETOWN_EX
4428 case TARGET_F_GETOWN_EX:
4429 return F_GETOWN_EX;
4430#endif
4431#ifdef F_SETOWN_EX
4432 case TARGET_F_SETOWN_EX:
4433 return F_SETOWN_EX;
4434#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004435 default:
4436 return -TARGET_EINVAL;
4437 }
4438 return -TARGET_EINVAL;
4439}
4440
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004441#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4442static const bitmask_transtbl flock_tbl[] = {
4443 TRANSTBL_CONVERT(F_RDLCK),
4444 TRANSTBL_CONVERT(F_WRLCK),
4445 TRANSTBL_CONVERT(F_UNLCK),
4446 TRANSTBL_CONVERT(F_EXLCK),
4447 TRANSTBL_CONVERT(F_SHLCK),
4448 { 0, 0, 0, 0 }
4449};
4450
blueswir1992f48a2007-10-14 16:27:31 +00004451static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004452{
4453 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004454 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004455 struct flock64 fl64;
4456 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004457#ifdef F_GETOWN_EX
4458 struct f_owner_ex fox;
4459 struct target_f_owner_ex *target_fox;
4460#endif
blueswir1992f48a2007-10-14 16:27:31 +00004461 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004462 int host_cmd = target_to_host_fcntl_cmd(cmd);
4463
4464 if (host_cmd == -TARGET_EINVAL)
4465 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004466
bellard7775e9e2003-05-14 22:46:48 +00004467 switch(cmd) {
4468 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004469 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4470 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004471 fl.l_type =
4472 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004473 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004474 fl.l_start = tswapal(target_fl->l_start);
4475 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004476 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004477 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004478 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004479 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004480 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4481 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004482 target_fl->l_type =
4483 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004484 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004485 target_fl->l_start = tswapal(fl.l_start);
4486 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004487 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004488 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004489 }
4490 break;
ths3b46e622007-09-17 08:09:54 +00004491
bellard7775e9e2003-05-14 22:46:48 +00004492 case TARGET_F_SETLK:
4493 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004494 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4495 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004496 fl.l_type =
4497 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004498 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004499 fl.l_start = tswapal(target_fl->l_start);
4500 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004501 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004502 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004503 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004504 break;
ths3b46e622007-09-17 08:09:54 +00004505
bellard7775e9e2003-05-14 22:46:48 +00004506 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004507 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4508 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004509 fl64.l_type =
4510 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004511 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004512 fl64.l_start = tswap64(target_fl64->l_start);
4513 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004514 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004515 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004516 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004517 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004518 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4519 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004520 target_fl64->l_type =
4521 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004522 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004523 target_fl64->l_start = tswap64(fl64.l_start);
4524 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004525 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004526 unlock_user_struct(target_fl64, arg, 1);
4527 }
bellard9ee1fa22007-11-11 15:11:19 +00004528 break;
bellard7775e9e2003-05-14 22:46:48 +00004529 case TARGET_F_SETLK64:
4530 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004531 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4532 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004533 fl64.l_type =
4534 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004535 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004536 fl64.l_start = tswap64(target_fl64->l_start);
4537 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004538 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004539 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004540 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004541 break;
4542
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004543 case TARGET_F_GETFL:
4544 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004545 if (ret >= 0) {
4546 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4547 }
bellardffa65c32004-01-04 23:57:22 +00004548 break;
4549
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004550 case TARGET_F_SETFL:
4551 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4552 break;
4553
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004554#ifdef F_GETOWN_EX
4555 case TARGET_F_GETOWN_EX:
4556 ret = get_errno(fcntl(fd, host_cmd, &fox));
4557 if (ret >= 0) {
4558 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4559 return -TARGET_EFAULT;
4560 target_fox->type = tswap32(fox.type);
4561 target_fox->pid = tswap32(fox.pid);
4562 unlock_user_struct(target_fox, arg, 1);
4563 }
4564 break;
4565#endif
4566
4567#ifdef F_SETOWN_EX
4568 case TARGET_F_SETOWN_EX:
4569 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4570 return -TARGET_EFAULT;
4571 fox.type = tswap32(target_fox->type);
4572 fox.pid = tswap32(target_fox->pid);
4573 unlock_user_struct(target_fox, arg, 0);
4574 ret = get_errno(fcntl(fd, host_cmd, &fox));
4575 break;
4576#endif
4577
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004578 case TARGET_F_SETOWN:
4579 case TARGET_F_GETOWN:
4580 case TARGET_F_SETSIG:
4581 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004582 case TARGET_F_SETLEASE:
4583 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004584 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004585 break;
4586
bellard7775e9e2003-05-14 22:46:48 +00004587 default:
bellard9ee1fa22007-11-11 15:11:19 +00004588 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004589 break;
4590 }
4591 return ret;
4592}
4593
bellard67867302003-11-23 17:05:30 +00004594#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004595
bellard67867302003-11-23 17:05:30 +00004596static inline int high2lowuid(int uid)
4597{
4598 if (uid > 65535)
4599 return 65534;
4600 else
4601 return uid;
4602}
4603
4604static inline int high2lowgid(int gid)
4605{
4606 if (gid > 65535)
4607 return 65534;
4608 else
4609 return gid;
4610}
4611
4612static inline int low2highuid(int uid)
4613{
4614 if ((int16_t)uid == -1)
4615 return -1;
4616 else
4617 return uid;
4618}
4619
4620static inline int low2highgid(int gid)
4621{
4622 if ((int16_t)gid == -1)
4623 return -1;
4624 else
4625 return gid;
4626}
Riku Voipio0c866a72011-04-18 15:23:06 +03004627static inline int tswapid(int id)
4628{
4629 return tswap16(id);
4630}
Peter Maydell76ca3102014-03-02 19:36:41 +00004631
4632#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4633
Riku Voipio0c866a72011-04-18 15:23:06 +03004634#else /* !USE_UID16 */
4635static inline int high2lowuid(int uid)
4636{
4637 return uid;
4638}
4639static inline int high2lowgid(int gid)
4640{
4641 return gid;
4642}
4643static inline int low2highuid(int uid)
4644{
4645 return uid;
4646}
4647static inline int low2highgid(int gid)
4648{
4649 return gid;
4650}
4651static inline int tswapid(int id)
4652{
4653 return tswap32(id);
4654}
Peter Maydell76ca3102014-03-02 19:36:41 +00004655
4656#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4657
bellard67867302003-11-23 17:05:30 +00004658#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004659
bellard31e31b82003-02-18 22:55:36 +00004660void syscall_init(void)
4661{
bellard2ab83ea2003-06-15 19:56:46 +00004662 IOCTLEntry *ie;
4663 const argtype *arg_type;
4664 int size;
thsb92c47c2007-11-01 00:07:38 +00004665 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004666
Blue Swirl001faf32009-05-13 17:53:17 +00004667#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004668#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004669#include "syscall_types.h"
4670#undef STRUCT
4671#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004672
Peter Maydelldd6e9572012-07-23 08:07:22 +00004673 /* Build target_to_host_errno_table[] table from
4674 * host_to_target_errno_table[]. */
4675 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4676 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4677 }
4678
bellard2ab83ea2003-06-15 19:56:46 +00004679 /* we patch the ioctl size if necessary. We rely on the fact that
4680 no ioctl has all the bits at '1' in the size field */
4681 ie = ioctl_entries;
4682 while (ie->target_cmd != 0) {
4683 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4684 TARGET_IOC_SIZEMASK) {
4685 arg_type = ie->arg_type;
4686 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004687 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004688 ie->target_cmd);
4689 exit(1);
4690 }
4691 arg_type++;
4692 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004693 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004694 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4695 (size << TARGET_IOC_SIZESHIFT);
4696 }
thsb92c47c2007-11-01 00:07:38 +00004697
bellard2ab83ea2003-06-15 19:56:46 +00004698 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004699#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4700 (defined(__x86_64__) && defined(TARGET_X86_64))
4701 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4702 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4703 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004704 }
4705#endif
4706 ie++;
4707 }
bellard31e31b82003-02-18 22:55:36 +00004708}
bellardc573ff62004-01-04 15:51:36 +00004709
blueswir1992f48a2007-10-14 16:27:31 +00004710#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004711static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4712{
thsaf325d32008-06-10 15:29:15 +00004713#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004714 return ((uint64_t)word0 << 32) | word1;
4715#else
4716 return ((uint64_t)word1 << 32) | word0;
4717#endif
4718}
blueswir1992f48a2007-10-14 16:27:31 +00004719#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004720static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4721{
4722 return word0;
4723}
blueswir1992f48a2007-10-14 16:27:31 +00004724#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004725
4726#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004727static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4728 abi_long arg2,
4729 abi_long arg3,
4730 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004731{
Riku Voipio48e515d2011-07-12 15:40:51 +03004732 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004733 arg2 = arg3;
4734 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004735 }
pbrookce4defa2006-02-09 16:49:55 +00004736 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4737}
4738#endif
4739
4740#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004741static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4742 abi_long arg2,
4743 abi_long arg3,
4744 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004745{
Riku Voipio48e515d2011-07-12 15:40:51 +03004746 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004747 arg2 = arg3;
4748 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004749 }
pbrookce4defa2006-02-09 16:49:55 +00004750 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4751}
4752#endif
4753
bellard579a97f2007-11-11 14:26:47 +00004754static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4755 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004756{
4757 struct target_timespec *target_ts;
4758
bellard579a97f2007-11-11 14:26:47 +00004759 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4760 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004761 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4762 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004763 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004764 return 0;
pbrook53a59602006-03-25 19:31:22 +00004765}
4766
bellard579a97f2007-11-11 14:26:47 +00004767static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4768 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004769{
4770 struct target_timespec *target_ts;
4771
bellard579a97f2007-11-11 14:26:47 +00004772 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4773 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004774 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4775 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004776 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004777 return 0;
pbrook53a59602006-03-25 19:31:22 +00004778}
4779
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004780static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4781 abi_ulong target_addr)
4782{
4783 struct target_itimerspec *target_itspec;
4784
4785 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4786 return -TARGET_EFAULT;
4787 }
4788
4789 host_itspec->it_interval.tv_sec =
4790 tswapal(target_itspec->it_interval.tv_sec);
4791 host_itspec->it_interval.tv_nsec =
4792 tswapal(target_itspec->it_interval.tv_nsec);
4793 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4794 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4795
4796 unlock_user_struct(target_itspec, target_addr, 1);
4797 return 0;
4798}
4799
4800static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4801 struct itimerspec *host_its)
4802{
4803 struct target_itimerspec *target_itspec;
4804
4805 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4806 return -TARGET_EFAULT;
4807 }
4808
4809 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4810 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4811
4812 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4813 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4814
4815 unlock_user_struct(target_itspec, target_addr, 0);
4816 return 0;
4817}
4818
aurel329d33b762009-04-08 23:07:05 +00004819#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004820static inline abi_long host_to_target_stat64(void *cpu_env,
4821 abi_ulong target_addr,
4822 struct stat *host_st)
4823{
Alexander Graf09701192013-09-03 20:12:15 +01004824#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004825 if (((CPUARMState *)cpu_env)->eabi) {
4826 struct target_eabi_stat64 *target_st;
4827
4828 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4829 return -TARGET_EFAULT;
4830 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4831 __put_user(host_st->st_dev, &target_st->st_dev);
4832 __put_user(host_st->st_ino, &target_st->st_ino);
4833#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4834 __put_user(host_st->st_ino, &target_st->__st_ino);
4835#endif
4836 __put_user(host_st->st_mode, &target_st->st_mode);
4837 __put_user(host_st->st_nlink, &target_st->st_nlink);
4838 __put_user(host_st->st_uid, &target_st->st_uid);
4839 __put_user(host_st->st_gid, &target_st->st_gid);
4840 __put_user(host_st->st_rdev, &target_st->st_rdev);
4841 __put_user(host_st->st_size, &target_st->st_size);
4842 __put_user(host_st->st_blksize, &target_st->st_blksize);
4843 __put_user(host_st->st_blocks, &target_st->st_blocks);
4844 __put_user(host_st->st_atime, &target_st->target_st_atime);
4845 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4846 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4847 unlock_user_struct(target_st, target_addr, 1);
4848 } else
4849#endif
4850 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004851#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004852 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004853#else
4854 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004855#endif
balrog6a24a772008-09-20 02:23:36 +00004856
4857 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4858 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004859 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004860 __put_user(host_st->st_dev, &target_st->st_dev);
4861 __put_user(host_st->st_ino, &target_st->st_ino);
4862#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4863 __put_user(host_st->st_ino, &target_st->__st_ino);
4864#endif
4865 __put_user(host_st->st_mode, &target_st->st_mode);
4866 __put_user(host_st->st_nlink, &target_st->st_nlink);
4867 __put_user(host_st->st_uid, &target_st->st_uid);
4868 __put_user(host_st->st_gid, &target_st->st_gid);
4869 __put_user(host_st->st_rdev, &target_st->st_rdev);
4870 /* XXX: better use of kernel struct */
4871 __put_user(host_st->st_size, &target_st->st_size);
4872 __put_user(host_st->st_blksize, &target_st->st_blksize);
4873 __put_user(host_st->st_blocks, &target_st->st_blocks);
4874 __put_user(host_st->st_atime, &target_st->target_st_atime);
4875 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4876 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4877 unlock_user_struct(target_st, target_addr, 1);
4878 }
4879
4880 return 0;
4881}
4882#endif
4883
pbrookbd0c5662008-05-29 14:34:11 +00004884/* ??? Using host futex calls even when target atomic operations
4885 are not really atomic probably breaks things. However implementing
4886 futexes locally would make futexes shared between multiple processes
4887 tricky. However they're probably useless because guest atomic
4888 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004889static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4890 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004891{
4892 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004893 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004894
4895 /* ??? We assume FUTEX_* constants are the same on both host
4896 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004897#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004898 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004899#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004900 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004901#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004902 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004903 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004904 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004905 if (timeout) {
4906 pts = &ts;
4907 target_to_host_timespec(pts, timeout);
4908 } else {
4909 pts = NULL;
4910 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004911 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004912 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004913 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004914 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004915 case FUTEX_FD:
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_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004918 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004919 case FUTEX_WAKE_OP:
4920 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4921 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4922 But the prototype takes a `struct timespec *'; insert casts
4923 to satisfy the compiler. We do not need to tswap TIMEOUT
4924 since it's not compared to guest memory. */
4925 pts = (struct timespec *)(uintptr_t) timeout;
4926 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4927 g2h(uaddr2),
4928 (base_op == FUTEX_CMP_REQUEUE
4929 ? tswap32(val3)
4930 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004931 default:
4932 return -TARGET_ENOSYS;
4933 }
4934}
pbrookbd0c5662008-05-29 14:34:11 +00004935
pbrook1d9d8b52009-04-16 15:17:02 +00004936/* Map host to target signal numbers for the wait family of syscalls.
4937 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004938int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004939{
4940 if (WIFSIGNALED(status)) {
4941 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4942 }
4943 if (WIFSTOPPED(status)) {
4944 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4945 | (status & 0xff);
4946 }
4947 return status;
4948}
4949
Alexander Graf36c08d42011-11-02 20:23:24 +01004950static int open_self_maps(void *cpu_env, int fd)
4951{
Alexander Graf1a49ef22012-05-01 16:30:28 +01004952#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber0429a972013-08-26 18:14:44 +02004953 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
4954 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01004955#endif
4956 FILE *fp;
4957 char *line = NULL;
4958 size_t len = 0;
4959 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01004960
Alexander Graf1a49ef22012-05-01 16:30:28 +01004961 fp = fopen("/proc/self/maps", "r");
4962 if (fp == NULL) {
4963 return -EACCES;
4964 }
4965
4966 while ((read = getline(&line, &len, fp)) != -1) {
4967 int fields, dev_maj, dev_min, inode;
4968 uint64_t min, max, offset;
4969 char flag_r, flag_w, flag_x, flag_p;
4970 char path[512] = "";
4971 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
4972 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
4973 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
4974
4975 if ((fields < 10) || (fields > 11)) {
4976 continue;
4977 }
4978 if (!strncmp(path, "[stack]", 7)) {
4979 continue;
4980 }
4981 if (h2g_valid(min) && h2g_valid(max)) {
4982 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02004983 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01004984 h2g(min), h2g(max), flag_r, flag_w,
4985 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02004986 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01004987 }
4988 }
4989
4990 free(line);
4991 fclose(fp);
4992
4993#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01004994 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
4995 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02004996 (unsigned long long)(ts->info->start_stack +
4997 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01004998 (unsigned long long)0);
4999#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005000
5001 return 0;
5002}
5003
Alexander Graf480b8e72011-11-02 20:23:25 +01005004static int open_self_stat(void *cpu_env, int fd)
5005{
Andreas Färber0429a972013-08-26 18:14:44 +02005006 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5007 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005008 abi_ulong start_stack = ts->info->start_stack;
5009 int i;
5010
5011 for (i = 0; i < 44; i++) {
5012 char buf[128];
5013 int len;
5014 uint64_t val = 0;
5015
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005016 if (i == 0) {
5017 /* pid */
5018 val = getpid();
5019 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5020 } else if (i == 1) {
5021 /* app name */
5022 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5023 } else if (i == 27) {
5024 /* stack bottom */
5025 val = start_stack;
5026 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5027 } else {
5028 /* for the rest, there is MasterCard */
5029 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005030 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005031
Alexander Graf480b8e72011-11-02 20:23:25 +01005032 len = strlen(buf);
5033 if (write(fd, buf, len) != len) {
5034 return -1;
5035 }
5036 }
5037
5038 return 0;
5039}
5040
Alexander Graf257450e2011-11-02 20:23:26 +01005041static int open_self_auxv(void *cpu_env, int fd)
5042{
Andreas Färber0429a972013-08-26 18:14:44 +02005043 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5044 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005045 abi_ulong auxv = ts->info->saved_auxv;
5046 abi_ulong len = ts->info->auxv_len;
5047 char *ptr;
5048
5049 /*
5050 * Auxiliary vector is stored in target process stack.
5051 * read in whole auxv vector and copy it to file
5052 */
5053 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5054 if (ptr != NULL) {
5055 while (len > 0) {
5056 ssize_t r;
5057 r = write(fd, ptr, len);
5058 if (r <= 0) {
5059 break;
5060 }
5061 len -= r;
5062 ptr += r;
5063 }
5064 lseek(fd, 0, SEEK_SET);
5065 unlock_user(ptr, auxv, len);
5066 }
5067
5068 return 0;
5069}
5070
Andreas Schwab463d8e72013-07-02 14:04:12 +01005071static int is_proc_myself(const char *filename, const char *entry)
5072{
5073 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5074 filename += strlen("/proc/");
5075 if (!strncmp(filename, "self/", strlen("self/"))) {
5076 filename += strlen("self/");
5077 } else if (*filename >= '1' && *filename <= '9') {
5078 char myself[80];
5079 snprintf(myself, sizeof(myself), "%d/", getpid());
5080 if (!strncmp(filename, myself, strlen(myself))) {
5081 filename += strlen(myself);
5082 } else {
5083 return 0;
5084 }
5085 } else {
5086 return 0;
5087 }
5088 if (!strcmp(filename, entry)) {
5089 return 1;
5090 }
5091 }
5092 return 0;
5093}
5094
Laurent Vivierde6b9932013-08-30 01:46:40 +02005095#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5096static int is_proc(const char *filename, const char *entry)
5097{
5098 return strcmp(filename, entry) == 0;
5099}
5100
5101static int open_net_route(void *cpu_env, int fd)
5102{
5103 FILE *fp;
5104 char *line = NULL;
5105 size_t len = 0;
5106 ssize_t read;
5107
5108 fp = fopen("/proc/net/route", "r");
5109 if (fp == NULL) {
5110 return -EACCES;
5111 }
5112
5113 /* read header */
5114
5115 read = getline(&line, &len, fp);
5116 dprintf(fd, "%s", line);
5117
5118 /* read routes */
5119
5120 while ((read = getline(&line, &len, fp)) != -1) {
5121 char iface[16];
5122 uint32_t dest, gw, mask;
5123 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5124 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5125 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5126 &mask, &mtu, &window, &irtt);
5127 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5128 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5129 metric, tswap32(mask), mtu, window, irtt);
5130 }
5131
5132 free(line);
5133 fclose(fp);
5134
5135 return 0;
5136}
5137#endif
5138
Alexander Graf3be14d02011-11-02 20:23:23 +01005139static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5140{
5141 struct fake_open {
5142 const char *filename;
5143 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005144 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005145 };
5146 const struct fake_open *fake_open;
5147 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005148 { "maps", open_self_maps, is_proc_myself },
5149 { "stat", open_self_stat, is_proc_myself },
5150 { "auxv", open_self_auxv, is_proc_myself },
5151#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5152 { "/proc/net/route", open_net_route, is_proc },
5153#endif
5154 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005155 };
5156
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005157 if (is_proc_myself(pathname, "exe")) {
5158 int execfd = qemu_getauxval(AT_EXECFD);
5159 return execfd ? execfd : get_errno(open(exec_path, flags, mode));
5160 }
5161
Alexander Graf3be14d02011-11-02 20:23:23 +01005162 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005163 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005164 break;
5165 }
5166 }
5167
5168 if (fake_open->filename) {
5169 const char *tmpdir;
5170 char filename[PATH_MAX];
5171 int fd, r;
5172
5173 /* create temporary file to map stat to */
5174 tmpdir = getenv("TMPDIR");
5175 if (!tmpdir)
5176 tmpdir = "/tmp";
5177 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5178 fd = mkstemp(filename);
5179 if (fd < 0) {
5180 return fd;
5181 }
5182 unlink(filename);
5183
5184 if ((r = fake_open->fill(cpu_env, fd))) {
5185 close(fd);
5186 return r;
5187 }
5188 lseek(fd, 0, SEEK_SET);
5189
5190 return fd;
5191 }
5192
5193 return get_errno(open(path(pathname), flags, mode));
5194}
5195
ths0da46a62007-10-20 20:23:07 +00005196/* do_syscall() should always have a single exit point at the end so
5197 that actions, such as logging of syscall results, can be performed.
5198 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005199abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5200 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005201 abi_long arg5, abi_long arg6, abi_long arg7,
5202 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005203{
Andreas Färber182735e2013-05-29 22:29:20 +02005204 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005205 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005206 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005207 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005208 void *p;
ths3b46e622007-09-17 08:09:54 +00005209
bellard72f03902003-02-18 23:33:18 +00005210#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005211 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005212#endif
thsb92c47c2007-11-01 00:07:38 +00005213 if(do_strace)
5214 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5215
bellard31e31b82003-02-18 22:55:36 +00005216 switch(num) {
5217 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005218 /* In old applications this may be used to implement _exit(2).
5219 However in threaded applictions it is used for thread termination,
5220 and _exit_group is used for application termination.
5221 Do thread termination if we have more then one thread. */
5222 /* FIXME: This probably breaks if a signal arrives. We should probably
5223 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005224 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005225 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005226
Andreas Färber9b056fc2013-06-24 23:53:10 +02005227 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005228 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005229 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005230 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005231 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005232 if (ts->child_tidptr) {
5233 put_user_u32(0, ts->child_tidptr);
5234 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5235 NULL, NULL, 0);
5236 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005237 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005238 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005239 g_free(ts);
5240 pthread_exit(NULL);
5241 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005242#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005243 _mcleanup();
5244#endif
bellarde9009672005-04-26 20:42:36 +00005245 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005246 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005247 ret = 0; /* avoid warning */
5248 break;
5249 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005250 if (arg3 == 0)
5251 ret = 0;
5252 else {
5253 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5254 goto efault;
5255 ret = get_errno(read(arg1, p, arg3));
5256 unlock_user(p, arg2, ret);
5257 }
bellard31e31b82003-02-18 22:55:36 +00005258 break;
5259 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005260 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5261 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005262 ret = get_errno(write(arg1, p, arg3));
5263 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005264 break;
5265 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005266 if (!(p = lock_user_string(arg1)))
5267 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005268 ret = get_errno(do_open(cpu_env, p,
5269 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5270 arg3));
pbrook53a59602006-03-25 19:31:22 +00005271 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005272 break;
ths82424832007-09-24 09:21:55 +00005273#if defined(TARGET_NR_openat) && defined(__NR_openat)
5274 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005275 if (!(p = lock_user_string(arg2)))
5276 goto efault;
5277 ret = get_errno(sys_openat(arg1,
5278 path(p),
5279 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5280 arg4));
5281 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005282 break;
5283#endif
bellard31e31b82003-02-18 22:55:36 +00005284 case TARGET_NR_close:
5285 ret = get_errno(close(arg1));
5286 break;
5287 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005288 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005289 break;
5290 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005291 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005292 break;
thse5febef2007-04-01 18:31:35 +00005293#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005294 case TARGET_NR_waitpid:
5295 {
pbrook53a59602006-03-25 19:31:22 +00005296 int status;
5297 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005298 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005299 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005300 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005301 }
5302 break;
thse5febef2007-04-01 18:31:35 +00005303#endif
pbrookf0cbb612008-05-30 18:20:05 +00005304#ifdef TARGET_NR_waitid
5305 case TARGET_NR_waitid:
5306 {
5307 siginfo_t info;
5308 info.si_pid = 0;
5309 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5310 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005311 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005312 goto efault;
5313 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005314 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005315 }
5316 }
5317 break;
5318#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005319#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005320 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005321 if (!(p = lock_user_string(arg1)))
5322 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005323 ret = get_errno(creat(p, arg2));
5324 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005325 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005326#endif
bellard31e31b82003-02-18 22:55:36 +00005327 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005328 {
5329 void * p2;
5330 p = lock_user_string(arg1);
5331 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005332 if (!p || !p2)
5333 ret = -TARGET_EFAULT;
5334 else
5335 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005336 unlock_user(p2, arg2, 0);
5337 unlock_user(p, arg1, 0);
5338 }
bellard31e31b82003-02-18 22:55:36 +00005339 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005340#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005341 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005342 {
5343 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005344 if (!arg2 || !arg4)
5345 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005346 p = lock_user_string(arg2);
5347 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005348 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005349 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005350 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005351 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005352 unlock_user(p, arg2, 0);
5353 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005354 }
5355 break;
5356#endif
bellard31e31b82003-02-18 22:55:36 +00005357 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005358 if (!(p = lock_user_string(arg1)))
5359 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005360 ret = get_errno(unlink(p));
5361 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005362 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005363#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005364 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005365 if (!(p = lock_user_string(arg2)))
5366 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005367 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005368 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005369 break;
balrogb7d35e62007-12-12 00:40:24 +00005370#endif
bellard31e31b82003-02-18 22:55:36 +00005371 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005372 {
5373 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005374 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005375 abi_ulong gp;
5376 abi_ulong guest_argp;
5377 abi_ulong guest_envp;
5378 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005379 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005380 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005381
bellardf7341ff2003-03-30 21:00:25 +00005382 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005383 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005384 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005385 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005386 goto efault;
ths03aa1972007-12-02 06:28:08 +00005387 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005388 break;
bellard7854b052003-03-29 17:22:23 +00005389 argc++;
bellard2f619692007-11-16 10:46:05 +00005390 }
bellardf7341ff2003-03-30 21:00:25 +00005391 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005392 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005393 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005394 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005395 goto efault;
ths03aa1972007-12-02 06:28:08 +00005396 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005397 break;
bellard7854b052003-03-29 17:22:23 +00005398 envc++;
bellard2f619692007-11-16 10:46:05 +00005399 }
bellard7854b052003-03-29 17:22:23 +00005400
bellardf7341ff2003-03-30 21:00:25 +00005401 argp = alloca((argc + 1) * sizeof(void *));
5402 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005403
pbrookda94d262008-05-30 18:24:00 +00005404 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005405 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005406 if (get_user_ual(addr, gp))
5407 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005408 if (!addr)
5409 break;
bellard2f619692007-11-16 10:46:05 +00005410 if (!(*q = lock_user_string(addr)))
5411 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005412 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005413 }
bellardf7341ff2003-03-30 21:00:25 +00005414 *q = NULL;
5415
pbrookda94d262008-05-30 18:24:00 +00005416 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005417 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005418 if (get_user_ual(addr, gp))
5419 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005420 if (!addr)
5421 break;
bellard2f619692007-11-16 10:46:05 +00005422 if (!(*q = lock_user_string(addr)))
5423 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005424 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005425 }
bellardf7341ff2003-03-30 21:00:25 +00005426 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005427
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005428 /* This case will not be caught by the host's execve() if its
5429 page size is bigger than the target's. */
5430 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5431 ret = -TARGET_E2BIG;
5432 goto execve_end;
5433 }
bellard2f619692007-11-16 10:46:05 +00005434 if (!(p = lock_user_string(arg1)))
5435 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005436 ret = get_errno(execve(p, argp, envp));
5437 unlock_user(p, arg1, 0);
5438
bellard2f619692007-11-16 10:46:05 +00005439 goto execve_end;
5440
5441 execve_efault:
5442 ret = -TARGET_EFAULT;
5443
5444 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005445 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005446 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005447 if (get_user_ual(addr, gp)
5448 || !addr)
5449 break;
pbrook53a59602006-03-25 19:31:22 +00005450 unlock_user(*q, addr, 0);
5451 }
5452 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005453 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005454 if (get_user_ual(addr, gp)
5455 || !addr)
5456 break;
pbrook53a59602006-03-25 19:31:22 +00005457 unlock_user(*q, addr, 0);
5458 }
bellard7854b052003-03-29 17:22:23 +00005459 }
bellard31e31b82003-02-18 22:55:36 +00005460 break;
5461 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005462 if (!(p = lock_user_string(arg1)))
5463 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005464 ret = get_errno(chdir(p));
5465 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005466 break;
bellarda315a142005-01-30 22:59:18 +00005467#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005468 case TARGET_NR_time:
5469 {
pbrook53a59602006-03-25 19:31:22 +00005470 time_t host_time;
5471 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005472 if (!is_error(ret)
5473 && arg1
5474 && put_user_sal(host_time, arg1))
5475 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005476 }
5477 break;
bellarda315a142005-01-30 22:59:18 +00005478#endif
bellard31e31b82003-02-18 22:55:36 +00005479 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005480 if (!(p = lock_user_string(arg1)))
5481 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005482 ret = get_errno(mknod(p, arg2, arg3));
5483 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005484 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005485#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005486 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005487 if (!(p = lock_user_string(arg2)))
5488 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005489 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005490 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005491 break;
5492#endif
bellard31e31b82003-02-18 22:55:36 +00005493 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005494 if (!(p = lock_user_string(arg1)))
5495 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005496 ret = get_errno(chmod(p, arg2));
5497 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005498 break;
bellardebc05482003-09-30 21:08:41 +00005499#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005500 case TARGET_NR_break:
5501 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005502#endif
5503#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005504 case TARGET_NR_oldstat:
5505 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005506#endif
bellard31e31b82003-02-18 22:55:36 +00005507 case TARGET_NR_lseek:
5508 ret = get_errno(lseek(arg1, arg2, arg3));
5509 break;
Richard Henderson92317332010-05-03 10:07:53 -07005510#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5511 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005512 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005513 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005514 ret = get_errno(getpid());
5515 break;
Richard Henderson92317332010-05-03 10:07:53 -07005516#endif
5517#ifdef TARGET_NR_getpid
5518 case TARGET_NR_getpid:
5519 ret = get_errno(getpid());
5520 break;
5521#endif
bellard31e31b82003-02-18 22:55:36 +00005522 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005523 {
5524 /* need to look at the data field */
5525 void *p2, *p3;
5526 p = lock_user_string(arg1);
5527 p2 = lock_user_string(arg2);
5528 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005529 if (!p || !p2 || !p3)
5530 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005531 else {
bellard579a97f2007-11-11 14:26:47 +00005532 /* FIXME - arg5 should be locked, but it isn't clear how to
5533 * do that since it's not guaranteed to be a NULL-terminated
5534 * string.
5535 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005536 if ( ! arg5 )
5537 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5538 else
5539 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5540 }
bellard579a97f2007-11-11 14:26:47 +00005541 unlock_user(p, arg1, 0);
5542 unlock_user(p2, arg2, 0);
5543 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005544 break;
5545 }
thse5febef2007-04-01 18:31:35 +00005546#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005547 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005548 if (!(p = lock_user_string(arg1)))
5549 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005550 ret = get_errno(umount(p));
5551 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005552 break;
thse5febef2007-04-01 18:31:35 +00005553#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005554#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005555 case TARGET_NR_stime:
5556 {
pbrook53a59602006-03-25 19:31:22 +00005557 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005558 if (get_user_sal(host_time, arg1))
5559 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005560 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005561 }
5562 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005563#endif
bellard31e31b82003-02-18 22:55:36 +00005564 case TARGET_NR_ptrace:
5565 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005566#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005567 case TARGET_NR_alarm:
5568 ret = alarm(arg1);
5569 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005570#endif
bellardebc05482003-09-30 21:08:41 +00005571#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005572 case TARGET_NR_oldfstat:
5573 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005574#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005575#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005576 case TARGET_NR_pause:
5577 ret = get_errno(pause());
5578 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005579#endif
thse5febef2007-04-01 18:31:35 +00005580#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005581 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005582 {
pbrook53a59602006-03-25 19:31:22 +00005583 struct utimbuf tbuf, *host_tbuf;
5584 struct target_utimbuf *target_tbuf;
5585 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005586 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5587 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005588 tbuf.actime = tswapal(target_tbuf->actime);
5589 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005590 unlock_user_struct(target_tbuf, arg2, 0);
5591 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005592 } else {
pbrook53a59602006-03-25 19:31:22 +00005593 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005594 }
bellard579a97f2007-11-11 14:26:47 +00005595 if (!(p = lock_user_string(arg1)))
5596 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005597 ret = get_errno(utime(p, host_tbuf));
5598 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005599 }
5600 break;
thse5febef2007-04-01 18:31:35 +00005601#endif
bellard978a66f2004-12-06 22:58:05 +00005602 case TARGET_NR_utimes:
5603 {
bellard978a66f2004-12-06 22:58:05 +00005604 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005605 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005606 if (copy_from_user_timeval(&tv[0], arg2)
5607 || copy_from_user_timeval(&tv[1],
5608 arg2 + sizeof(struct target_timeval)))
5609 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005610 tvp = tv;
5611 } else {
5612 tvp = NULL;
5613 }
bellard579a97f2007-11-11 14:26:47 +00005614 if (!(p = lock_user_string(arg1)))
5615 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005616 ret = get_errno(utimes(p, tvp));
5617 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005618 }
5619 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005620#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005621 case TARGET_NR_futimesat:
5622 {
5623 struct timeval *tvp, tv[2];
5624 if (arg3) {
5625 if (copy_from_user_timeval(&tv[0], arg3)
5626 || copy_from_user_timeval(&tv[1],
5627 arg3 + sizeof(struct target_timeval)))
5628 goto efault;
5629 tvp = tv;
5630 } else {
5631 tvp = NULL;
5632 }
5633 if (!(p = lock_user_string(arg2)))
5634 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005635 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005636 unlock_user(p, arg2, 0);
5637 }
5638 break;
5639#endif
bellardebc05482003-09-30 21:08:41 +00005640#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005641 case TARGET_NR_stty:
5642 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005643#endif
5644#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005645 case TARGET_NR_gtty:
5646 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005647#endif
bellard31e31b82003-02-18 22:55:36 +00005648 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005649 if (!(p = lock_user_string(arg1)))
5650 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005651 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005652 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005653 break;
ths92a34c12007-09-24 09:27:49 +00005654#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5655 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005656 if (!(p = lock_user_string(arg2)))
5657 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005658 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005659 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005660 break;
5661#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005662#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005663 case TARGET_NR_nice:
5664 ret = get_errno(nice(arg1));
5665 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005666#endif
bellardebc05482003-09-30 21:08:41 +00005667#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005668 case TARGET_NR_ftime:
5669 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005670#endif
bellard31e31b82003-02-18 22:55:36 +00005671 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005672 sync();
5673 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005674 break;
5675 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005676 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005677 break;
5678 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005679 {
5680 void *p2;
5681 p = lock_user_string(arg1);
5682 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005683 if (!p || !p2)
5684 ret = -TARGET_EFAULT;
5685 else
5686 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005687 unlock_user(p2, arg2, 0);
5688 unlock_user(p, arg1, 0);
5689 }
bellard31e31b82003-02-18 22:55:36 +00005690 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005691#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005692 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005693 {
bellard579a97f2007-11-11 14:26:47 +00005694 void *p2;
ths722183f2007-09-24 09:24:37 +00005695 p = lock_user_string(arg2);
5696 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005697 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005698 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005699 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005700 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005701 unlock_user(p2, arg4, 0);
5702 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005703 }
5704 break;
5705#endif
bellard31e31b82003-02-18 22:55:36 +00005706 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005707 if (!(p = lock_user_string(arg1)))
5708 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005709 ret = get_errno(mkdir(p, arg2));
5710 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005711 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005712#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005713 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005714 if (!(p = lock_user_string(arg2)))
5715 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005716 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005717 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005718 break;
5719#endif
bellard31e31b82003-02-18 22:55:36 +00005720 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005721 if (!(p = lock_user_string(arg1)))
5722 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005723 ret = get_errno(rmdir(p));
5724 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005725 break;
5726 case TARGET_NR_dup:
5727 ret = get_errno(dup(arg1));
5728 break;
5729 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005730 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005731 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005732#ifdef TARGET_NR_pipe2
5733 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005734 ret = do_pipe(cpu_env, arg1,
5735 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005736 break;
5737#endif
bellard31e31b82003-02-18 22:55:36 +00005738 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005739 {
pbrook53a59602006-03-25 19:31:22 +00005740 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005741 struct tms tms;
5742 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005743 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005744 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5745 if (!tmsp)
5746 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005747 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5748 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5749 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5750 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005751 }
bellardc596ed12003-07-13 17:32:31 +00005752 if (!is_error(ret))
5753 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005754 }
5755 break;
bellardebc05482003-09-30 21:08:41 +00005756#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005757 case TARGET_NR_prof:
5758 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005759#endif
thse5febef2007-04-01 18:31:35 +00005760#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005761 case TARGET_NR_signal:
5762 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005763#endif
bellard31e31b82003-02-18 22:55:36 +00005764 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005765 if (arg1 == 0) {
5766 ret = get_errno(acct(NULL));
5767 } else {
5768 if (!(p = lock_user_string(arg1)))
5769 goto efault;
5770 ret = get_errno(acct(path(p)));
5771 unlock_user(p, arg1, 0);
5772 }
pbrook24836682006-04-16 14:14:53 +00005773 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005774#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005775 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005776 if (!(p = lock_user_string(arg1)))
5777 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005778 ret = get_errno(umount2(p, arg2));
5779 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005780 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005781#endif
bellardebc05482003-09-30 21:08:41 +00005782#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005783 case TARGET_NR_lock:
5784 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005785#endif
bellard31e31b82003-02-18 22:55:36 +00005786 case TARGET_NR_ioctl:
5787 ret = do_ioctl(arg1, arg2, arg3);
5788 break;
5789 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005790 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005791 break;
bellardebc05482003-09-30 21:08:41 +00005792#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005793 case TARGET_NR_mpx:
5794 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005795#endif
bellard31e31b82003-02-18 22:55:36 +00005796 case TARGET_NR_setpgid:
5797 ret = get_errno(setpgid(arg1, arg2));
5798 break;
bellardebc05482003-09-30 21:08:41 +00005799#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005800 case TARGET_NR_ulimit:
5801 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005802#endif
5803#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005804 case TARGET_NR_oldolduname:
5805 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005806#endif
bellard31e31b82003-02-18 22:55:36 +00005807 case TARGET_NR_umask:
5808 ret = get_errno(umask(arg1));
5809 break;
5810 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005811 if (!(p = lock_user_string(arg1)))
5812 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005813 ret = get_errno(chroot(p));
5814 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005815 break;
5816 case TARGET_NR_ustat:
5817 goto unimplemented;
5818 case TARGET_NR_dup2:
5819 ret = get_errno(dup2(arg1, arg2));
5820 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005821#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5822 case TARGET_NR_dup3:
5823 ret = get_errno(dup3(arg1, arg2, arg3));
5824 break;
5825#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005826#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005827 case TARGET_NR_getppid:
5828 ret = get_errno(getppid());
5829 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005830#endif
bellard31e31b82003-02-18 22:55:36 +00005831 case TARGET_NR_getpgrp:
5832 ret = get_errno(getpgrp());
5833 break;
5834 case TARGET_NR_setsid:
5835 ret = get_errno(setsid());
5836 break;
thse5febef2007-04-01 18:31:35 +00005837#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005838 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005839 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005840#if defined(TARGET_ALPHA)
5841 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005842 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005843 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005844 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5845 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005846 act._sa_handler = old_act->_sa_handler;
5847 target_siginitset(&act.sa_mask, old_act->sa_mask);
5848 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005849 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005850 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005851 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005852 }
5853 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005854 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005855 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5856 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005857 old_act->_sa_handler = oact._sa_handler;
5858 old_act->sa_mask = oact.sa_mask.sig[0];
5859 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005860 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005861 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005862#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005863 struct target_sigaction act, oact, *pact, *old_act;
5864
5865 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005866 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5867 goto efault;
bellard106ec872006-06-27 21:08:10 +00005868 act._sa_handler = old_act->_sa_handler;
5869 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5870 act.sa_flags = old_act->sa_flags;
5871 unlock_user_struct(old_act, arg2, 0);
5872 pact = &act;
5873 } else {
5874 pact = NULL;
5875 }
5876
5877 ret = get_errno(do_sigaction(arg1, pact, &oact));
5878
5879 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005880 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5881 goto efault;
bellard106ec872006-06-27 21:08:10 +00005882 old_act->_sa_handler = oact._sa_handler;
5883 old_act->sa_flags = oact.sa_flags;
5884 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5885 old_act->sa_mask.sig[1] = 0;
5886 old_act->sa_mask.sig[2] = 0;
5887 old_act->sa_mask.sig[3] = 0;
5888 unlock_user_struct(old_act, arg3, 1);
5889 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005890#else
5891 struct target_old_sigaction *old_act;
5892 struct target_sigaction act, oact, *pact;
5893 if (arg2) {
5894 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5895 goto efault;
5896 act._sa_handler = old_act->_sa_handler;
5897 target_siginitset(&act.sa_mask, old_act->sa_mask);
5898 act.sa_flags = old_act->sa_flags;
5899 act.sa_restorer = old_act->sa_restorer;
5900 unlock_user_struct(old_act, arg2, 0);
5901 pact = &act;
5902 } else {
5903 pact = NULL;
5904 }
5905 ret = get_errno(do_sigaction(arg1, pact, &oact));
5906 if (!is_error(ret) && arg3) {
5907 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5908 goto efault;
5909 old_act->_sa_handler = oact._sa_handler;
5910 old_act->sa_mask = oact.sa_mask.sig[0];
5911 old_act->sa_flags = oact.sa_flags;
5912 old_act->sa_restorer = oact.sa_restorer;
5913 unlock_user_struct(old_act, arg3, 1);
5914 }
ths388bb212007-05-13 13:58:00 +00005915#endif
bellard31e31b82003-02-18 22:55:36 +00005916 }
5917 break;
thse5febef2007-04-01 18:31:35 +00005918#endif
bellard66fb9762003-03-23 01:06:05 +00005919 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00005920 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005921#if defined(TARGET_ALPHA)
5922 struct target_sigaction act, oact, *pact = 0;
5923 struct target_rt_sigaction *rt_act;
5924 /* ??? arg4 == sizeof(sigset_t). */
5925 if (arg2) {
5926 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
5927 goto efault;
5928 act._sa_handler = rt_act->_sa_handler;
5929 act.sa_mask = rt_act->sa_mask;
5930 act.sa_flags = rt_act->sa_flags;
5931 act.sa_restorer = arg5;
5932 unlock_user_struct(rt_act, arg2, 0);
5933 pact = &act;
5934 }
5935 ret = get_errno(do_sigaction(arg1, pact, &oact));
5936 if (!is_error(ret) && arg3) {
5937 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
5938 goto efault;
5939 rt_act->_sa_handler = oact._sa_handler;
5940 rt_act->sa_mask = oact.sa_mask;
5941 rt_act->sa_flags = oact.sa_flags;
5942 unlock_user_struct(rt_act, arg3, 1);
5943 }
5944#else
pbrook53a59602006-03-25 19:31:22 +00005945 struct target_sigaction *act;
5946 struct target_sigaction *oact;
5947
bellard579a97f2007-11-11 14:26:47 +00005948 if (arg2) {
5949 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
5950 goto efault;
5951 } else
pbrook53a59602006-03-25 19:31:22 +00005952 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00005953 if (arg3) {
5954 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
5955 ret = -TARGET_EFAULT;
5956 goto rt_sigaction_fail;
5957 }
5958 } else
pbrook53a59602006-03-25 19:31:22 +00005959 oact = NULL;
5960 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00005961 rt_sigaction_fail:
5962 if (act)
pbrook53a59602006-03-25 19:31:22 +00005963 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00005964 if (oact)
pbrook53a59602006-03-25 19:31:22 +00005965 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005966#endif
pbrook53a59602006-03-25 19:31:22 +00005967 }
bellard66fb9762003-03-23 01:06:05 +00005968 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005969#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005970 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00005971 {
5972 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005973 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00005974 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00005975 host_to_target_old_sigset(&target_set, &cur_set);
5976 ret = target_set;
5977 }
5978 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005979#endif
5980#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005981 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00005982 {
5983 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00005984 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00005985 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00005986 target_to_host_old_sigset(&set, &target_set);
5987 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005988 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00005989 host_to_target_old_sigset(&target_set, &oset);
5990 ret = target_set;
5991 }
5992 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005993#endif
thse5febef2007-04-01 18:31:35 +00005994#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00005995 case TARGET_NR_sigprocmask:
5996 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07005997#if defined(TARGET_ALPHA)
5998 sigset_t set, oldset;
5999 abi_ulong mask;
6000 int how;
6001
6002 switch (arg1) {
6003 case TARGET_SIG_BLOCK:
6004 how = SIG_BLOCK;
6005 break;
6006 case TARGET_SIG_UNBLOCK:
6007 how = SIG_UNBLOCK;
6008 break;
6009 case TARGET_SIG_SETMASK:
6010 how = SIG_SETMASK;
6011 break;
6012 default:
6013 ret = -TARGET_EINVAL;
6014 goto fail;
6015 }
6016 mask = arg2;
6017 target_to_host_old_sigset(&set, &mask);
6018
Alex Barcelo1c275922014-03-14 14:36:55 +00006019 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006020 if (!is_error(ret)) {
6021 host_to_target_old_sigset(&mask, &oldset);
6022 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006023 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006024 }
6025#else
bellard66fb9762003-03-23 01:06:05 +00006026 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006027 int how;
ths3b46e622007-09-17 08:09:54 +00006028
pbrook53a59602006-03-25 19:31:22 +00006029 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006030 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006031 case TARGET_SIG_BLOCK:
6032 how = SIG_BLOCK;
6033 break;
6034 case TARGET_SIG_UNBLOCK:
6035 how = SIG_UNBLOCK;
6036 break;
6037 case TARGET_SIG_SETMASK:
6038 how = SIG_SETMASK;
6039 break;
6040 default:
ths0da46a62007-10-20 20:23:07 +00006041 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006042 goto fail;
6043 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006044 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006045 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006046 target_to_host_old_sigset(&set, p);
6047 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006048 set_ptr = &set;
6049 } else {
6050 how = 0;
6051 set_ptr = NULL;
6052 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006053 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006054 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006055 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006056 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006057 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006058 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006059 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006060#endif
bellard66fb9762003-03-23 01:06:05 +00006061 }
6062 break;
thse5febef2007-04-01 18:31:35 +00006063#endif
bellard66fb9762003-03-23 01:06:05 +00006064 case TARGET_NR_rt_sigprocmask:
6065 {
6066 int how = arg1;
6067 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006068
pbrook53a59602006-03-25 19:31:22 +00006069 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006070 switch(how) {
6071 case TARGET_SIG_BLOCK:
6072 how = SIG_BLOCK;
6073 break;
6074 case TARGET_SIG_UNBLOCK:
6075 how = SIG_UNBLOCK;
6076 break;
6077 case TARGET_SIG_SETMASK:
6078 how = SIG_SETMASK;
6079 break;
6080 default:
ths0da46a62007-10-20 20:23:07 +00006081 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006082 goto fail;
6083 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006084 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006085 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006086 target_to_host_sigset(&set, p);
6087 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006088 set_ptr = &set;
6089 } else {
6090 how = 0;
6091 set_ptr = NULL;
6092 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006093 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006094 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006095 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006096 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006097 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006098 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006099 }
6100 }
6101 break;
thse5febef2007-04-01 18:31:35 +00006102#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006103 case TARGET_NR_sigpending:
6104 {
6105 sigset_t set;
6106 ret = get_errno(sigpending(&set));
6107 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006108 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006109 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006110 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006111 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006112 }
6113 }
6114 break;
thse5febef2007-04-01 18:31:35 +00006115#endif
bellard66fb9762003-03-23 01:06:05 +00006116 case TARGET_NR_rt_sigpending:
6117 {
6118 sigset_t set;
6119 ret = get_errno(sigpending(&set));
6120 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006121 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006122 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006123 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006124 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006125 }
6126 }
6127 break;
thse5febef2007-04-01 18:31:35 +00006128#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006129 case TARGET_NR_sigsuspend:
6130 {
6131 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006132#if defined(TARGET_ALPHA)
6133 abi_ulong mask = arg1;
6134 target_to_host_old_sigset(&set, &mask);
6135#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006136 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006137 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006138 target_to_host_old_sigset(&set, p);
6139 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006140#endif
bellard66fb9762003-03-23 01:06:05 +00006141 ret = get_errno(sigsuspend(&set));
6142 }
6143 break;
thse5febef2007-04-01 18:31:35 +00006144#endif
bellard66fb9762003-03-23 01:06:05 +00006145 case TARGET_NR_rt_sigsuspend:
6146 {
6147 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006148 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006149 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006150 target_to_host_sigset(&set, p);
6151 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006152 ret = get_errno(sigsuspend(&set));
6153 }
6154 break;
6155 case TARGET_NR_rt_sigtimedwait:
6156 {
bellard66fb9762003-03-23 01:06:05 +00006157 sigset_t set;
6158 struct timespec uts, *puts;
6159 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006160
Anthony Liguoric227f092009-10-01 16:12:16 -05006161 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006162 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006163 target_to_host_sigset(&set, p);
6164 unlock_user(p, arg1, 0);
6165 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006166 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006167 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006168 } else {
6169 puts = NULL;
6170 }
6171 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006172 if (!is_error(ret)) {
6173 if (arg2) {
6174 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6175 0);
6176 if (!p) {
6177 goto efault;
6178 }
6179 host_to_target_siginfo(p, &uinfo);
6180 unlock_user(p, arg2, sizeof(target_siginfo_t));
6181 }
6182 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006183 }
6184 }
6185 break;
6186 case TARGET_NR_rt_sigqueueinfo:
6187 {
6188 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006189 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006190 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006191 target_to_host_siginfo(&uinfo, p);
6192 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006193 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6194 }
6195 break;
thse5febef2007-04-01 18:31:35 +00006196#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006197 case TARGET_NR_sigreturn:
6198 /* NOTE: ret is eax, so not transcoding must be done */
6199 ret = do_sigreturn(cpu_env);
6200 break;
thse5febef2007-04-01 18:31:35 +00006201#endif
bellard66fb9762003-03-23 01:06:05 +00006202 case TARGET_NR_rt_sigreturn:
6203 /* NOTE: ret is eax, so not transcoding must be done */
6204 ret = do_rt_sigreturn(cpu_env);
6205 break;
bellard31e31b82003-02-18 22:55:36 +00006206 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006207 if (!(p = lock_user_string(arg1)))
6208 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006209 ret = get_errno(sethostname(p, arg2));
6210 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006211 break;
6212 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006213 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006214 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006215 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006216 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006217 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6218 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006219 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6220 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006221 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006222 ret = get_errno(setrlimit(resource, &rlim));
6223 }
6224 break;
bellard31e31b82003-02-18 22:55:36 +00006225 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006226 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006227 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006228 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006229 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006230
bellard9de5e442003-03-23 16:49:39 +00006231 ret = get_errno(getrlimit(resource, &rlim));
6232 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006233 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6234 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006235 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6236 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006237 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006238 }
6239 }
6240 break;
bellard31e31b82003-02-18 22:55:36 +00006241 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006242 {
6243 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006244 ret = get_errno(getrusage(arg1, &rusage));
6245 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006246 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006247 }
6248 }
6249 break;
bellard31e31b82003-02-18 22:55:36 +00006250 case TARGET_NR_gettimeofday:
6251 {
bellard31e31b82003-02-18 22:55:36 +00006252 struct timeval tv;
6253 ret = get_errno(gettimeofday(&tv, NULL));
6254 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006255 if (copy_to_user_timeval(arg1, &tv))
6256 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006257 }
6258 }
6259 break;
6260 case TARGET_NR_settimeofday:
6261 {
bellard31e31b82003-02-18 22:55:36 +00006262 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006263 if (copy_from_user_timeval(&tv, arg1))
6264 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006265 ret = get_errno(settimeofday(&tv, NULL));
6266 }
6267 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006268#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006269 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006270#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6271 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6272#else
bellardf2674e32003-07-09 12:26:09 +00006273 {
pbrook53a59602006-03-25 19:31:22 +00006274 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006275 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006276 long nsel;
6277
bellard579a97f2007-11-11 14:26:47 +00006278 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6279 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006280 nsel = tswapal(sel->n);
6281 inp = tswapal(sel->inp);
6282 outp = tswapal(sel->outp);
6283 exp = tswapal(sel->exp);
6284 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006285 unlock_user_struct(sel, arg1, 0);
6286 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006287 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006288#endif
bellardf2674e32003-07-09 12:26:09 +00006289 break;
bellard048f6b42005-11-26 18:47:20 +00006290#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006291#ifdef TARGET_NR_pselect6
6292 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006293 {
6294 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6295 fd_set rfds, wfds, efds;
6296 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6297 struct timespec ts, *ts_ptr;
6298
6299 /*
6300 * The 6th arg is actually two args smashed together,
6301 * so we cannot use the C library.
6302 */
6303 sigset_t set;
6304 struct {
6305 sigset_t *set;
6306 size_t size;
6307 } sig, *sig_ptr;
6308
6309 abi_ulong arg_sigset, arg_sigsize, *arg7;
6310 target_sigset_t *target_sigset;
6311
6312 n = arg1;
6313 rfd_addr = arg2;
6314 wfd_addr = arg3;
6315 efd_addr = arg4;
6316 ts_addr = arg5;
6317
6318 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6319 if (ret) {
6320 goto fail;
6321 }
6322 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6323 if (ret) {
6324 goto fail;
6325 }
6326 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6327 if (ret) {
6328 goto fail;
6329 }
6330
6331 /*
6332 * This takes a timespec, and not a timeval, so we cannot
6333 * use the do_select() helper ...
6334 */
6335 if (ts_addr) {
6336 if (target_to_host_timespec(&ts, ts_addr)) {
6337 goto efault;
6338 }
6339 ts_ptr = &ts;
6340 } else {
6341 ts_ptr = NULL;
6342 }
6343
6344 /* Extract the two packed args for the sigset */
6345 if (arg6) {
6346 sig_ptr = &sig;
6347 sig.size = _NSIG / 8;
6348
6349 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6350 if (!arg7) {
6351 goto efault;
6352 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006353 arg_sigset = tswapal(arg7[0]);
6354 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006355 unlock_user(arg7, arg6, 0);
6356
6357 if (arg_sigset) {
6358 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006359 if (arg_sigsize != sizeof(*target_sigset)) {
6360 /* Like the kernel, we enforce correct size sigsets */
6361 ret = -TARGET_EINVAL;
6362 goto fail;
6363 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006364 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6365 sizeof(*target_sigset), 1);
6366 if (!target_sigset) {
6367 goto efault;
6368 }
6369 target_to_host_sigset(&set, target_sigset);
6370 unlock_user(target_sigset, arg_sigset, 0);
6371 } else {
6372 sig.set = NULL;
6373 }
6374 } else {
6375 sig_ptr = NULL;
6376 }
6377
6378 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6379 ts_ptr, sig_ptr));
6380
6381 if (!is_error(ret)) {
6382 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6383 goto efault;
6384 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6385 goto efault;
6386 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6387 goto efault;
6388
6389 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6390 goto efault;
6391 }
6392 }
6393 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006394#endif
bellard31e31b82003-02-18 22:55:36 +00006395 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006396 {
6397 void *p2;
6398 p = lock_user_string(arg1);
6399 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006400 if (!p || !p2)
6401 ret = -TARGET_EFAULT;
6402 else
6403 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006404 unlock_user(p2, arg2, 0);
6405 unlock_user(p, arg1, 0);
6406 }
bellard31e31b82003-02-18 22:55:36 +00006407 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006408#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006409 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006410 {
bellard579a97f2007-11-11 14:26:47 +00006411 void *p2;
thsf0b62432007-09-24 09:25:40 +00006412 p = lock_user_string(arg1);
6413 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006414 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006415 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006416 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006417 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006418 unlock_user(p2, arg3, 0);
6419 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006420 }
6421 break;
6422#endif
bellardebc05482003-09-30 21:08:41 +00006423#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006424 case TARGET_NR_oldlstat:
6425 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006426#endif
bellard31e31b82003-02-18 22:55:36 +00006427 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006428 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006429 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006430 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006431 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006432 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006433 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006434 } else if (is_proc_myself((const char *)p, "exe")) {
6435 char real[PATH_MAX], *temp;
6436 temp = realpath(exec_path, real);
6437 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6438 snprintf((char *)p2, arg3, "%s", real);
6439 } else {
6440 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006441 }
pbrook53a59602006-03-25 19:31:22 +00006442 unlock_user(p2, arg2, ret);
6443 unlock_user(p, arg1, 0);
6444 }
bellard31e31b82003-02-18 22:55:36 +00006445 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006446#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006447 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006448 {
bellard579a97f2007-11-11 14:26:47 +00006449 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006450 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006451 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006452 if (!p || !p2) {
6453 ret = -TARGET_EFAULT;
6454 } else if (is_proc_myself((const char *)p, "exe")) {
6455 char real[PATH_MAX], *temp;
6456 temp = realpath(exec_path, real);
6457 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6458 snprintf((char *)p2, arg4, "%s", real);
6459 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006460 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006461 }
bellard579a97f2007-11-11 14:26:47 +00006462 unlock_user(p2, arg3, ret);
6463 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006464 }
6465 break;
6466#endif
thse5febef2007-04-01 18:31:35 +00006467#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006468 case TARGET_NR_uselib:
6469 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006470#endif
6471#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006472 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006473 if (!(p = lock_user_string(arg1)))
6474 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006475 ret = get_errno(swapon(p, arg2));
6476 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006477 break;
thse5febef2007-04-01 18:31:35 +00006478#endif
bellard31e31b82003-02-18 22:55:36 +00006479 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006480 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6481 /* arg4 must be ignored in all other cases */
6482 p = lock_user_string(arg4);
6483 if (!p) {
6484 goto efault;
6485 }
6486 ret = get_errno(reboot(arg1, arg2, arg3, p));
6487 unlock_user(p, arg4, 0);
6488 } else {
6489 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6490 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006491 break;
thse5febef2007-04-01 18:31:35 +00006492#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006493 case TARGET_NR_readdir:
6494 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006495#endif
6496#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006497 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006498#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6499 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006500 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6501 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006502 {
blueswir1992f48a2007-10-14 16:27:31 +00006503 abi_ulong *v;
6504 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006505 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6506 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006507 v1 = tswapal(v[0]);
6508 v2 = tswapal(v[1]);
6509 v3 = tswapal(v[2]);
6510 v4 = tswapal(v[3]);
6511 v5 = tswapal(v[4]);
6512 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006513 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006514 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006515 target_to_host_bitmask(v4, mmap_flags_tbl),
6516 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006517 }
bellard31e31b82003-02-18 22:55:36 +00006518#else
ths5fafdf22007-09-16 21:08:06 +00006519 ret = get_errno(target_mmap(arg1, arg2, arg3,
6520 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006521 arg5,
6522 arg6));
bellard31e31b82003-02-18 22:55:36 +00006523#endif
bellard6fb883e2003-07-09 17:12:39 +00006524 break;
thse5febef2007-04-01 18:31:35 +00006525#endif
bellarda315a142005-01-30 22:59:18 +00006526#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006527 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006528#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006529#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006530#endif
ths5fafdf22007-09-16 21:08:06 +00006531 ret = get_errno(target_mmap(arg1, arg2, arg3,
6532 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006533 arg5,
bellardc573ff62004-01-04 15:51:36 +00006534 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006535 break;
bellarda315a142005-01-30 22:59:18 +00006536#endif
bellard31e31b82003-02-18 22:55:36 +00006537 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006538 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006539 break;
bellard9de5e442003-03-23 16:49:39 +00006540 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006541 {
Andreas Färber0429a972013-08-26 18:14:44 +02006542 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006543 /* Special hack to detect libc making the stack executable. */
6544 if ((arg3 & PROT_GROWSDOWN)
6545 && arg1 >= ts->info->stack_limit
6546 && arg1 <= ts->info->start_stack) {
6547 arg3 &= ~PROT_GROWSDOWN;
6548 arg2 = arg2 + arg1 - ts->info->stack_limit;
6549 arg1 = ts->info->stack_limit;
6550 }
6551 }
bellard54936002003-05-13 00:25:15 +00006552 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006553 break;
thse5febef2007-04-01 18:31:35 +00006554#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006555 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006556 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006557 break;
thse5febef2007-04-01 18:31:35 +00006558#endif
pbrook53a59602006-03-25 19:31:22 +00006559 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006560#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006561 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006562 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006563 break;
thse5febef2007-04-01 18:31:35 +00006564#endif
6565#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006566 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006567 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006568 break;
thse5febef2007-04-01 18:31:35 +00006569#endif
6570#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006571 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006572 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006573 break;
thse5febef2007-04-01 18:31:35 +00006574#endif
6575#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006576 case TARGET_NR_mlockall:
6577 ret = get_errno(mlockall(arg1));
6578 break;
thse5febef2007-04-01 18:31:35 +00006579#endif
6580#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006581 case TARGET_NR_munlockall:
6582 ret = get_errno(munlockall());
6583 break;
thse5febef2007-04-01 18:31:35 +00006584#endif
bellard31e31b82003-02-18 22:55:36 +00006585 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006586 if (!(p = lock_user_string(arg1)))
6587 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006588 ret = get_errno(truncate(p, arg2));
6589 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006590 break;
6591 case TARGET_NR_ftruncate:
6592 ret = get_errno(ftruncate(arg1, arg2));
6593 break;
6594 case TARGET_NR_fchmod:
6595 ret = get_errno(fchmod(arg1, arg2));
6596 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006597#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006598 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006599 if (!(p = lock_user_string(arg2)))
6600 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006601 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006602 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006603 break;
6604#endif
bellard31e31b82003-02-18 22:55:36 +00006605 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006606 /* Note that negative values are valid for getpriority, so we must
6607 differentiate based on errno settings. */
6608 errno = 0;
6609 ret = getpriority(arg1, arg2);
6610 if (ret == -1 && errno != 0) {
6611 ret = -host_to_target_errno(errno);
6612 break;
6613 }
6614#ifdef TARGET_ALPHA
6615 /* Return value is the unbiased priority. Signal no error. */
6616 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6617#else
6618 /* Return value is a biased priority to avoid negative numbers. */
6619 ret = 20 - ret;
6620#endif
bellard31e31b82003-02-18 22:55:36 +00006621 break;
6622 case TARGET_NR_setpriority:
6623 ret = get_errno(setpriority(arg1, arg2, arg3));
6624 break;
bellardebc05482003-09-30 21:08:41 +00006625#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006626 case TARGET_NR_profil:
6627 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006628#endif
bellard31e31b82003-02-18 22:55:36 +00006629 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006630 if (!(p = lock_user_string(arg1)))
6631 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006632 ret = get_errno(statfs(path(p), &stfs));
6633 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006634 convert_statfs:
6635 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006636 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006637
bellard579a97f2007-11-11 14:26:47 +00006638 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6639 goto efault;
6640 __put_user(stfs.f_type, &target_stfs->f_type);
6641 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6642 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6643 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6644 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6645 __put_user(stfs.f_files, &target_stfs->f_files);
6646 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6647 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6648 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6649 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006650 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6651 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006652 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006653 }
6654 break;
6655 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006656 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006657 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006658#ifdef TARGET_NR_statfs64
6659 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006660 if (!(p = lock_user_string(arg1)))
6661 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006662 ret = get_errno(statfs(path(p), &stfs));
6663 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006664 convert_statfs64:
6665 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006666 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006667
bellard579a97f2007-11-11 14:26:47 +00006668 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6669 goto efault;
6670 __put_user(stfs.f_type, &target_stfs->f_type);
6671 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6672 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6673 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6674 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6675 __put_user(stfs.f_files, &target_stfs->f_files);
6676 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6677 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6678 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6679 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006680 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6681 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006682 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006683 }
6684 break;
6685 case TARGET_NR_fstatfs64:
6686 ret = get_errno(fstatfs(arg1, &stfs));
6687 goto convert_statfs64;
6688#endif
bellardebc05482003-09-30 21:08:41 +00006689#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006690 case TARGET_NR_ioperm:
6691 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006692#endif
thse5febef2007-04-01 18:31:35 +00006693#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006694 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006695 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006696 break;
thse5febef2007-04-01 18:31:35 +00006697#endif
bellard3532fa72006-06-24 15:06:03 +00006698#ifdef TARGET_NR_accept
6699 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006700 ret = do_accept4(arg1, arg2, arg3, 0);
6701 break;
6702#endif
6703#ifdef TARGET_NR_accept4
6704 case TARGET_NR_accept4:
6705#ifdef CONFIG_ACCEPT4
6706 ret = do_accept4(arg1, arg2, arg3, arg4);
6707#else
6708 goto unimplemented;
6709#endif
bellard3532fa72006-06-24 15:06:03 +00006710 break;
6711#endif
6712#ifdef TARGET_NR_bind
6713 case TARGET_NR_bind:
6714 ret = do_bind(arg1, arg2, arg3);
6715 break;
6716#endif
6717#ifdef TARGET_NR_connect
6718 case TARGET_NR_connect:
6719 ret = do_connect(arg1, arg2, arg3);
6720 break;
6721#endif
6722#ifdef TARGET_NR_getpeername
6723 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006724 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006725 break;
6726#endif
6727#ifdef TARGET_NR_getsockname
6728 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006729 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006730 break;
6731#endif
6732#ifdef TARGET_NR_getsockopt
6733 case TARGET_NR_getsockopt:
6734 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6735 break;
6736#endif
6737#ifdef TARGET_NR_listen
6738 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006739 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006740 break;
6741#endif
6742#ifdef TARGET_NR_recv
6743 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006744 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006745 break;
6746#endif
6747#ifdef TARGET_NR_recvfrom
6748 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006749 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006750 break;
6751#endif
6752#ifdef TARGET_NR_recvmsg
6753 case TARGET_NR_recvmsg:
6754 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6755 break;
6756#endif
6757#ifdef TARGET_NR_send
6758 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006759 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006760 break;
6761#endif
6762#ifdef TARGET_NR_sendmsg
6763 case TARGET_NR_sendmsg:
6764 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6765 break;
6766#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006767#ifdef TARGET_NR_sendmmsg
6768 case TARGET_NR_sendmmsg:
6769 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6770 break;
6771 case TARGET_NR_recvmmsg:
6772 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6773 break;
6774#endif
bellard3532fa72006-06-24 15:06:03 +00006775#ifdef TARGET_NR_sendto
6776 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006777 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006778 break;
6779#endif
6780#ifdef TARGET_NR_shutdown
6781 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006782 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006783 break;
6784#endif
6785#ifdef TARGET_NR_socket
6786 case TARGET_NR_socket:
6787 ret = do_socket(arg1, arg2, arg3);
6788 break;
6789#endif
6790#ifdef TARGET_NR_socketpair
6791 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006792 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006793 break;
6794#endif
6795#ifdef TARGET_NR_setsockopt
6796 case TARGET_NR_setsockopt:
6797 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6798 break;
6799#endif
ths7494b0f2007-02-11 18:26:53 +00006800
bellard31e31b82003-02-18 22:55:36 +00006801 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006802 if (!(p = lock_user_string(arg2)))
6803 goto efault;
thse5574482007-02-11 20:03:13 +00006804 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6805 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006806 break;
6807
bellard31e31b82003-02-18 22:55:36 +00006808 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006809 {
bellard66fb9762003-03-23 01:06:05 +00006810 struct itimerval value, ovalue, *pvalue;
6811
pbrook53a59602006-03-25 19:31:22 +00006812 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006813 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006814 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6815 || copy_from_user_timeval(&pvalue->it_value,
6816 arg2 + sizeof(struct target_timeval)))
6817 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006818 } else {
6819 pvalue = NULL;
6820 }
6821 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006822 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006823 if (copy_to_user_timeval(arg3,
6824 &ovalue.it_interval)
6825 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6826 &ovalue.it_value))
6827 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006828 }
6829 }
6830 break;
bellard31e31b82003-02-18 22:55:36 +00006831 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006832 {
bellard66fb9762003-03-23 01:06:05 +00006833 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006834
bellard66fb9762003-03-23 01:06:05 +00006835 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006836 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006837 if (copy_to_user_timeval(arg2,
6838 &value.it_interval)
6839 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6840 &value.it_value))
6841 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006842 }
6843 }
6844 break;
bellard31e31b82003-02-18 22:55:36 +00006845 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006846 if (!(p = lock_user_string(arg1)))
6847 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006848 ret = get_errno(stat(path(p), &st));
6849 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006850 goto do_stat;
6851 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006852 if (!(p = lock_user_string(arg1)))
6853 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006854 ret = get_errno(lstat(path(p), &st));
6855 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006856 goto do_stat;
6857 case TARGET_NR_fstat:
6858 {
6859 ret = get_errno(fstat(arg1, &st));
6860 do_stat:
6861 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006862 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006863
bellard579a97f2007-11-11 14:26:47 +00006864 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6865 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006866 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006867 __put_user(st.st_dev, &target_st->st_dev);
6868 __put_user(st.st_ino, &target_st->st_ino);
6869 __put_user(st.st_mode, &target_st->st_mode);
6870 __put_user(st.st_uid, &target_st->st_uid);
6871 __put_user(st.st_gid, &target_st->st_gid);
6872 __put_user(st.st_nlink, &target_st->st_nlink);
6873 __put_user(st.st_rdev, &target_st->st_rdev);
6874 __put_user(st.st_size, &target_st->st_size);
6875 __put_user(st.st_blksize, &target_st->st_blksize);
6876 __put_user(st.st_blocks, &target_st->st_blocks);
6877 __put_user(st.st_atime, &target_st->target_st_atime);
6878 __put_user(st.st_mtime, &target_st->target_st_mtime);
6879 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006880 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006881 }
6882 }
6883 break;
bellardebc05482003-09-30 21:08:41 +00006884#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006885 case TARGET_NR_olduname:
6886 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006887#endif
6888#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006889 case TARGET_NR_iopl:
6890 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006891#endif
bellard31e31b82003-02-18 22:55:36 +00006892 case TARGET_NR_vhangup:
6893 ret = get_errno(vhangup());
6894 break;
bellardebc05482003-09-30 21:08:41 +00006895#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006896 case TARGET_NR_idle:
6897 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006898#endif
bellard42ad6ae2005-01-03 22:48:11 +00006899#ifdef TARGET_NR_syscall
6900 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01006901 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
6902 arg6, arg7, arg8, 0);
6903 break;
bellard42ad6ae2005-01-03 22:48:11 +00006904#endif
bellard31e31b82003-02-18 22:55:36 +00006905 case TARGET_NR_wait4:
6906 {
6907 int status;
blueswir1992f48a2007-10-14 16:27:31 +00006908 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00006909 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00006910 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02006911 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00006912 if (target_rusage)
6913 rusage_ptr = &rusage;
6914 else
6915 rusage_ptr = NULL;
6916 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
6917 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01006918 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00006919 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00006920 if (put_user_s32(status, status_ptr))
6921 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006922 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02006923 if (target_rusage) {
6924 rusage_err = host_to_target_rusage(target_rusage, &rusage);
6925 if (rusage_err) {
6926 ret = rusage_err;
6927 }
6928 }
bellard31e31b82003-02-18 22:55:36 +00006929 }
6930 }
6931 break;
thse5febef2007-04-01 18:31:35 +00006932#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00006933 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00006934 if (!(p = lock_user_string(arg1)))
6935 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006936 ret = get_errno(swapoff(p));
6937 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006938 break;
thse5febef2007-04-01 18:31:35 +00006939#endif
bellard31e31b82003-02-18 22:55:36 +00006940 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00006941 {
pbrook53a59602006-03-25 19:31:22 +00006942 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00006943 struct sysinfo value;
6944 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00006945 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00006946 {
bellard579a97f2007-11-11 14:26:47 +00006947 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
6948 goto efault;
bellarda5448a72004-06-19 16:59:03 +00006949 __put_user(value.uptime, &target_value->uptime);
6950 __put_user(value.loads[0], &target_value->loads[0]);
6951 __put_user(value.loads[1], &target_value->loads[1]);
6952 __put_user(value.loads[2], &target_value->loads[2]);
6953 __put_user(value.totalram, &target_value->totalram);
6954 __put_user(value.freeram, &target_value->freeram);
6955 __put_user(value.sharedram, &target_value->sharedram);
6956 __put_user(value.bufferram, &target_value->bufferram);
6957 __put_user(value.totalswap, &target_value->totalswap);
6958 __put_user(value.freeswap, &target_value->freeswap);
6959 __put_user(value.procs, &target_value->procs);
6960 __put_user(value.totalhigh, &target_value->totalhigh);
6961 __put_user(value.freehigh, &target_value->freehigh);
6962 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00006963 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00006964 }
6965 }
6966 break;
thse5febef2007-04-01 18:31:35 +00006967#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00006968 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00006969 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
6970 break;
thse5febef2007-04-01 18:31:35 +00006971#endif
aurel32e5289082009-04-18 16:16:12 +00006972#ifdef TARGET_NR_semget
6973 case TARGET_NR_semget:
6974 ret = get_errno(semget(arg1, arg2, arg3));
6975 break;
6976#endif
6977#ifdef TARGET_NR_semop
6978 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00006979 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00006980 break;
6981#endif
6982#ifdef TARGET_NR_semctl
6983 case TARGET_NR_semctl:
6984 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
6985 break;
6986#endif
aurel32eeb438c2008-10-13 21:08:55 +00006987#ifdef TARGET_NR_msgctl
6988 case TARGET_NR_msgctl:
6989 ret = do_msgctl(arg1, arg2, arg3);
6990 break;
6991#endif
6992#ifdef TARGET_NR_msgget
6993 case TARGET_NR_msgget:
6994 ret = get_errno(msgget(arg1, arg2));
6995 break;
6996#endif
6997#ifdef TARGET_NR_msgrcv
6998 case TARGET_NR_msgrcv:
6999 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7000 break;
7001#endif
7002#ifdef TARGET_NR_msgsnd
7003 case TARGET_NR_msgsnd:
7004 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7005 break;
7006#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007007#ifdef TARGET_NR_shmget
7008 case TARGET_NR_shmget:
7009 ret = get_errno(shmget(arg1, arg2, arg3));
7010 break;
7011#endif
7012#ifdef TARGET_NR_shmctl
7013 case TARGET_NR_shmctl:
7014 ret = do_shmctl(arg1, arg2, arg3);
7015 break;
7016#endif
7017#ifdef TARGET_NR_shmat
7018 case TARGET_NR_shmat:
7019 ret = do_shmat(arg1, arg2, arg3);
7020 break;
7021#endif
7022#ifdef TARGET_NR_shmdt
7023 case TARGET_NR_shmdt:
7024 ret = do_shmdt(arg1);
7025 break;
7026#endif
bellard31e31b82003-02-18 22:55:36 +00007027 case TARGET_NR_fsync:
7028 ret = get_errno(fsync(arg1));
7029 break;
bellard31e31b82003-02-18 22:55:36 +00007030 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007031 /* Linux manages to have three different orderings for its
7032 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7033 * match the kernel's CONFIG_CLONE_* settings.
7034 * Microblaze is further special in that it uses a sixth
7035 * implicit argument to clone for the TLS pointer.
7036 */
7037#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007038 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007039#elif defined(TARGET_CLONE_BACKWARDS)
7040 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7041#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007042 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007043#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007044 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007045#endif
bellard1b6b0292003-03-22 17:31:38 +00007046 break;
bellardec86b0f2003-04-11 00:15:04 +00007047#ifdef __NR_exit_group
7048 /* new thread calls */
7049 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007050#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007051 _mcleanup();
7052#endif
bellarde9009672005-04-26 20:42:36 +00007053 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007054 ret = get_errno(exit_group(arg1));
7055 break;
7056#endif
bellard31e31b82003-02-18 22:55:36 +00007057 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007058 if (!(p = lock_user_string(arg1)))
7059 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007060 ret = get_errno(setdomainname(p, arg2));
7061 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007062 break;
7063 case TARGET_NR_uname:
7064 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007065 {
7066 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007067
bellard579a97f2007-11-11 14:26:47 +00007068 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7069 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007070 ret = get_errno(sys_uname(buf));
7071 if (!is_error(ret)) {
7072 /* Overrite the native machine name with whatever is being
7073 emulated. */
LoĂŻc Minierda790302009-12-29 22:06:13 +01007074 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007075 /* Allow the user to override the reported release. */
7076 if (qemu_uname_release && *qemu_uname_release)
7077 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007078 }
pbrook53a59602006-03-25 19:31:22 +00007079 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007080 }
bellard31e31b82003-02-18 22:55:36 +00007081 break;
bellard6dbad632003-03-16 18:05:05 +00007082#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007083 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007084 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007085 break;
j_mayer84409dd2007-04-06 08:56:50 +00007086#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007087 case TARGET_NR_vm86old:
7088 goto unimplemented;
7089 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007090 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007091 break;
7092#endif
j_mayer84409dd2007-04-06 08:56:50 +00007093#endif
bellard31e31b82003-02-18 22:55:36 +00007094 case TARGET_NR_adjtimex:
7095 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007096#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007097 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007098#endif
bellard31e31b82003-02-18 22:55:36 +00007099 case TARGET_NR_init_module:
7100 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007101#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007102 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007103#endif
bellard31e31b82003-02-18 22:55:36 +00007104 goto unimplemented;
7105 case TARGET_NR_quotactl:
7106 goto unimplemented;
7107 case TARGET_NR_getpgid:
7108 ret = get_errno(getpgid(arg1));
7109 break;
7110 case TARGET_NR_fchdir:
7111 ret = get_errno(fchdir(arg1));
7112 break;
j_mayer84409dd2007-04-06 08:56:50 +00007113#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007114 case TARGET_NR_bdflush:
7115 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007116#endif
thse5febef2007-04-01 18:31:35 +00007117#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007118 case TARGET_NR_sysfs:
7119 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007120#endif
bellard31e31b82003-02-18 22:55:36 +00007121 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007122 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007123 break;
thse5febef2007-04-01 18:31:35 +00007124#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007125 case TARGET_NR_afs_syscall:
7126 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007127#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007128#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007129 case TARGET_NR__llseek:
7130 {
7131 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007132#if !defined(__NR_llseek)
7133 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7134 if (res == -1) {
7135 ret = get_errno(res);
7136 } else {
7137 ret = 0;
7138 }
7139#else
bellard31e31b82003-02-18 22:55:36 +00007140 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007141#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007142 if ((ret == 0) && put_user_s64(res, arg4)) {
7143 goto efault;
7144 }
bellard31e31b82003-02-18 22:55:36 +00007145 }
7146 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007147#endif
bellard31e31b82003-02-18 22:55:36 +00007148 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007149#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007150#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007151 {
pbrook53a59602006-03-25 19:31:22 +00007152 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007153 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007154 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007155
7156 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007157 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007158 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007159 goto fail;
7160 }
ths3b46e622007-09-17 08:09:54 +00007161
bellard4add45b2003-06-05 01:52:59 +00007162 ret = get_errno(sys_getdents(arg1, dirp, count));
7163 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007164 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007165 struct target_dirent *tde;
7166 int len = ret;
7167 int reclen, treclen;
7168 int count1, tnamelen;
7169
7170 count1 = 0;
7171 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007172 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7173 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007174 tde = target_dirp;
7175 while (len > 0) {
7176 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007177 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7178 assert(tnamelen >= 0);
7179 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7180 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007181 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007182 tde->d_ino = tswapal(de->d_ino);
7183 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007184 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007185 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007186 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007187 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007188 count1 += treclen;
7189 }
7190 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007191 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007192 }
7193 free(dirp);
7194 }
7195#else
bellard31e31b82003-02-18 22:55:36 +00007196 {
aurel326556a832008-10-13 21:08:17 +00007197 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007198 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007199
bellard579a97f2007-11-11 14:26:47 +00007200 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7201 goto efault;
bellard72f03902003-02-18 23:33:18 +00007202 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007203 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007204 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007205 int len = ret;
7206 int reclen;
7207 de = dirp;
7208 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007209 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007210 if (reclen > len)
7211 break;
bellard8083a3e2003-03-24 23:12:16 +00007212 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007213 tswapls(&de->d_ino);
7214 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007215 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007216 len -= reclen;
7217 }
7218 }
pbrook53a59602006-03-25 19:31:22 +00007219 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007220 }
bellard4add45b2003-06-05 01:52:59 +00007221#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007222#else
7223 /* Implement getdents in terms of getdents64 */
7224 {
7225 struct linux_dirent64 *dirp;
7226 abi_long count = arg3;
7227
7228 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7229 if (!dirp) {
7230 goto efault;
7231 }
7232 ret = get_errno(sys_getdents64(arg1, dirp, count));
7233 if (!is_error(ret)) {
7234 /* Convert the dirent64 structs to target dirent. We do this
7235 * in-place, since we can guarantee that a target_dirent is no
7236 * larger than a dirent64; however this means we have to be
7237 * careful to read everything before writing in the new format.
7238 */
7239 struct linux_dirent64 *de;
7240 struct target_dirent *tde;
7241 int len = ret;
7242 int tlen = 0;
7243
7244 de = dirp;
7245 tde = (struct target_dirent *)dirp;
7246 while (len > 0) {
7247 int namelen, treclen;
7248 int reclen = de->d_reclen;
7249 uint64_t ino = de->d_ino;
7250 int64_t off = de->d_off;
7251 uint8_t type = de->d_type;
7252
7253 namelen = strlen(de->d_name);
7254 treclen = offsetof(struct target_dirent, d_name)
7255 + namelen + 2;
7256 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7257
7258 memmove(tde->d_name, de->d_name, namelen + 1);
7259 tde->d_ino = tswapal(ino);
7260 tde->d_off = tswapal(off);
7261 tde->d_reclen = tswap16(treclen);
7262 /* The target_dirent type is in what was formerly a padding
7263 * byte at the end of the structure:
7264 */
7265 *(((char *)tde) + treclen - 1) = type;
7266
7267 de = (struct linux_dirent64 *)((char *)de + reclen);
7268 tde = (struct target_dirent *)((char *)tde + treclen);
7269 len -= reclen;
7270 tlen += treclen;
7271 }
7272 ret = tlen;
7273 }
7274 unlock_user(dirp, arg2, ret);
7275 }
7276#endif
bellard31e31b82003-02-18 22:55:36 +00007277 break;
ths3ae43202007-09-16 21:39:48 +00007278#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007279 case TARGET_NR_getdents64:
7280 {
aurel326556a832008-10-13 21:08:17 +00007281 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007282 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007283 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7284 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007285 ret = get_errno(sys_getdents64(arg1, dirp, count));
7286 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007287 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007288 int len = ret;
7289 int reclen;
7290 de = dirp;
7291 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007292 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007293 if (reclen > len)
7294 break;
bellard8083a3e2003-03-24 23:12:16 +00007295 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007296 tswap64s((uint64_t *)&de->d_ino);
7297 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007298 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007299 len -= reclen;
7300 }
7301 }
pbrook53a59602006-03-25 19:31:22 +00007302 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007303 }
7304 break;
bellarda541f292004-04-12 20:39:29 +00007305#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007306#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007307 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007308 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007309 break;
thse5febef2007-04-01 18:31:35 +00007310#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007311#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7312# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007313 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007314# endif
7315# ifdef TARGET_NR_ppoll
7316 case TARGET_NR_ppoll:
7317# endif
bellard9de5e442003-03-23 16:49:39 +00007318 {
pbrook53a59602006-03-25 19:31:22 +00007319 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007320 unsigned int nfds = arg2;
7321 int timeout = arg3;
7322 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007323 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007324
bellard579a97f2007-11-11 14:26:47 +00007325 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7326 if (!target_pfd)
7327 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007328
bellard9de5e442003-03-23 16:49:39 +00007329 pfd = alloca(sizeof(struct pollfd) * nfds);
7330 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007331 pfd[i].fd = tswap32(target_pfd[i].fd);
7332 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007333 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007334
7335# ifdef TARGET_NR_ppoll
7336 if (num == TARGET_NR_ppoll) {
7337 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7338 target_sigset_t *target_set;
7339 sigset_t _set, *set = &_set;
7340
7341 if (arg3) {
7342 if (target_to_host_timespec(timeout_ts, arg3)) {
7343 unlock_user(target_pfd, arg1, 0);
7344 goto efault;
7345 }
7346 } else {
7347 timeout_ts = NULL;
7348 }
7349
7350 if (arg4) {
7351 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7352 if (!target_set) {
7353 unlock_user(target_pfd, arg1, 0);
7354 goto efault;
7355 }
7356 target_to_host_sigset(set, target_set);
7357 } else {
7358 set = NULL;
7359 }
7360
7361 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7362
7363 if (!is_error(ret) && arg3) {
7364 host_to_target_timespec(arg3, timeout_ts);
7365 }
7366 if (arg4) {
7367 unlock_user(target_set, arg4, 0);
7368 }
7369 } else
7370# endif
7371 ret = get_errno(poll(pfd, nfds, timeout));
7372
bellard9de5e442003-03-23 16:49:39 +00007373 if (!is_error(ret)) {
7374 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007375 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007376 }
7377 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007378 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007379 }
7380 break;
thse5febef2007-04-01 18:31:35 +00007381#endif
bellard31e31b82003-02-18 22:55:36 +00007382 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007383 /* NOTE: the flock constant seems to be the same for every
7384 Linux platform */
7385 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007386 break;
7387 case TARGET_NR_readv:
7388 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007389 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7390 if (vec != NULL) {
7391 ret = get_errno(readv(arg1, vec, arg3));
7392 unlock_iovec(vec, arg2, arg3, 1);
7393 } else {
7394 ret = -host_to_target_errno(errno);
7395 }
bellard31e31b82003-02-18 22:55:36 +00007396 }
7397 break;
7398 case TARGET_NR_writev:
7399 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007400 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7401 if (vec != NULL) {
7402 ret = get_errno(writev(arg1, vec, arg3));
7403 unlock_iovec(vec, arg2, arg3, 0);
7404 } else {
7405 ret = -host_to_target_errno(errno);
7406 }
bellard31e31b82003-02-18 22:55:36 +00007407 }
7408 break;
7409 case TARGET_NR_getsid:
7410 ret = get_errno(getsid(arg1));
7411 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007412#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007413 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007414 ret = get_errno(fdatasync(arg1));
7415 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007416#endif
bellard31e31b82003-02-18 22:55:36 +00007417 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007418 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007419 return value. */
ths0da46a62007-10-20 20:23:07 +00007420 ret = -TARGET_ENOTDIR;
7421 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007422 case TARGET_NR_sched_getaffinity:
7423 {
7424 unsigned int mask_size;
7425 unsigned long *mask;
7426
7427 /*
7428 * sched_getaffinity needs multiples of ulong, so need to take
7429 * care of mismatches between target ulong and host ulong sizes.
7430 */
7431 if (arg2 & (sizeof(abi_ulong) - 1)) {
7432 ret = -TARGET_EINVAL;
7433 break;
7434 }
7435 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7436
7437 mask = alloca(mask_size);
7438 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7439
7440 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007441 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007442 goto efault;
7443 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007444 }
7445 }
7446 break;
7447 case TARGET_NR_sched_setaffinity:
7448 {
7449 unsigned int mask_size;
7450 unsigned long *mask;
7451
7452 /*
7453 * sched_setaffinity needs multiples of ulong, so need to take
7454 * care of mismatches between target ulong and host ulong sizes.
7455 */
7456 if (arg2 & (sizeof(abi_ulong) - 1)) {
7457 ret = -TARGET_EINVAL;
7458 break;
7459 }
7460 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7461
7462 mask = alloca(mask_size);
7463 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7464 goto efault;
7465 }
7466 memcpy(mask, p, arg2);
7467 unlock_user_struct(p, arg2, 0);
7468
7469 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7470 }
7471 break;
bellard31e31b82003-02-18 22:55:36 +00007472 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007473 {
pbrook53a59602006-03-25 19:31:22 +00007474 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007475 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007476
bellard579a97f2007-11-11 14:26:47 +00007477 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7478 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007479 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007480 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007481 ret = get_errno(sched_setparam(arg1, &schp));
7482 }
7483 break;
bellard31e31b82003-02-18 22:55:36 +00007484 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007485 {
pbrook53a59602006-03-25 19:31:22 +00007486 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007487 struct sched_param schp;
7488 ret = get_errno(sched_getparam(arg1, &schp));
7489 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007490 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7491 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007492 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007493 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007494 }
7495 }
7496 break;
bellard31e31b82003-02-18 22:55:36 +00007497 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007498 {
pbrook53a59602006-03-25 19:31:22 +00007499 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007500 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007501 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7502 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007503 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007504 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007505 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7506 }
7507 break;
bellard31e31b82003-02-18 22:55:36 +00007508 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007509 ret = get_errno(sched_getscheduler(arg1));
7510 break;
bellard31e31b82003-02-18 22:55:36 +00007511 case TARGET_NR_sched_yield:
7512 ret = get_errno(sched_yield());
7513 break;
7514 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007515 ret = get_errno(sched_get_priority_max(arg1));
7516 break;
bellard31e31b82003-02-18 22:55:36 +00007517 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007518 ret = get_errno(sched_get_priority_min(arg1));
7519 break;
bellard31e31b82003-02-18 22:55:36 +00007520 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007521 {
bellard5cd43932003-03-29 16:54:36 +00007522 struct timespec ts;
7523 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7524 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007525 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007526 }
7527 }
7528 break;
bellard31e31b82003-02-18 22:55:36 +00007529 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007530 {
bellard1b6b0292003-03-22 17:31:38 +00007531 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007532 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007533 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007534 if (is_error(ret) && arg2) {
7535 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007536 }
7537 }
7538 break;
thse5febef2007-04-01 18:31:35 +00007539#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007540 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007541 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007542#endif
7543#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007544 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007545 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007546#endif
bellard31e31b82003-02-18 22:55:36 +00007547 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007548 switch (arg1) {
7549 case PR_GET_PDEATHSIG:
7550 {
7551 int deathsig;
7552 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7553 if (!is_error(ret) && arg2
7554 && put_user_ual(deathsig, arg2)) {
7555 goto efault;
thse5574482007-02-11 20:03:13 +00007556 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007557 break;
7558 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007559#ifdef PR_GET_NAME
7560 case PR_GET_NAME:
7561 {
7562 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7563 if (!name) {
7564 goto efault;
7565 }
7566 ret = get_errno(prctl(arg1, (unsigned long)name,
7567 arg3, arg4, arg5));
7568 unlock_user(name, arg2, 16);
7569 break;
7570 }
7571 case PR_SET_NAME:
7572 {
7573 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7574 if (!name) {
7575 goto efault;
7576 }
7577 ret = get_errno(prctl(arg1, (unsigned long)name,
7578 arg3, arg4, arg5));
7579 unlock_user(name, arg2, 0);
7580 break;
7581 }
7582#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007583 default:
7584 /* Most prctl options have no pointer arguments */
7585 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7586 break;
7587 }
ths39b9aae2007-02-11 18:36:44 +00007588 break;
bellardd2fd1af2007-11-14 18:08:56 +00007589#ifdef TARGET_NR_arch_prctl
7590 case TARGET_NR_arch_prctl:
7591#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7592 ret = do_arch_prctl(cpu_env, arg1, arg2);
7593 break;
7594#else
7595 goto unimplemented;
7596#endif
7597#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007598#ifdef TARGET_NR_pread64
7599 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007600 if (regpairs_aligned(cpu_env)) {
7601 arg4 = arg5;
7602 arg5 = arg6;
7603 }
aurel32f2c7ba12008-03-28 22:32:06 +00007604 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7605 goto efault;
7606 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7607 unlock_user(p, arg2, ret);
7608 break;
7609 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007610 if (regpairs_aligned(cpu_env)) {
7611 arg4 = arg5;
7612 arg5 = arg6;
7613 }
aurel32f2c7ba12008-03-28 22:32:06 +00007614 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7615 goto efault;
7616 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7617 unlock_user(p, arg2, 0);
7618 break;
7619#endif
bellard31e31b82003-02-18 22:55:36 +00007620 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007621 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7622 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007623 ret = get_errno(sys_getcwd1(p, arg2));
7624 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007625 break;
7626 case TARGET_NR_capget:
7627 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007628 {
7629 struct target_user_cap_header *target_header;
7630 struct target_user_cap_data *target_data = NULL;
7631 struct __user_cap_header_struct header;
7632 struct __user_cap_data_struct data[2];
7633 struct __user_cap_data_struct *dataptr = NULL;
7634 int i, target_datalen;
7635 int data_items = 1;
7636
7637 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7638 goto efault;
7639 }
7640 header.version = tswap32(target_header->version);
7641 header.pid = tswap32(target_header->pid);
7642
Peter Maydellec864872014-03-19 16:07:30 +00007643 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007644 /* Version 2 and up takes pointer to two user_data structs */
7645 data_items = 2;
7646 }
7647
7648 target_datalen = sizeof(*target_data) * data_items;
7649
7650 if (arg2) {
7651 if (num == TARGET_NR_capget) {
7652 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7653 } else {
7654 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7655 }
7656 if (!target_data) {
7657 unlock_user_struct(target_header, arg1, 0);
7658 goto efault;
7659 }
7660
7661 if (num == TARGET_NR_capset) {
7662 for (i = 0; i < data_items; i++) {
7663 data[i].effective = tswap32(target_data[i].effective);
7664 data[i].permitted = tswap32(target_data[i].permitted);
7665 data[i].inheritable = tswap32(target_data[i].inheritable);
7666 }
7667 }
7668
7669 dataptr = data;
7670 }
7671
7672 if (num == TARGET_NR_capget) {
7673 ret = get_errno(capget(&header, dataptr));
7674 } else {
7675 ret = get_errno(capset(&header, dataptr));
7676 }
7677
7678 /* The kernel always updates version for both capget and capset */
7679 target_header->version = tswap32(header.version);
7680 unlock_user_struct(target_header, arg1, 1);
7681
7682 if (arg2) {
7683 if (num == TARGET_NR_capget) {
7684 for (i = 0; i < data_items; i++) {
7685 target_data[i].effective = tswap32(data[i].effective);
7686 target_data[i].permitted = tswap32(data[i].permitted);
7687 target_data[i].inheritable = tswap32(data[i].inheritable);
7688 }
7689 unlock_user(target_data, arg2, target_datalen);
7690 } else {
7691 unlock_user(target_data, arg2, 0);
7692 }
7693 }
7694 break;
7695 }
bellard31e31b82003-02-18 22:55:36 +00007696 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007697#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007698 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007699 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007700 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007701 break;
7702#else
bellard5cd43932003-03-29 16:54:36 +00007703 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007704#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007705
7706#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007707 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007708 {
7709 off_t *offp = NULL;
7710 off_t off;
7711 if (arg3) {
7712 ret = get_user_sal(off, arg3);
7713 if (is_error(ret)) {
7714 break;
7715 }
7716 offp = &off;
7717 }
7718 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7719 if (!is_error(ret) && arg3) {
7720 abi_long ret2 = put_user_sal(off, arg3);
7721 if (is_error(ret2)) {
7722 ret = ret2;
7723 }
7724 }
7725 break;
7726 }
7727#ifdef TARGET_NR_sendfile64
7728 case TARGET_NR_sendfile64:
7729 {
7730 off_t *offp = NULL;
7731 off_t off;
7732 if (arg3) {
7733 ret = get_user_s64(off, arg3);
7734 if (is_error(ret)) {
7735 break;
7736 }
7737 offp = &off;
7738 }
7739 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7740 if (!is_error(ret) && arg3) {
7741 abi_long ret2 = put_user_s64(off, arg3);
7742 if (is_error(ret2)) {
7743 ret = ret2;
7744 }
7745 }
7746 break;
7747 }
7748#endif
7749#else
7750 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007751#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007752 case TARGET_NR_sendfile64:
7753#endif
bellard5cd43932003-03-29 16:54:36 +00007754 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007755#endif
7756
bellardebc05482003-09-30 21:08:41 +00007757#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007758 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007759 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007760#endif
7761#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007762 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007763 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007764#endif
bellard048f6b42005-11-26 18:47:20 +00007765#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007766 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007767 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7768 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007769 break;
bellard048f6b42005-11-26 18:47:20 +00007770#endif
bellardebc05482003-09-30 21:08:41 +00007771#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007772 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007773 {
7774 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007775 int resource = target_to_host_resource(arg1);
7776 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007777 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007778 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007779 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7780 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007781 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7782 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007783 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007784 }
7785 break;
7786 }
bellardebc05482003-09-30 21:08:41 +00007787#endif
bellarda315a142005-01-30 22:59:18 +00007788#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007789 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007790 if (!(p = lock_user_string(arg1)))
7791 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007792 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7793 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007794 break;
bellarda315a142005-01-30 22:59:18 +00007795#endif
7796#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007797 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007798 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007799 break;
bellarda315a142005-01-30 22:59:18 +00007800#endif
7801#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007802 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007803 if (!(p = lock_user_string(arg1)))
7804 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007805 ret = get_errno(stat(path(p), &st));
7806 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007807 if (!is_error(ret))
7808 ret = host_to_target_stat64(cpu_env, arg2, &st);
7809 break;
bellarda315a142005-01-30 22:59:18 +00007810#endif
7811#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007812 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007813 if (!(p = lock_user_string(arg1)))
7814 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007815 ret = get_errno(lstat(path(p), &st));
7816 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007817 if (!is_error(ret))
7818 ret = host_to_target_stat64(cpu_env, arg2, &st);
7819 break;
bellarda315a142005-01-30 22:59:18 +00007820#endif
7821#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007822 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007823 ret = get_errno(fstat(arg1, &st));
7824 if (!is_error(ret))
7825 ret = host_to_target_stat64(cpu_env, arg2, &st);
7826 break;
bellardec86b0f2003-04-11 00:15:04 +00007827#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007828#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007829#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007830 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007831#endif
7832#ifdef TARGET_NR_newfstatat
7833 case TARGET_NR_newfstatat:
7834#endif
balrog6a24a772008-09-20 02:23:36 +00007835 if (!(p = lock_user_string(arg2)))
7836 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007837 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007838 if (!is_error(ret))
7839 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007840 break;
bellarda315a142005-01-30 22:59:18 +00007841#endif
bellard67867302003-11-23 17:05:30 +00007842 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007843 if (!(p = lock_user_string(arg1)))
7844 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007845 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7846 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007847 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007848#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007849 case TARGET_NR_getuid:
7850 ret = get_errno(high2lowuid(getuid()));
7851 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007852#endif
7853#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007854 case TARGET_NR_getgid:
7855 ret = get_errno(high2lowgid(getgid()));
7856 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007857#endif
7858#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007859 case TARGET_NR_geteuid:
7860 ret = get_errno(high2lowuid(geteuid()));
7861 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007862#endif
7863#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007864 case TARGET_NR_getegid:
7865 ret = get_errno(high2lowgid(getegid()));
7866 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007867#endif
bellard67867302003-11-23 17:05:30 +00007868 case TARGET_NR_setreuid:
7869 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7870 break;
7871 case TARGET_NR_setregid:
7872 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7873 break;
7874 case TARGET_NR_getgroups:
7875 {
7876 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007877 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007878 gid_t *grouplist;
7879 int i;
7880
7881 grouplist = alloca(gidsetsize * sizeof(gid_t));
7882 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007883 if (gidsetsize == 0)
7884 break;
bellard67867302003-11-23 17:05:30 +00007885 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007886 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007887 if (!target_grouplist)
7888 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007889 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007890 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007891 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007892 }
7893 }
7894 break;
7895 case TARGET_NR_setgroups:
7896 {
7897 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007898 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007899 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007900 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007901 if (gidsetsize) {
7902 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007903 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007904 if (!target_grouplist) {
7905 ret = -TARGET_EFAULT;
7906 goto fail;
7907 }
7908 for (i = 0; i < gidsetsize; i++) {
7909 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
7910 }
7911 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00007912 }
bellard67867302003-11-23 17:05:30 +00007913 ret = get_errno(setgroups(gidsetsize, grouplist));
7914 }
7915 break;
7916 case TARGET_NR_fchown:
7917 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
7918 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007919#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00007920 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00007921 if (!(p = lock_user_string(arg2)))
7922 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007923 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
7924 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00007925 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00007926 break;
7927#endif
bellard67867302003-11-23 17:05:30 +00007928#ifdef TARGET_NR_setresuid
7929 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00007930 ret = get_errno(setresuid(low2highuid(arg1),
7931 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00007932 low2highuid(arg3)));
7933 break;
7934#endif
7935#ifdef TARGET_NR_getresuid
7936 case TARGET_NR_getresuid:
7937 {
pbrook53a59602006-03-25 19:31:22 +00007938 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00007939 ret = get_errno(getresuid(&ruid, &euid, &suid));
7940 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007941 if (put_user_id(high2lowuid(ruid), arg1)
7942 || put_user_id(high2lowuid(euid), arg2)
7943 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00007944 goto efault;
bellard67867302003-11-23 17:05:30 +00007945 }
7946 }
7947 break;
7948#endif
7949#ifdef TARGET_NR_getresgid
7950 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00007951 ret = get_errno(setresgid(low2highgid(arg1),
7952 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00007953 low2highgid(arg3)));
7954 break;
7955#endif
7956#ifdef TARGET_NR_getresgid
7957 case TARGET_NR_getresgid:
7958 {
pbrook53a59602006-03-25 19:31:22 +00007959 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00007960 ret = get_errno(getresgid(&rgid, &egid, &sgid));
7961 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00007962 if (put_user_id(high2lowgid(rgid), arg1)
7963 || put_user_id(high2lowgid(egid), arg2)
7964 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00007965 goto efault;
bellard67867302003-11-23 17:05:30 +00007966 }
7967 }
7968 break;
7969#endif
7970 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00007971 if (!(p = lock_user_string(arg1)))
7972 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007973 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
7974 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007975 break;
7976 case TARGET_NR_setuid:
7977 ret = get_errno(setuid(low2highuid(arg1)));
7978 break;
7979 case TARGET_NR_setgid:
7980 ret = get_errno(setgid(low2highgid(arg1)));
7981 break;
7982 case TARGET_NR_setfsuid:
7983 ret = get_errno(setfsuid(arg1));
7984 break;
7985 case TARGET_NR_setfsgid:
7986 ret = get_errno(setfsgid(arg1));
7987 break;
bellard67867302003-11-23 17:05:30 +00007988
bellarda315a142005-01-30 22:59:18 +00007989#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00007990 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00007991 if (!(p = lock_user_string(arg1)))
7992 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007993 ret = get_errno(lchown(p, arg2, arg3));
7994 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00007995 break;
bellarda315a142005-01-30 22:59:18 +00007996#endif
7997#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00007998 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00007999 ret = get_errno(getuid());
8000 break;
bellarda315a142005-01-30 22:59:18 +00008001#endif
aurel3264b4d282008-11-14 17:20:15 +00008002
8003#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8004 /* Alpha specific */
8005 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008006 {
8007 uid_t euid;
8008 euid=geteuid();
8009 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8010 }
aurel3264b4d282008-11-14 17:20:15 +00008011 ret = get_errno(getuid());
8012 break;
8013#endif
8014#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8015 /* Alpha specific */
8016 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008017 {
8018 uid_t egid;
8019 egid=getegid();
8020 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8021 }
aurel3264b4d282008-11-14 17:20:15 +00008022 ret = get_errno(getgid());
8023 break;
8024#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008025#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8026 /* Alpha specific */
8027 case TARGET_NR_osf_getsysinfo:
8028 ret = -TARGET_EOPNOTSUPP;
8029 switch (arg1) {
8030 case TARGET_GSI_IEEE_FP_CONTROL:
8031 {
8032 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8033
8034 /* Copied from linux ieee_fpcr_to_swcr. */
8035 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8036 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8037 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8038 | SWCR_TRAP_ENABLE_DZE
8039 | SWCR_TRAP_ENABLE_OVF);
8040 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8041 | SWCR_TRAP_ENABLE_INE);
8042 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8043 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8044
8045 if (put_user_u64 (swcr, arg2))
8046 goto efault;
8047 ret = 0;
8048 }
8049 break;
8050
8051 /* case GSI_IEEE_STATE_AT_SIGNAL:
8052 -- Not implemented in linux kernel.
8053 case GSI_UACPROC:
8054 -- Retrieves current unaligned access state; not much used.
8055 case GSI_PROC_TYPE:
8056 -- Retrieves implver information; surely not used.
8057 case GSI_GET_HWRPB:
8058 -- Grabs a copy of the HWRPB; surely not used.
8059 */
8060 }
8061 break;
8062#endif
8063#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8064 /* Alpha specific */
8065 case TARGET_NR_osf_setsysinfo:
8066 ret = -TARGET_EOPNOTSUPP;
8067 switch (arg1) {
8068 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008069 {
8070 uint64_t swcr, fpcr, orig_fpcr;
8071
Richard Henderson6e06d512012-06-01 09:08:21 -07008072 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008073 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008074 }
8075 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008076 fpcr = orig_fpcr & FPCR_DYN_MASK;
8077
8078 /* Copied from linux ieee_swcr_to_fpcr. */
8079 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8080 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8081 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8082 | SWCR_TRAP_ENABLE_DZE
8083 | SWCR_TRAP_ENABLE_OVF)) << 48;
8084 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8085 | SWCR_TRAP_ENABLE_INE)) << 57;
8086 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8087 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8088
Richard Henderson6e06d512012-06-01 09:08:21 -07008089 cpu_alpha_store_fpcr(cpu_env, fpcr);
8090 ret = 0;
8091 }
8092 break;
8093
8094 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8095 {
8096 uint64_t exc, fpcr, orig_fpcr;
8097 int si_code;
8098
8099 if (get_user_u64(exc, arg2)) {
8100 goto efault;
8101 }
8102
8103 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8104
8105 /* We only add to the exception status here. */
8106 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8107
8108 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008109 ret = 0;
8110
Richard Henderson6e06d512012-06-01 09:08:21 -07008111 /* Old exceptions are not signaled. */
8112 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008113
Richard Henderson6e06d512012-06-01 09:08:21 -07008114 /* If any exceptions set by this call,
8115 and are unmasked, send a signal. */
8116 si_code = 0;
8117 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8118 si_code = TARGET_FPE_FLTRES;
8119 }
8120 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8121 si_code = TARGET_FPE_FLTUND;
8122 }
8123 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8124 si_code = TARGET_FPE_FLTOVF;
8125 }
8126 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8127 si_code = TARGET_FPE_FLTDIV;
8128 }
8129 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8130 si_code = TARGET_FPE_FLTINV;
8131 }
8132 if (si_code != 0) {
8133 target_siginfo_t info;
8134 info.si_signo = SIGFPE;
8135 info.si_errno = 0;
8136 info.si_code = si_code;
8137 info._sifields._sigfault._addr
8138 = ((CPUArchState *)cpu_env)->pc;
8139 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008140 }
8141 }
8142 break;
8143
8144 /* case SSI_NVPAIRS:
8145 -- Used with SSIN_UACPROC to enable unaligned accesses.
8146 case SSI_IEEE_STATE_AT_SIGNAL:
8147 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8148 -- Not implemented in linux kernel
8149 */
8150 }
8151 break;
8152#endif
8153#ifdef TARGET_NR_osf_sigprocmask
8154 /* Alpha specific. */
8155 case TARGET_NR_osf_sigprocmask:
8156 {
8157 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008158 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008159 sigset_t set, oldset;
8160
8161 switch(arg1) {
8162 case TARGET_SIG_BLOCK:
8163 how = SIG_BLOCK;
8164 break;
8165 case TARGET_SIG_UNBLOCK:
8166 how = SIG_UNBLOCK;
8167 break;
8168 case TARGET_SIG_SETMASK:
8169 how = SIG_SETMASK;
8170 break;
8171 default:
8172 ret = -TARGET_EINVAL;
8173 goto fail;
8174 }
8175 mask = arg2;
8176 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008177 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008178 host_to_target_old_sigset(&mask, &oldset);
8179 ret = mask;
8180 }
8181 break;
8182#endif
aurel3264b4d282008-11-14 17:20:15 +00008183
bellarda315a142005-01-30 22:59:18 +00008184#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008185 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008186 ret = get_errno(getgid());
8187 break;
bellarda315a142005-01-30 22:59:18 +00008188#endif
8189#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008190 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008191 ret = get_errno(geteuid());
8192 break;
bellarda315a142005-01-30 22:59:18 +00008193#endif
8194#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008195 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008196 ret = get_errno(getegid());
8197 break;
bellarda315a142005-01-30 22:59:18 +00008198#endif
8199#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008200 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008201 ret = get_errno(setreuid(arg1, arg2));
8202 break;
bellarda315a142005-01-30 22:59:18 +00008203#endif
8204#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008205 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008206 ret = get_errno(setregid(arg1, arg2));
8207 break;
bellarda315a142005-01-30 22:59:18 +00008208#endif
8209#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008210 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008211 {
8212 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008213 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008214 gid_t *grouplist;
8215 int i;
8216
8217 grouplist = alloca(gidsetsize * sizeof(gid_t));
8218 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008219 if (gidsetsize == 0)
8220 break;
bellard99c475a2005-01-31 20:45:13 +00008221 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008222 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8223 if (!target_grouplist) {
8224 ret = -TARGET_EFAULT;
8225 goto fail;
8226 }
balroga2155fc2008-09-20 02:12:08 +00008227 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008228 target_grouplist[i] = tswap32(grouplist[i]);
8229 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008230 }
8231 }
8232 break;
bellarda315a142005-01-30 22:59:18 +00008233#endif
8234#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008235 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008236 {
8237 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008238 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008239 gid_t *grouplist;
8240 int i;
ths3b46e622007-09-17 08:09:54 +00008241
bellard99c475a2005-01-31 20:45:13 +00008242 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008243 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8244 if (!target_grouplist) {
8245 ret = -TARGET_EFAULT;
8246 goto fail;
8247 }
bellard99c475a2005-01-31 20:45:13 +00008248 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008249 grouplist[i] = tswap32(target_grouplist[i]);
8250 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008251 ret = get_errno(setgroups(gidsetsize, grouplist));
8252 }
8253 break;
bellarda315a142005-01-30 22:59:18 +00008254#endif
8255#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008256 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008257 ret = get_errno(fchown(arg1, arg2, arg3));
8258 break;
bellarda315a142005-01-30 22:59:18 +00008259#endif
8260#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008261 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008262 ret = get_errno(setresuid(arg1, arg2, arg3));
8263 break;
bellarda315a142005-01-30 22:59:18 +00008264#endif
8265#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008266 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008267 {
pbrook53a59602006-03-25 19:31:22 +00008268 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008269 ret = get_errno(getresuid(&ruid, &euid, &suid));
8270 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008271 if (put_user_u32(ruid, arg1)
8272 || put_user_u32(euid, arg2)
8273 || put_user_u32(suid, arg3))
8274 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008275 }
8276 }
8277 break;
bellarda315a142005-01-30 22:59:18 +00008278#endif
8279#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008280 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008281 ret = get_errno(setresgid(arg1, arg2, arg3));
8282 break;
bellarda315a142005-01-30 22:59:18 +00008283#endif
8284#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008285 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008286 {
pbrook53a59602006-03-25 19:31:22 +00008287 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008288 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8289 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008290 if (put_user_u32(rgid, arg1)
8291 || put_user_u32(egid, arg2)
8292 || put_user_u32(sgid, arg3))
8293 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008294 }
8295 }
8296 break;
bellarda315a142005-01-30 22:59:18 +00008297#endif
8298#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008299 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008300 if (!(p = lock_user_string(arg1)))
8301 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008302 ret = get_errno(chown(p, arg2, arg3));
8303 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008304 break;
bellarda315a142005-01-30 22:59:18 +00008305#endif
8306#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008307 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008308 ret = get_errno(setuid(arg1));
8309 break;
bellarda315a142005-01-30 22:59:18 +00008310#endif
8311#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008312 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008313 ret = get_errno(setgid(arg1));
8314 break;
bellarda315a142005-01-30 22:59:18 +00008315#endif
8316#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008317 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008318 ret = get_errno(setfsuid(arg1));
8319 break;
bellarda315a142005-01-30 22:59:18 +00008320#endif
8321#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008322 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008323 ret = get_errno(setfsgid(arg1));
8324 break;
bellarda315a142005-01-30 22:59:18 +00008325#endif
bellard67867302003-11-23 17:05:30 +00008326
bellard31e31b82003-02-18 22:55:36 +00008327 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008328 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008329#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008330 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008331 {
8332 void *a;
8333 ret = -TARGET_EFAULT;
8334 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8335 goto efault;
8336 if (!(p = lock_user_string(arg3)))
8337 goto mincore_fail;
8338 ret = get_errno(mincore(a, arg2, p));
8339 unlock_user(p, arg3, ret);
8340 mincore_fail:
8341 unlock_user(a, arg1, 0);
8342 }
8343 break;
bellardffa65c32004-01-04 23:57:22 +00008344#endif
aurel32408321b2008-10-01 21:46:32 +00008345#ifdef TARGET_NR_arm_fadvise64_64
8346 case TARGET_NR_arm_fadvise64_64:
8347 {
8348 /*
8349 * arm_fadvise64_64 looks like fadvise64_64 but
8350 * with different argument order
8351 */
8352 abi_long temp;
8353 temp = arg3;
8354 arg3 = arg4;
8355 arg4 = temp;
8356 }
8357#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008358#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008359#ifdef TARGET_NR_fadvise64_64
8360 case TARGET_NR_fadvise64_64:
8361#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008362#ifdef TARGET_NR_fadvise64
8363 case TARGET_NR_fadvise64:
8364#endif
8365#ifdef TARGET_S390X
8366 switch (arg4) {
8367 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8368 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8369 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8370 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8371 default: break;
8372 }
8373#endif
8374 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008375 break;
8376#endif
bellardffa65c32004-01-04 23:57:22 +00008377#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008378 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008379 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008380 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008381 This will break MADV_DONTNEED.
8382 This is a hint, so ignoring and returning success is ok. */
8383 ret = get_errno(0);
8384 break;
bellardffa65c32004-01-04 23:57:22 +00008385#endif
blueswir1992f48a2007-10-14 16:27:31 +00008386#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008387 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008388 {
thsb1e341e2007-03-20 21:50:52 +00008389 int cmd;
bellard77e46722003-04-29 20:39:06 +00008390 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008391 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008392#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008393 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008394#endif
bellard77e46722003-04-29 20:39:06 +00008395
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008396 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008397 if (cmd == -TARGET_EINVAL) {
8398 ret = cmd;
8399 break;
8400 }
thsb1e341e2007-03-20 21:50:52 +00008401
bellard60cd49d2003-03-16 22:53:56 +00008402 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008403 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008404#ifdef TARGET_ARM
8405 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008406 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8407 goto efault;
ths58134272007-03-31 18:59:32 +00008408 fl.l_type = tswap16(target_efl->l_type);
8409 fl.l_whence = tswap16(target_efl->l_whence);
8410 fl.l_start = tswap64(target_efl->l_start);
8411 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008412 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008413 unlock_user_struct(target_efl, arg3, 0);
8414 } else
8415#endif
8416 {
bellard9ee1fa22007-11-11 15:11:19 +00008417 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8418 goto efault;
ths58134272007-03-31 18:59:32 +00008419 fl.l_type = tswap16(target_fl->l_type);
8420 fl.l_whence = tswap16(target_fl->l_whence);
8421 fl.l_start = tswap64(target_fl->l_start);
8422 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008423 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008424 unlock_user_struct(target_fl, arg3, 0);
8425 }
thsb1e341e2007-03-20 21:50:52 +00008426 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008427 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008428#ifdef TARGET_ARM
8429 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008430 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8431 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008432 target_efl->l_type = tswap16(fl.l_type);
8433 target_efl->l_whence = tswap16(fl.l_whence);
8434 target_efl->l_start = tswap64(fl.l_start);
8435 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008436 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008437 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008438 } else
8439#endif
8440 {
bellard9ee1fa22007-11-11 15:11:19 +00008441 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8442 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008443 target_fl->l_type = tswap16(fl.l_type);
8444 target_fl->l_whence = tswap16(fl.l_whence);
8445 target_fl->l_start = tswap64(fl.l_start);
8446 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008447 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008448 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008449 }
bellard77e46722003-04-29 20:39:06 +00008450 }
8451 break;
8452
thsb1e341e2007-03-20 21:50:52 +00008453 case TARGET_F_SETLK64:
8454 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008455#ifdef TARGET_ARM
8456 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008457 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8458 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008459 fl.l_type = tswap16(target_efl->l_type);
8460 fl.l_whence = tswap16(target_efl->l_whence);
8461 fl.l_start = tswap64(target_efl->l_start);
8462 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008463 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008464 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008465 } else
8466#endif
8467 {
bellard9ee1fa22007-11-11 15:11:19 +00008468 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8469 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008470 fl.l_type = tswap16(target_fl->l_type);
8471 fl.l_whence = tswap16(target_fl->l_whence);
8472 fl.l_start = tswap64(target_fl->l_start);
8473 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008474 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008475 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008476 }
thsb1e341e2007-03-20 21:50:52 +00008477 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008478 break;
bellard60cd49d2003-03-16 22:53:56 +00008479 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008480 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008481 break;
8482 }
bellard77e46722003-04-29 20:39:06 +00008483 break;
8484 }
bellard60cd49d2003-03-16 22:53:56 +00008485#endif
ths7d600c82006-12-08 01:32:58 +00008486#ifdef TARGET_NR_cacheflush
8487 case TARGET_NR_cacheflush:
8488 /* self-modifying code is handled automatically, so nothing needed */
8489 ret = 0;
8490 break;
8491#endif
bellardebc05482003-09-30 21:08:41 +00008492#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008493 case TARGET_NR_security:
8494 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008495#endif
bellardc573ff62004-01-04 15:51:36 +00008496#ifdef TARGET_NR_getpagesize
8497 case TARGET_NR_getpagesize:
8498 ret = TARGET_PAGE_SIZE;
8499 break;
8500#endif
bellard31e31b82003-02-18 22:55:36 +00008501 case TARGET_NR_gettid:
8502 ret = get_errno(gettid());
8503 break;
thse5febef2007-04-01 18:31:35 +00008504#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008505 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008506#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008507 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008508 arg2 = arg3;
8509 arg3 = arg4;
8510 arg4 = arg5;
8511 }
aurel322054ac92008-10-13 21:08:07 +00008512 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8513#else
8514 ret = get_errno(readahead(arg1, arg2, arg3));
8515#endif
8516 break;
thse5febef2007-04-01 18:31:35 +00008517#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008518#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008519#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008520 case TARGET_NR_listxattr:
8521 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008522 {
8523 void *p, *b = 0;
8524 if (arg2) {
8525 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8526 if (!b) {
8527 ret = -TARGET_EFAULT;
8528 break;
8529 }
8530 }
8531 p = lock_user_string(arg1);
8532 if (p) {
8533 if (num == TARGET_NR_listxattr) {
8534 ret = get_errno(listxattr(p, b, arg3));
8535 } else {
8536 ret = get_errno(llistxattr(p, b, arg3));
8537 }
8538 } else {
8539 ret = -TARGET_EFAULT;
8540 }
8541 unlock_user(p, arg1, 0);
8542 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008543 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008544 }
8545 case TARGET_NR_flistxattr:
8546 {
8547 void *b = 0;
8548 if (arg2) {
8549 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8550 if (!b) {
8551 ret = -TARGET_EFAULT;
8552 break;
8553 }
8554 }
8555 ret = get_errno(flistxattr(arg1, b, arg3));
8556 unlock_user(b, arg2, arg3);
8557 break;
8558 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008559 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008560 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008561 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008562 void *p, *n, *v = 0;
8563 if (arg3) {
8564 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8565 if (!v) {
8566 ret = -TARGET_EFAULT;
8567 break;
8568 }
8569 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008570 p = lock_user_string(arg1);
8571 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008572 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008573 if (num == TARGET_NR_setxattr) {
8574 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8575 } else {
8576 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8577 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008578 } else {
8579 ret = -TARGET_EFAULT;
8580 }
8581 unlock_user(p, arg1, 0);
8582 unlock_user(n, arg2, 0);
8583 unlock_user(v, arg3, 0);
8584 }
8585 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008586 case TARGET_NR_fsetxattr:
8587 {
8588 void *n, *v = 0;
8589 if (arg3) {
8590 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8591 if (!v) {
8592 ret = -TARGET_EFAULT;
8593 break;
8594 }
8595 }
8596 n = lock_user_string(arg2);
8597 if (n) {
8598 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8599 } else {
8600 ret = -TARGET_EFAULT;
8601 }
8602 unlock_user(n, arg2, 0);
8603 unlock_user(v, arg3, 0);
8604 }
8605 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008606 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008607 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008608 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008609 void *p, *n, *v = 0;
8610 if (arg3) {
8611 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8612 if (!v) {
8613 ret = -TARGET_EFAULT;
8614 break;
8615 }
8616 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008617 p = lock_user_string(arg1);
8618 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008619 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008620 if (num == TARGET_NR_getxattr) {
8621 ret = get_errno(getxattr(p, n, v, arg4));
8622 } else {
8623 ret = get_errno(lgetxattr(p, n, v, arg4));
8624 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008625 } else {
8626 ret = -TARGET_EFAULT;
8627 }
8628 unlock_user(p, arg1, 0);
8629 unlock_user(n, arg2, 0);
8630 unlock_user(v, arg3, arg4);
8631 }
8632 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008633 case TARGET_NR_fgetxattr:
8634 {
8635 void *n, *v = 0;
8636 if (arg3) {
8637 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8638 if (!v) {
8639 ret = -TARGET_EFAULT;
8640 break;
8641 }
8642 }
8643 n = lock_user_string(arg2);
8644 if (n) {
8645 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8646 } else {
8647 ret = -TARGET_EFAULT;
8648 }
8649 unlock_user(n, arg2, 0);
8650 unlock_user(v, arg3, arg4);
8651 }
8652 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008653 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008654 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008655 {
8656 void *p, *n;
8657 p = lock_user_string(arg1);
8658 n = lock_user_string(arg2);
8659 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008660 if (num == TARGET_NR_removexattr) {
8661 ret = get_errno(removexattr(p, n));
8662 } else {
8663 ret = get_errno(lremovexattr(p, n));
8664 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008665 } else {
8666 ret = -TARGET_EFAULT;
8667 }
8668 unlock_user(p, arg1, 0);
8669 unlock_user(n, arg2, 0);
8670 }
8671 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008672 case TARGET_NR_fremovexattr:
8673 {
8674 void *n;
8675 n = lock_user_string(arg2);
8676 if (n) {
8677 ret = get_errno(fremovexattr(arg1, n));
8678 } else {
8679 ret = -TARGET_EFAULT;
8680 }
8681 unlock_user(n, arg2, 0);
8682 }
8683 break;
bellardebc05482003-09-30 21:08:41 +00008684#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008685#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008686#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008687 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008688#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008689 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8690 ret = 0;
8691 break;
edgar_iglef967792009-01-07 14:19:38 +00008692#elif defined(TARGET_CRIS)
8693 if (arg1 & 0xff)
8694 ret = -TARGET_EINVAL;
8695 else {
8696 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8697 ret = 0;
8698 }
8699 break;
bellard8d18e892007-11-14 15:18:40 +00008700#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8701 ret = do_set_thread_area(cpu_env, arg1);
8702 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008703#elif defined(TARGET_M68K)
8704 {
Andreas Färber0429a972013-08-26 18:14:44 +02008705 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008706 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008707 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008708 break;
8709 }
ths6f5b89a2007-03-02 20:48:00 +00008710#else
8711 goto unimplemented_nowarn;
8712#endif
8713#endif
8714#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008715 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008716#if defined(TARGET_I386) && defined(TARGET_ABI32)
8717 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008718 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008719#elif defined(TARGET_M68K)
8720 {
Andreas Färber0429a972013-08-26 18:14:44 +02008721 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008722 ret = ts->tp_value;
8723 break;
8724 }
bellard8d18e892007-11-14 15:18:40 +00008725#else
bellard5cd43932003-03-29 16:54:36 +00008726 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008727#endif
bellard8d18e892007-11-14 15:18:40 +00008728#endif
bellard48dc41e2006-06-21 18:15:50 +00008729#ifdef TARGET_NR_getdomainname
8730 case TARGET_NR_getdomainname:
8731 goto unimplemented_nowarn;
8732#endif
ths6f5b89a2007-03-02 20:48:00 +00008733
thsb5906f92007-03-19 13:32:45 +00008734#ifdef TARGET_NR_clock_gettime
8735 case TARGET_NR_clock_gettime:
8736 {
8737 struct timespec ts;
8738 ret = get_errno(clock_gettime(arg1, &ts));
8739 if (!is_error(ret)) {
8740 host_to_target_timespec(arg2, &ts);
8741 }
8742 break;
8743 }
8744#endif
8745#ifdef TARGET_NR_clock_getres
8746 case TARGET_NR_clock_getres:
8747 {
8748 struct timespec ts;
8749 ret = get_errno(clock_getres(arg1, &ts));
8750 if (!is_error(ret)) {
8751 host_to_target_timespec(arg2, &ts);
8752 }
8753 break;
8754 }
8755#endif
pbrook63d76512008-05-29 13:43:29 +00008756#ifdef TARGET_NR_clock_nanosleep
8757 case TARGET_NR_clock_nanosleep:
8758 {
8759 struct timespec ts;
8760 target_to_host_timespec(&ts, arg3);
8761 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8762 if (arg4)
8763 host_to_target_timespec(arg4, &ts);
8764 break;
8765 }
8766#endif
thsb5906f92007-03-19 13:32:45 +00008767
ths6f5b89a2007-03-02 20:48:00 +00008768#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8769 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008770 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8771 break;
ths6f5b89a2007-03-02 20:48:00 +00008772#endif
8773
ths3ae43202007-09-16 21:39:48 +00008774#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008775 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008776 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008777 break;
8778#endif
8779
ths3ae43202007-09-16 21:39:48 +00008780#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008781 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008782 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8783 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008784 break;
8785#endif
8786
ths4f2b1fe2007-06-21 21:57:12 +00008787#ifdef TARGET_NR_set_robust_list
8788 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008789 case TARGET_NR_get_robust_list:
8790 /* The ABI for supporting robust futexes has userspace pass
8791 * the kernel a pointer to a linked list which is updated by
8792 * userspace after the syscall; the list is walked by the kernel
8793 * when the thread exits. Since the linked list in QEMU guest
8794 * memory isn't a valid linked list for the host and we have
8795 * no way to reliably intercept the thread-death event, we can't
8796 * support these. Silently return ENOSYS so that guest userspace
8797 * falls back to a non-robust futex implementation (which should
8798 * be OK except in the corner case of the guest crashing while
8799 * holding a mutex that is shared with another process via
8800 * shared memory).
8801 */
8802 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008803#endif
8804
Peter Maydell1acae9f2013-07-02 14:04:12 +01008805#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00008806 case TARGET_NR_utimensat:
8807 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008808 struct timespec *tsp, ts[2];
8809 if (!arg3) {
8810 tsp = NULL;
8811 } else {
8812 target_to_host_timespec(ts, arg3);
8813 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8814 tsp = ts;
8815 }
ths9007f0e2007-09-25 17:50:37 +00008816 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008817 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008818 else {
bellard579a97f2007-11-11 14:26:47 +00008819 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008820 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008821 goto fail;
8822 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008823 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008824 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008825 }
8826 }
8827 break;
8828#endif
pbrookbd0c5662008-05-29 14:34:11 +00008829 case TARGET_NR_futex:
8830 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8831 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008832#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008833 case TARGET_NR_inotify_init:
8834 ret = get_errno(sys_inotify_init());
8835 break;
8836#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008837#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008838#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8839 case TARGET_NR_inotify_init1:
8840 ret = get_errno(sys_inotify_init1(arg1));
8841 break;
8842#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008843#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008844#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008845 case TARGET_NR_inotify_add_watch:
8846 p = lock_user_string(arg2);
8847 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8848 unlock_user(p, arg2, 0);
8849 break;
8850#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008851#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008852 case TARGET_NR_inotify_rm_watch:
8853 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8854 break;
8855#endif
ths9007f0e2007-09-25 17:50:37 +00008856
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008857#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008858 case TARGET_NR_mq_open:
8859 {
8860 struct mq_attr posix_mq_attr;
8861
8862 p = lock_user_string(arg1 - 1);
8863 if (arg4 != 0)
8864 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8865 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8866 unlock_user (p, arg1, 0);
8867 }
8868 break;
8869
8870 case TARGET_NR_mq_unlink:
8871 p = lock_user_string(arg1 - 1);
8872 ret = get_errno(mq_unlink(p));
8873 unlock_user (p, arg1, 0);
8874 break;
8875
8876 case TARGET_NR_mq_timedsend:
8877 {
8878 struct timespec ts;
8879
8880 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8881 if (arg5 != 0) {
8882 target_to_host_timespec(&ts, arg5);
8883 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8884 host_to_target_timespec(arg5, &ts);
8885 }
8886 else
8887 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8888 unlock_user (p, arg2, arg3);
8889 }
8890 break;
8891
8892 case TARGET_NR_mq_timedreceive:
8893 {
8894 struct timespec ts;
8895 unsigned int prio;
8896
8897 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8898 if (arg5 != 0) {
8899 target_to_host_timespec(&ts, arg5);
8900 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8901 host_to_target_timespec(arg5, &ts);
8902 }
8903 else
8904 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
8905 unlock_user (p, arg2, arg3);
8906 if (arg4 != 0)
8907 put_user_u32(prio, arg4);
8908 }
8909 break;
8910
8911 /* Not implemented for now... */
8912/* case TARGET_NR_mq_notify: */
8913/* break; */
8914
8915 case TARGET_NR_mq_getsetattr:
8916 {
8917 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
8918 ret = 0;
8919 if (arg3 != 0) {
8920 ret = mq_getattr(arg1, &posix_mq_attr_out);
8921 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
8922 }
8923 if (arg2 != 0) {
8924 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
8925 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
8926 }
8927
8928 }
8929 break;
8930#endif
8931
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308932#ifdef CONFIG_SPLICE
8933#ifdef TARGET_NR_tee
8934 case TARGET_NR_tee:
8935 {
8936 ret = get_errno(tee(arg1,arg2,arg3,arg4));
8937 }
8938 break;
8939#endif
8940#ifdef TARGET_NR_splice
8941 case TARGET_NR_splice:
8942 {
8943 loff_t loff_in, loff_out;
8944 loff_t *ploff_in = NULL, *ploff_out = NULL;
8945 if(arg2) {
8946 get_user_u64(loff_in, arg2);
8947 ploff_in = &loff_in;
8948 }
8949 if(arg4) {
8950 get_user_u64(loff_out, arg2);
8951 ploff_out = &loff_out;
8952 }
8953 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
8954 }
8955 break;
8956#endif
8957#ifdef TARGET_NR_vmsplice
8958 case TARGET_NR_vmsplice:
8959 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07008960 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
8961 if (vec != NULL) {
8962 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
8963 unlock_iovec(vec, arg2, arg3, 0);
8964 } else {
8965 ret = -host_to_target_errno(errno);
8966 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05308967 }
8968 break;
8969#endif
8970#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03008971#ifdef CONFIG_EVENTFD
8972#if defined(TARGET_NR_eventfd)
8973 case TARGET_NR_eventfd:
8974 ret = get_errno(eventfd(arg1, 0));
8975 break;
8976#endif
8977#if defined(TARGET_NR_eventfd2)
8978 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02008979 {
8980 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
8981 if (arg2 & TARGET_O_NONBLOCK) {
8982 host_flags |= O_NONBLOCK;
8983 }
8984 if (arg2 & TARGET_O_CLOEXEC) {
8985 host_flags |= O_CLOEXEC;
8986 }
8987 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03008988 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02008989 }
Riku Voipioc2882b92009-08-12 15:08:24 +03008990#endif
8991#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03008992#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
8993 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01008994#if TARGET_ABI_BITS == 32
8995 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
8996 target_offset64(arg5, arg6)));
8997#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03008998 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01008999#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009000 break;
9001#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009002#if defined(CONFIG_SYNC_FILE_RANGE)
9003#if defined(TARGET_NR_sync_file_range)
9004 case TARGET_NR_sync_file_range:
9005#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009006#if defined(TARGET_MIPS)
9007 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9008 target_offset64(arg5, arg6), arg7));
9009#else
Peter Maydellc727f472011-01-06 11:05:10 +00009010 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9011 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009012#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009013#else
9014 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9015#endif
9016 break;
9017#endif
9018#if defined(TARGET_NR_sync_file_range2)
9019 case TARGET_NR_sync_file_range2:
9020 /* This is like sync_file_range but the arguments are reordered */
9021#if TARGET_ABI_BITS == 32
9022 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9023 target_offset64(arg5, arg6), arg2));
9024#else
9025 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9026#endif
9027 break;
9028#endif
9029#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009030#if defined(CONFIG_EPOLL)
9031#if defined(TARGET_NR_epoll_create)
9032 case TARGET_NR_epoll_create:
9033 ret = get_errno(epoll_create(arg1));
9034 break;
9035#endif
9036#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9037 case TARGET_NR_epoll_create1:
9038 ret = get_errno(epoll_create1(arg1));
9039 break;
9040#endif
9041#if defined(TARGET_NR_epoll_ctl)
9042 case TARGET_NR_epoll_ctl:
9043 {
9044 struct epoll_event ep;
9045 struct epoll_event *epp = 0;
9046 if (arg4) {
9047 struct target_epoll_event *target_ep;
9048 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9049 goto efault;
9050 }
9051 ep.events = tswap32(target_ep->events);
9052 /* The epoll_data_t union is just opaque data to the kernel,
9053 * so we transfer all 64 bits across and need not worry what
9054 * actual data type it is.
9055 */
9056 ep.data.u64 = tswap64(target_ep->data.u64);
9057 unlock_user_struct(target_ep, arg4, 0);
9058 epp = &ep;
9059 }
9060 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9061 break;
9062 }
9063#endif
9064
9065#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9066#define IMPLEMENT_EPOLL_PWAIT
9067#endif
9068#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9069#if defined(TARGET_NR_epoll_wait)
9070 case TARGET_NR_epoll_wait:
9071#endif
9072#if defined(IMPLEMENT_EPOLL_PWAIT)
9073 case TARGET_NR_epoll_pwait:
9074#endif
9075 {
9076 struct target_epoll_event *target_ep;
9077 struct epoll_event *ep;
9078 int epfd = arg1;
9079 int maxevents = arg3;
9080 int timeout = arg4;
9081
9082 target_ep = lock_user(VERIFY_WRITE, arg2,
9083 maxevents * sizeof(struct target_epoll_event), 1);
9084 if (!target_ep) {
9085 goto efault;
9086 }
9087
9088 ep = alloca(maxevents * sizeof(struct epoll_event));
9089
9090 switch (num) {
9091#if defined(IMPLEMENT_EPOLL_PWAIT)
9092 case TARGET_NR_epoll_pwait:
9093 {
9094 target_sigset_t *target_set;
9095 sigset_t _set, *set = &_set;
9096
9097 if (arg5) {
9098 target_set = lock_user(VERIFY_READ, arg5,
9099 sizeof(target_sigset_t), 1);
9100 if (!target_set) {
9101 unlock_user(target_ep, arg2, 0);
9102 goto efault;
9103 }
9104 target_to_host_sigset(set, target_set);
9105 unlock_user(target_set, arg5, 0);
9106 } else {
9107 set = NULL;
9108 }
9109
9110 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9111 break;
9112 }
9113#endif
9114#if defined(TARGET_NR_epoll_wait)
9115 case TARGET_NR_epoll_wait:
9116 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9117 break;
9118#endif
9119 default:
9120 ret = -TARGET_ENOSYS;
9121 }
9122 if (!is_error(ret)) {
9123 int i;
9124 for (i = 0; i < ret; i++) {
9125 target_ep[i].events = tswap32(ep[i].events);
9126 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9127 }
9128 }
9129 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9130 break;
9131 }
9132#endif
9133#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009134#ifdef TARGET_NR_prlimit64
9135 case TARGET_NR_prlimit64:
9136 {
9137 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9138 struct target_rlimit64 *target_rnew, *target_rold;
9139 struct host_rlimit64 rnew, rold, *rnewp = 0;
9140 if (arg3) {
9141 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9142 goto efault;
9143 }
9144 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9145 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9146 unlock_user_struct(target_rnew, arg3, 0);
9147 rnewp = &rnew;
9148 }
9149
9150 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9151 if (!is_error(ret) && arg4) {
9152 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9153 goto efault;
9154 }
9155 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9156 target_rold->rlim_max = tswap64(rold.rlim_max);
9157 unlock_user_struct(target_rold, arg4, 1);
9158 }
9159 break;
9160 }
9161#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009162#ifdef TARGET_NR_gethostname
9163 case TARGET_NR_gethostname:
9164 {
9165 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9166 if (name) {
9167 ret = get_errno(gethostname(name, arg2));
9168 unlock_user(name, arg1, arg2);
9169 } else {
9170 ret = -TARGET_EFAULT;
9171 }
9172 break;
9173 }
9174#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009175#ifdef TARGET_NR_atomic_cmpxchg_32
9176 case TARGET_NR_atomic_cmpxchg_32:
9177 {
9178 /* should use start_exclusive from main.c */
9179 abi_ulong mem_value;
9180 if (get_user_u32(mem_value, arg6)) {
9181 target_siginfo_t info;
9182 info.si_signo = SIGSEGV;
9183 info.si_errno = 0;
9184 info.si_code = TARGET_SEGV_MAPERR;
9185 info._sifields._sigfault._addr = arg6;
9186 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9187 ret = 0xdeadbeef;
9188
9189 }
9190 if (mem_value == arg2)
9191 put_user_u32(arg1, arg6);
9192 ret = mem_value;
9193 break;
9194 }
9195#endif
9196#ifdef TARGET_NR_atomic_barrier
9197 case TARGET_NR_atomic_barrier:
9198 {
9199 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009200 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009201 break;
9202 }
9203#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009204
9205#ifdef TARGET_NR_timer_create
9206 case TARGET_NR_timer_create:
9207 {
9208 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9209
9210 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9211 struct target_sigevent *ptarget_sevp;
9212 struct target_timer_t *ptarget_timer;
9213
9214 int clkid = arg1;
9215 int timer_index = next_free_host_timer();
9216
9217 if (timer_index < 0) {
9218 ret = -TARGET_EAGAIN;
9219 } else {
9220 timer_t *phtimer = g_posix_timers + timer_index;
9221
9222 if (arg2) {
9223 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9224 goto efault;
9225 }
9226
9227 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9228 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9229
9230 phost_sevp = &host_sevp;
9231 }
9232
9233 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9234 if (ret) {
9235 phtimer = NULL;
9236 } else {
9237 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9238 goto efault;
9239 }
9240 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9241 unlock_user_struct(ptarget_timer, arg3, 1);
9242 }
9243 }
9244 break;
9245 }
9246#endif
9247
9248#ifdef TARGET_NR_timer_settime
9249 case TARGET_NR_timer_settime:
9250 {
9251 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9252 * struct itimerspec * old_value */
9253 arg1 &= 0xffff;
9254 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9255 ret = -TARGET_EINVAL;
9256 } else {
9257 timer_t htimer = g_posix_timers[arg1];
9258 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9259
9260 target_to_host_itimerspec(&hspec_new, arg3);
9261 ret = get_errno(
9262 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9263 host_to_target_itimerspec(arg2, &hspec_old);
9264 }
9265 break;
9266 }
9267#endif
9268
9269#ifdef TARGET_NR_timer_gettime
9270 case TARGET_NR_timer_gettime:
9271 {
9272 /* args: timer_t timerid, struct itimerspec *curr_value */
9273 arg1 &= 0xffff;
9274 if (!arg2) {
9275 return -TARGET_EFAULT;
9276 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9277 ret = -TARGET_EINVAL;
9278 } else {
9279 timer_t htimer = g_posix_timers[arg1];
9280 struct itimerspec hspec;
9281 ret = get_errno(timer_gettime(htimer, &hspec));
9282
9283 if (host_to_target_itimerspec(arg2, &hspec)) {
9284 ret = -TARGET_EFAULT;
9285 }
9286 }
9287 break;
9288 }
9289#endif
9290
9291#ifdef TARGET_NR_timer_getoverrun
9292 case TARGET_NR_timer_getoverrun:
9293 {
9294 /* args: timer_t timerid */
9295 arg1 &= 0xffff;
9296 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9297 ret = -TARGET_EINVAL;
9298 } else {
9299 timer_t htimer = g_posix_timers[arg1];
9300 ret = get_errno(timer_getoverrun(htimer));
9301 }
9302 break;
9303 }
9304#endif
9305
9306#ifdef TARGET_NR_timer_delete
9307 case TARGET_NR_timer_delete:
9308 {
9309 /* args: timer_t timerid */
9310 arg1 &= 0xffff;
9311 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9312 ret = -TARGET_EINVAL;
9313 } else {
9314 timer_t htimer = g_posix_timers[arg1];
9315 ret = get_errno(timer_delete(htimer));
9316 g_posix_timers[arg1] = 0;
9317 }
9318 break;
9319 }
9320#endif
9321
bellard31e31b82003-02-18 22:55:36 +00009322 default:
9323 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009324 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009325#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 +00009326 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009327#endif
ths0da46a62007-10-20 20:23:07 +00009328 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009329 break;
9330 }
bellard579a97f2007-11-11 14:26:47 +00009331fail:
bellardc573ff62004-01-04 15:51:36 +00009332#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009333 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009334#endif
thsb92c47c2007-11-01 00:07:38 +00009335 if(do_strace)
9336 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009337 return ret;
bellard579a97f2007-11-11 14:26:47 +00009338efault:
9339 ret = -TARGET_EFAULT;
9340 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009341}