blob: c8c2b4c15bbe0a1207194dbabbd204cea913a8df [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
Paul Burton8289d112014-06-22 11:25:33 +0100595static inline int host_to_target_sock_type(int host_type)
596{
597 int target_type;
598
599 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
600 case SOCK_DGRAM:
601 target_type = TARGET_SOCK_DGRAM;
602 break;
603 case SOCK_STREAM:
604 target_type = TARGET_SOCK_STREAM;
605 break;
606 default:
607 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
608 break;
609 }
610
611#if defined(SOCK_CLOEXEC)
612 if (host_type & SOCK_CLOEXEC) {
613 target_type |= TARGET_SOCK_CLOEXEC;
614 }
615#endif
616
617#if defined(SOCK_NONBLOCK)
618 if (host_type & SOCK_NONBLOCK) {
619 target_type |= TARGET_SOCK_NONBLOCK;
620 }
621#endif
622
623 return target_type;
624}
625
blueswir1992f48a2007-10-14 16:27:31 +0000626static abi_ulong target_brk;
627static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000628static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000629
blueswir1992f48a2007-10-14 16:27:31 +0000630void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000631{
blueswir14c1de732007-07-07 20:45:44 +0000632 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000633 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000634}
635
vincent4d1de872011-06-14 21:56:33 +0000636//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
637#define DEBUGF_BRK(message, args...)
638
ths0da46a62007-10-20 20:23:07 +0000639/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000640abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000641{
blueswir1992f48a2007-10-14 16:27:31 +0000642 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000643 int new_alloc_size;
644
Paul Brook3a0c6c42012-02-09 19:04:27 +0000645 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000646
vincent4d1de872011-06-14 21:56:33 +0000647 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000648 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000649 return target_brk;
650 }
651 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000652 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
653 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000654 return target_brk;
655 }
bellard31e31b82003-02-18 22:55:36 +0000656
vincent4d1de872011-06-14 21:56:33 +0000657 /* If the new brk is less than the highest page reserved to the
658 * target heap allocation, set it and we're almost done... */
659 if (new_brk <= brk_page) {
660 /* Heap contents are initialized to zero, as for anonymous
661 * mapped pages. */
662 if (new_brk > target_brk) {
663 memset(g2h(target_brk), 0, new_brk - target_brk);
664 }
bellard31e31b82003-02-18 22:55:36 +0000665 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000666 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000667 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000668 }
669
Peter Maydell00faf082011-04-18 16:34:24 +0100670 /* We need to allocate more memory after the brk... Note that
671 * we don't use MAP_FIXED because that will map over the top of
672 * any existing mapping (like the one with the host libc or qemu
673 * itself); instead we treat "mapped but at wrong address" as
674 * a failure and unmap again.
675 */
vincent4d1de872011-06-14 21:56:33 +0000676 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000677 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000678 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100679 MAP_ANON|MAP_PRIVATE, 0, 0));
680
681 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200682 /* Heap contents are initialized to zero, as for anonymous
683 * mapped pages. Technically the new pages are already
684 * initialized to zero since they *are* anonymous mapped
685 * pages, however we have to take care with the contents that
686 * come from the remaining part of the previous page: it may
687 * contains garbage data due to a previous heap usage (grown
688 * then shrunken). */
689 memset(g2h(target_brk), 0, brk_page - target_brk);
690
Peter Maydell00faf082011-04-18 16:34:24 +0100691 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000692 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000693 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
694 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100695 return target_brk;
696 } else if (mapped_addr != -1) {
697 /* Mapped but at wrong address, meaning there wasn't actually
698 * enough space for this brk.
699 */
700 target_munmap(mapped_addr, new_alloc_size);
701 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000702 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000703 }
704 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000705 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100706 }
balrog7ab240a2008-04-26 12:17:34 +0000707
Richard Henderson7dd46c02010-05-03 10:07:49 -0700708#if defined(TARGET_ALPHA)
709 /* We (partially) emulate OSF/1 on Alpha, which requires we
710 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100711 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700712#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100713 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000714 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000715}
716
ths26edcf42007-12-09 02:25:24 +0000717static inline abi_long copy_from_user_fdset(fd_set *fds,
718 abi_ulong target_fds_addr,
719 int n)
bellard31e31b82003-02-18 22:55:36 +0000720{
ths26edcf42007-12-09 02:25:24 +0000721 int i, nw, j, k;
722 abi_ulong b, *target_fds;
723
724 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
725 if (!(target_fds = lock_user(VERIFY_READ,
726 target_fds_addr,
727 sizeof(abi_ulong) * nw,
728 1)))
729 return -TARGET_EFAULT;
730
731 FD_ZERO(fds);
732 k = 0;
733 for (i = 0; i < nw; i++) {
734 /* grab the abi_ulong */
735 __get_user(b, &target_fds[i]);
736 for (j = 0; j < TARGET_ABI_BITS; j++) {
737 /* check the bit inside the abi_ulong */
738 if ((b >> j) & 1)
739 FD_SET(k, fds);
740 k++;
bellard31e31b82003-02-18 22:55:36 +0000741 }
bellard31e31b82003-02-18 22:55:36 +0000742 }
ths26edcf42007-12-09 02:25:24 +0000743
744 unlock_user(target_fds, target_fds_addr, 0);
745
746 return 0;
bellard31e31b82003-02-18 22:55:36 +0000747}
748
Mike Frysinger055e0902011-06-03 17:01:49 -0400749static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
750 abi_ulong target_fds_addr,
751 int n)
752{
753 if (target_fds_addr) {
754 if (copy_from_user_fdset(fds, target_fds_addr, n))
755 return -TARGET_EFAULT;
756 *fds_ptr = fds;
757 } else {
758 *fds_ptr = NULL;
759 }
760 return 0;
761}
762
ths26edcf42007-12-09 02:25:24 +0000763static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
764 const fd_set *fds,
765 int n)
bellard31e31b82003-02-18 22:55:36 +0000766{
bellard31e31b82003-02-18 22:55:36 +0000767 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000768 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000769 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000770
ths26edcf42007-12-09 02:25:24 +0000771 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
772 if (!(target_fds = lock_user(VERIFY_WRITE,
773 target_fds_addr,
774 sizeof(abi_ulong) * nw,
775 0)))
776 return -TARGET_EFAULT;
777
778 k = 0;
779 for (i = 0; i < nw; i++) {
780 v = 0;
781 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000782 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000783 k++;
bellard31e31b82003-02-18 22:55:36 +0000784 }
ths26edcf42007-12-09 02:25:24 +0000785 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000786 }
ths26edcf42007-12-09 02:25:24 +0000787
788 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
789
790 return 0;
bellard31e31b82003-02-18 22:55:36 +0000791}
792
bellardc596ed12003-07-13 17:32:31 +0000793#if defined(__alpha__)
794#define HOST_HZ 1024
795#else
796#define HOST_HZ 100
797#endif
798
blueswir1992f48a2007-10-14 16:27:31 +0000799static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000800{
801#if HOST_HZ == TARGET_HZ
802 return ticks;
803#else
804 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
805#endif
806}
807
bellard579a97f2007-11-11 14:26:47 +0000808static inline abi_long host_to_target_rusage(abi_ulong target_addr,
809 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000810{
pbrook53a59602006-03-25 19:31:22 +0000811 struct target_rusage *target_rusage;
812
bellard579a97f2007-11-11 14:26:47 +0000813 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
814 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200815 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
816 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
817 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
818 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
819 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
820 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
821 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
822 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
823 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
824 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
825 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
826 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
827 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
828 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
829 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
830 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
831 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
832 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000833 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000834
835 return 0;
bellardb4091862003-05-16 15:39:34 +0000836}
837
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200838static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900839{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200840 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300841 rlim_t result;
842
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200843 target_rlim_swap = tswapal(target_rlim);
844 if (target_rlim_swap == TARGET_RLIM_INFINITY)
845 return RLIM_INFINITY;
846
847 result = target_rlim_swap;
848 if (target_rlim_swap != (rlim_t)result)
849 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300850
851 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900852}
853
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200854static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900855{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200856 abi_ulong target_rlim_swap;
857 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300858
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200859 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300860 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900861 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300862 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200863 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300864
865 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900866}
867
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300868static inline int target_to_host_resource(int code)
869{
870 switch (code) {
871 case TARGET_RLIMIT_AS:
872 return RLIMIT_AS;
873 case TARGET_RLIMIT_CORE:
874 return RLIMIT_CORE;
875 case TARGET_RLIMIT_CPU:
876 return RLIMIT_CPU;
877 case TARGET_RLIMIT_DATA:
878 return RLIMIT_DATA;
879 case TARGET_RLIMIT_FSIZE:
880 return RLIMIT_FSIZE;
881 case TARGET_RLIMIT_LOCKS:
882 return RLIMIT_LOCKS;
883 case TARGET_RLIMIT_MEMLOCK:
884 return RLIMIT_MEMLOCK;
885 case TARGET_RLIMIT_MSGQUEUE:
886 return RLIMIT_MSGQUEUE;
887 case TARGET_RLIMIT_NICE:
888 return RLIMIT_NICE;
889 case TARGET_RLIMIT_NOFILE:
890 return RLIMIT_NOFILE;
891 case TARGET_RLIMIT_NPROC:
892 return RLIMIT_NPROC;
893 case TARGET_RLIMIT_RSS:
894 return RLIMIT_RSS;
895 case TARGET_RLIMIT_RTPRIO:
896 return RLIMIT_RTPRIO;
897 case TARGET_RLIMIT_SIGPENDING:
898 return RLIMIT_SIGPENDING;
899 case TARGET_RLIMIT_STACK:
900 return RLIMIT_STACK;
901 default:
902 return code;
903 }
904}
905
ths788f5ec2007-12-09 02:37:05 +0000906static inline abi_long copy_from_user_timeval(struct timeval *tv,
907 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000908{
pbrook53a59602006-03-25 19:31:22 +0000909 struct target_timeval *target_tv;
910
ths788f5ec2007-12-09 02:37:05 +0000911 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000912 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000913
914 __get_user(tv->tv_sec, &target_tv->tv_sec);
915 __get_user(tv->tv_usec, &target_tv->tv_usec);
916
917 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000918
919 return 0;
bellard31e31b82003-02-18 22:55:36 +0000920}
921
ths788f5ec2007-12-09 02:37:05 +0000922static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
923 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000924{
pbrook53a59602006-03-25 19:31:22 +0000925 struct target_timeval *target_tv;
926
ths788f5ec2007-12-09 02:37:05 +0000927 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000928 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000929
930 __put_user(tv->tv_sec, &target_tv->tv_sec);
931 __put_user(tv->tv_usec, &target_tv->tv_usec);
932
933 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000934
935 return 0;
bellard31e31b82003-02-18 22:55:36 +0000936}
937
Paul Burtonef4467e2014-06-22 11:25:40 +0100938static inline abi_long copy_from_user_timezone(struct timezone *tz,
939 abi_ulong target_tz_addr)
940{
941 struct target_timezone *target_tz;
942
943 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
944 return -TARGET_EFAULT;
945 }
946
947 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
948 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
949
950 unlock_user_struct(target_tz, target_tz_addr, 0);
951
952 return 0;
953}
954
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700955#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
956#include <mqueue.h>
957
aurel3224e10032009-04-15 16:11:43 +0000958static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
959 abi_ulong target_mq_attr_addr)
960{
961 struct target_mq_attr *target_mq_attr;
962
963 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
964 target_mq_attr_addr, 1))
965 return -TARGET_EFAULT;
966
967 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
968 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
969 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
970 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
971
972 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
973
974 return 0;
975}
976
977static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
978 const struct mq_attr *attr)
979{
980 struct target_mq_attr *target_mq_attr;
981
982 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
983 target_mq_attr_addr, 0))
984 return -TARGET_EFAULT;
985
986 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
987 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
988 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
989 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
990
991 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
992
993 return 0;
994}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700995#endif
bellard31e31b82003-02-18 22:55:36 +0000996
Mike Frysinger055e0902011-06-03 17:01:49 -0400997#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000998/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000999static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +00001000 abi_ulong rfd_addr, abi_ulong wfd_addr,
1001 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001002{
1003 fd_set rfds, wfds, efds;
1004 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1005 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001006 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001007
Mike Frysinger055e0902011-06-03 17:01:49 -04001008 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1009 if (ret) {
1010 return ret;
pbrook53a59602006-03-25 19:31:22 +00001011 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001012 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1013 if (ret) {
1014 return ret;
pbrook53a59602006-03-25 19:31:22 +00001015 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001016 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1017 if (ret) {
1018 return ret;
pbrook53a59602006-03-25 19:31:22 +00001019 }
ths3b46e622007-09-17 08:09:54 +00001020
ths26edcf42007-12-09 02:25:24 +00001021 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001022 if (copy_from_user_timeval(&tv, target_tv_addr))
1023 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001024 tv_ptr = &tv;
1025 } else {
1026 tv_ptr = NULL;
1027 }
ths26edcf42007-12-09 02:25:24 +00001028
bellard31e31b82003-02-18 22:55:36 +00001029 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001030
ths26edcf42007-12-09 02:25:24 +00001031 if (!is_error(ret)) {
1032 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1033 return -TARGET_EFAULT;
1034 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1035 return -TARGET_EFAULT;
1036 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1037 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001038
ths788f5ec2007-12-09 02:37:05 +00001039 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1040 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001041 }
bellard579a97f2007-11-11 14:26:47 +00001042
bellard31e31b82003-02-18 22:55:36 +00001043 return ret;
1044}
Mike Frysinger055e0902011-06-03 17:01:49 -04001045#endif
bellard31e31b82003-02-18 22:55:36 +00001046
Riku Voipio099d6b02009-05-05 12:10:04 +03001047static abi_long do_pipe2(int host_pipe[], int flags)
1048{
1049#ifdef CONFIG_PIPE2
1050 return pipe2(host_pipe, flags);
1051#else
1052 return -ENOSYS;
1053#endif
1054}
1055
Richard Hendersonfb41a662010-05-03 10:07:52 -07001056static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1057 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001058{
1059 int host_pipe[2];
1060 abi_long ret;
1061 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1062
1063 if (is_error(ret))
1064 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001065
1066 /* Several targets have special calling conventions for the original
1067 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1068 if (!is_pipe2) {
1069#if defined(TARGET_ALPHA)
1070 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1071 return host_pipe[0];
1072#elif defined(TARGET_MIPS)
1073 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1074 return host_pipe[0];
1075#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001076 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001077 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001078#elif defined(TARGET_SPARC)
1079 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1080 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001081#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001082 }
1083
Riku Voipio099d6b02009-05-05 12:10:04 +03001084 if (put_user_s32(host_pipe[0], pipedes)
1085 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1086 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001087 return get_errno(ret);
1088}
1089
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001090static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1091 abi_ulong target_addr,
1092 socklen_t len)
1093{
1094 struct target_ip_mreqn *target_smreqn;
1095
1096 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1097 if (!target_smreqn)
1098 return -TARGET_EFAULT;
1099 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1100 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1101 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001102 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001103 unlock_user(target_smreqn, target_addr, 0);
1104
1105 return 0;
1106}
1107
bellard579a97f2007-11-11 14:26:47 +00001108static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1109 abi_ulong target_addr,
1110 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001111{
aurel32607175e2009-04-15 16:11:59 +00001112 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1113 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001114 struct target_sockaddr *target_saddr;
1115
bellard579a97f2007-11-11 14:26:47 +00001116 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1117 if (!target_saddr)
1118 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001119
1120 sa_family = tswap16(target_saddr->sa_family);
1121
1122 /* Oops. The caller might send a incomplete sun_path; sun_path
1123 * must be terminated by \0 (see the manual page), but
1124 * unfortunately it is quite common to specify sockaddr_un
1125 * length as "strlen(x->sun_path)" while it should be
1126 * "strlen(...) + 1". We'll fix that here if needed.
1127 * Linux kernel has a similar feature.
1128 */
1129
1130 if (sa_family == AF_UNIX) {
1131 if (len < unix_maxlen && len > 0) {
1132 char *cp = (char*)target_saddr;
1133
1134 if ( cp[len-1] && !cp[len] )
1135 len++;
1136 }
1137 if (len > unix_maxlen)
1138 len = unix_maxlen;
1139 }
1140
pbrook53a59602006-03-25 19:31:22 +00001141 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001142 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001143 if (sa_family == AF_PACKET) {
1144 struct target_sockaddr_ll *lladdr;
1145
1146 lladdr = (struct target_sockaddr_ll *)addr;
1147 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1148 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1149 }
pbrook53a59602006-03-25 19:31:22 +00001150 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001151
1152 return 0;
bellard7854b052003-03-29 17:22:23 +00001153}
1154
bellard579a97f2007-11-11 14:26:47 +00001155static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1156 struct sockaddr *addr,
1157 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001158{
pbrook53a59602006-03-25 19:31:22 +00001159 struct target_sockaddr *target_saddr;
1160
bellard579a97f2007-11-11 14:26:47 +00001161 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1162 if (!target_saddr)
1163 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001164 memcpy(target_saddr, addr, len);
1165 target_saddr->sa_family = tswap16(addr->sa_family);
1166 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001167
1168 return 0;
bellard7854b052003-03-29 17:22:23 +00001169}
1170
bellard5a4a8982007-11-11 17:39:18 +00001171static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1172 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001173{
1174 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001175 abi_long msg_controllen;
1176 abi_ulong target_cmsg_addr;
1177 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001178 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001179
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001180 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001181 if (msg_controllen < sizeof (struct target_cmsghdr))
1182 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001183 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001184 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1185 if (!target_cmsg)
1186 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001187
1188 while (cmsg && target_cmsg) {
1189 void *data = CMSG_DATA(cmsg);
1190 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1191
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001192 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001193 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1194
1195 space += CMSG_SPACE(len);
1196 if (space > msgh->msg_controllen) {
1197 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001198 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001199 break;
1200 }
1201
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001202 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1203 cmsg->cmsg_level = SOL_SOCKET;
1204 } else {
1205 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1206 }
bellard7854b052003-03-29 17:22:23 +00001207 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1208 cmsg->cmsg_len = CMSG_LEN(len);
1209
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001210 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001211 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1212 memcpy(data, target_data, len);
1213 } else {
1214 int *fd = (int *)data;
1215 int *target_fd = (int *)target_data;
1216 int i, numfds = len / sizeof(int);
1217
1218 for (i = 0; i < numfds; i++)
1219 fd[i] = tswap32(target_fd[i]);
1220 }
1221
1222 cmsg = CMSG_NXTHDR(msgh, cmsg);
1223 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1224 }
bellard5a4a8982007-11-11 17:39:18 +00001225 unlock_user(target_cmsg, target_cmsg_addr, 0);
1226 the_end:
bellard7854b052003-03-29 17:22:23 +00001227 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001228 return 0;
bellard7854b052003-03-29 17:22:23 +00001229}
1230
bellard5a4a8982007-11-11 17:39:18 +00001231static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1232 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001233{
1234 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001235 abi_long msg_controllen;
1236 abi_ulong target_cmsg_addr;
1237 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001238 socklen_t space = 0;
1239
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001240 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001241 if (msg_controllen < sizeof (struct target_cmsghdr))
1242 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001243 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001244 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1245 if (!target_cmsg)
1246 return -TARGET_EFAULT;
1247
bellard7854b052003-03-29 17:22:23 +00001248 while (cmsg && target_cmsg) {
1249 void *data = CMSG_DATA(cmsg);
1250 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1251
1252 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1253
1254 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001255 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001256 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001257 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001258 break;
1259 }
1260
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001261 if (cmsg->cmsg_level == SOL_SOCKET) {
1262 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1263 } else {
1264 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1265 }
bellard7854b052003-03-29 17:22:23 +00001266 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001267 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001268
Huw Davies52b65492014-04-17 14:02:47 +01001269 switch (cmsg->cmsg_level) {
1270 case SOL_SOCKET:
1271 switch (cmsg->cmsg_type) {
1272 case SCM_RIGHTS:
1273 {
1274 int *fd = (int *)data;
1275 int *target_fd = (int *)target_data;
1276 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001277
Huw Davies52b65492014-04-17 14:02:47 +01001278 for (i = 0; i < numfds; i++)
1279 target_fd[i] = tswap32(fd[i]);
1280 break;
1281 }
1282 case SO_TIMESTAMP:
1283 {
1284 struct timeval *tv = (struct timeval *)data;
1285 struct target_timeval *target_tv =
1286 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001287
Huw Davies52b65492014-04-17 14:02:47 +01001288 if (len != sizeof(struct timeval))
1289 goto unimplemented;
1290
1291 /* copy struct timeval to target */
1292 target_tv->tv_sec = tswapal(tv->tv_sec);
1293 target_tv->tv_usec = tswapal(tv->tv_usec);
1294 break;
1295 }
Huw Davies4bc29752014-04-17 14:02:48 +01001296 case SCM_CREDENTIALS:
1297 {
1298 struct ucred *cred = (struct ucred *)data;
1299 struct target_ucred *target_cred =
1300 (struct target_ucred *)target_data;
1301
1302 __put_user(cred->pid, &target_cred->pid);
1303 __put_user(cred->uid, &target_cred->uid);
1304 __put_user(cred->gid, &target_cred->gid);
1305 break;
1306 }
Huw Davies52b65492014-04-17 14:02:47 +01001307 default:
1308 goto unimplemented;
1309 }
1310 break;
1311
1312 default:
1313 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001314 gemu_log("Unsupported ancillary data: %d/%d\n",
1315 cmsg->cmsg_level, cmsg->cmsg_type);
1316 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001317 }
1318
1319 cmsg = CMSG_NXTHDR(msgh, cmsg);
1320 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1321 }
bellard5a4a8982007-11-11 17:39:18 +00001322 unlock_user(target_cmsg, target_cmsg_addr, space);
1323 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001324 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001325 return 0;
bellard7854b052003-03-29 17:22:23 +00001326}
1327
ths0da46a62007-10-20 20:23:07 +00001328/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001329static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001330 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001331{
blueswir1992f48a2007-10-14 16:27:31 +00001332 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001333 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001334 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001335 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001336
bellard8853f862004-02-22 14:57:26 +00001337 switch(level) {
1338 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001339 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001340 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001341 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001342
bellard2f619692007-11-16 10:46:05 +00001343 if (get_user_u32(val, optval_addr))
1344 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001345 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1346 break;
1347 case SOL_IP:
1348 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001349 case IP_TOS:
1350 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001351 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001352 case IP_ROUTER_ALERT:
1353 case IP_RECVOPTS:
1354 case IP_RETOPTS:
1355 case IP_PKTINFO:
1356 case IP_MTU_DISCOVER:
1357 case IP_RECVERR:
1358 case IP_RECVTOS:
1359#ifdef IP_FREEBIND
1360 case IP_FREEBIND:
1361#endif
1362 case IP_MULTICAST_TTL:
1363 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001364 val = 0;
1365 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001366 if (get_user_u32(val, optval_addr))
1367 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001368 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001369 if (get_user_u8(val, optval_addr))
1370 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001371 }
1372 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1373 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001374 case IP_ADD_MEMBERSHIP:
1375 case IP_DROP_MEMBERSHIP:
1376 if (optlen < sizeof (struct target_ip_mreq) ||
1377 optlen > sizeof (struct target_ip_mreqn))
1378 return -TARGET_EINVAL;
1379
1380 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1381 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1382 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1383 break;
1384
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001385 case IP_BLOCK_SOURCE:
1386 case IP_UNBLOCK_SOURCE:
1387 case IP_ADD_SOURCE_MEMBERSHIP:
1388 case IP_DROP_SOURCE_MEMBERSHIP:
1389 if (optlen != sizeof (struct target_ip_mreq_source))
1390 return -TARGET_EINVAL;
1391
1392 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1393 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1394 unlock_user (ip_mreq_source, optval_addr, 0);
1395 break;
1396
bellard8853f862004-02-22 14:57:26 +00001397 default:
1398 goto unimplemented;
1399 }
1400 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001401 case SOL_IPV6:
1402 switch (optname) {
1403 case IPV6_MTU_DISCOVER:
1404 case IPV6_MTU:
1405 case IPV6_V6ONLY:
1406 case IPV6_RECVPKTINFO:
1407 val = 0;
1408 if (optlen < sizeof(uint32_t)) {
1409 return -TARGET_EINVAL;
1410 }
1411 if (get_user_u32(val, optval_addr)) {
1412 return -TARGET_EFAULT;
1413 }
1414 ret = get_errno(setsockopt(sockfd, level, optname,
1415 &val, sizeof(val)));
1416 break;
1417 default:
1418 goto unimplemented;
1419 }
1420 break;
Jing Huang920394d2012-07-24 13:59:23 +00001421 case SOL_RAW:
1422 switch (optname) {
1423 case ICMP_FILTER:
1424 /* struct icmp_filter takes an u32 value */
1425 if (optlen < sizeof(uint32_t)) {
1426 return -TARGET_EINVAL;
1427 }
1428
1429 if (get_user_u32(val, optval_addr)) {
1430 return -TARGET_EFAULT;
1431 }
1432 ret = get_errno(setsockopt(sockfd, level, optname,
1433 &val, sizeof(val)));
1434 break;
1435
1436 default:
1437 goto unimplemented;
1438 }
1439 break;
bellard3532fa72006-06-24 15:06:03 +00001440 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001441 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001442 case TARGET_SO_RCVTIMEO:
1443 {
1444 struct timeval tv;
1445
1446 optname = SO_RCVTIMEO;
1447
1448set_timeout:
1449 if (optlen != sizeof(struct target_timeval)) {
1450 return -TARGET_EINVAL;
1451 }
1452
1453 if (copy_from_user_timeval(&tv, optval_addr)) {
1454 return -TARGET_EFAULT;
1455 }
1456
1457 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1458 &tv, sizeof(tv)));
1459 return ret;
1460 }
1461 case TARGET_SO_SNDTIMEO:
1462 optname = SO_SNDTIMEO;
1463 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001464 case TARGET_SO_ATTACH_FILTER:
1465 {
1466 struct target_sock_fprog *tfprog;
1467 struct target_sock_filter *tfilter;
1468 struct sock_fprog fprog;
1469 struct sock_filter *filter;
1470 int i;
1471
1472 if (optlen != sizeof(*tfprog)) {
1473 return -TARGET_EINVAL;
1474 }
1475 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1476 return -TARGET_EFAULT;
1477 }
1478 if (!lock_user_struct(VERIFY_READ, tfilter,
1479 tswapal(tfprog->filter), 0)) {
1480 unlock_user_struct(tfprog, optval_addr, 1);
1481 return -TARGET_EFAULT;
1482 }
1483
1484 fprog.len = tswap16(tfprog->len);
1485 filter = malloc(fprog.len * sizeof(*filter));
1486 if (filter == NULL) {
1487 unlock_user_struct(tfilter, tfprog->filter, 1);
1488 unlock_user_struct(tfprog, optval_addr, 1);
1489 return -TARGET_ENOMEM;
1490 }
1491 for (i = 0; i < fprog.len; i++) {
1492 filter[i].code = tswap16(tfilter[i].code);
1493 filter[i].jt = tfilter[i].jt;
1494 filter[i].jf = tfilter[i].jf;
1495 filter[i].k = tswap32(tfilter[i].k);
1496 }
1497 fprog.filter = filter;
1498
1499 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1500 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1501 free(filter);
1502
1503 unlock_user_struct(tfilter, tfprog->filter, 1);
1504 unlock_user_struct(tfprog, optval_addr, 1);
1505 return ret;
1506 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001507 case TARGET_SO_BINDTODEVICE:
1508 {
1509 char *dev_ifname, *addr_ifname;
1510
1511 if (optlen > IFNAMSIZ - 1) {
1512 optlen = IFNAMSIZ - 1;
1513 }
1514 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1515 if (!dev_ifname) {
1516 return -TARGET_EFAULT;
1517 }
1518 optname = SO_BINDTODEVICE;
1519 addr_ifname = alloca(IFNAMSIZ);
1520 memcpy(addr_ifname, dev_ifname, optlen);
1521 addr_ifname[optlen] = 0;
1522 ret = get_errno(setsockopt(sockfd, level, optname, addr_ifname, optlen));
1523 unlock_user (dev_ifname, optval_addr, 0);
1524 return ret;
1525 }
bellard8853f862004-02-22 14:57:26 +00001526 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001527 case TARGET_SO_DEBUG:
1528 optname = SO_DEBUG;
1529 break;
1530 case TARGET_SO_REUSEADDR:
1531 optname = SO_REUSEADDR;
1532 break;
1533 case TARGET_SO_TYPE:
1534 optname = SO_TYPE;
1535 break;
1536 case TARGET_SO_ERROR:
1537 optname = SO_ERROR;
1538 break;
1539 case TARGET_SO_DONTROUTE:
1540 optname = SO_DONTROUTE;
1541 break;
1542 case TARGET_SO_BROADCAST:
1543 optname = SO_BROADCAST;
1544 break;
1545 case TARGET_SO_SNDBUF:
1546 optname = SO_SNDBUF;
1547 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001548 case TARGET_SO_SNDBUFFORCE:
1549 optname = SO_SNDBUFFORCE;
1550 break;
bellard3532fa72006-06-24 15:06:03 +00001551 case TARGET_SO_RCVBUF:
1552 optname = SO_RCVBUF;
1553 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001554 case TARGET_SO_RCVBUFFORCE:
1555 optname = SO_RCVBUFFORCE;
1556 break;
bellard3532fa72006-06-24 15:06:03 +00001557 case TARGET_SO_KEEPALIVE:
1558 optname = SO_KEEPALIVE;
1559 break;
1560 case TARGET_SO_OOBINLINE:
1561 optname = SO_OOBINLINE;
1562 break;
1563 case TARGET_SO_NO_CHECK:
1564 optname = SO_NO_CHECK;
1565 break;
1566 case TARGET_SO_PRIORITY:
1567 optname = SO_PRIORITY;
1568 break;
bellard5e83e8e2005-03-01 22:32:06 +00001569#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001570 case TARGET_SO_BSDCOMPAT:
1571 optname = SO_BSDCOMPAT;
1572 break;
bellard5e83e8e2005-03-01 22:32:06 +00001573#endif
bellard3532fa72006-06-24 15:06:03 +00001574 case TARGET_SO_PASSCRED:
1575 optname = SO_PASSCRED;
1576 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001577 case TARGET_SO_PASSSEC:
1578 optname = SO_PASSSEC;
1579 break;
bellard3532fa72006-06-24 15:06:03 +00001580 case TARGET_SO_TIMESTAMP:
1581 optname = SO_TIMESTAMP;
1582 break;
1583 case TARGET_SO_RCVLOWAT:
1584 optname = SO_RCVLOWAT;
1585 break;
bellard8853f862004-02-22 14:57:26 +00001586 break;
1587 default:
1588 goto unimplemented;
1589 }
bellard3532fa72006-06-24 15:06:03 +00001590 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001591 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001592
bellard2f619692007-11-16 10:46:05 +00001593 if (get_user_u32(val, optval_addr))
1594 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001595 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001596 break;
bellard7854b052003-03-29 17:22:23 +00001597 default:
bellard8853f862004-02-22 14:57:26 +00001598 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001599 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001600 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001601 }
bellard8853f862004-02-22 14:57:26 +00001602 return ret;
bellard7854b052003-03-29 17:22:23 +00001603}
1604
ths0da46a62007-10-20 20:23:07 +00001605/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001606static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001607 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001608{
blueswir1992f48a2007-10-14 16:27:31 +00001609 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001610 int len, val;
1611 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001612
1613 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001614 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001615 level = SOL_SOCKET;
1616 switch (optname) {
1617 /* These don't just return a single integer */
1618 case TARGET_SO_LINGER:
1619 case TARGET_SO_RCVTIMEO:
1620 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001621 case TARGET_SO_PEERNAME:
1622 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001623 case TARGET_SO_PEERCRED: {
1624 struct ucred cr;
1625 socklen_t crlen;
1626 struct target_ucred *tcr;
1627
1628 if (get_user_u32(len, optlen)) {
1629 return -TARGET_EFAULT;
1630 }
1631 if (len < 0) {
1632 return -TARGET_EINVAL;
1633 }
1634
1635 crlen = sizeof(cr);
1636 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1637 &cr, &crlen));
1638 if (ret < 0) {
1639 return ret;
1640 }
1641 if (len > crlen) {
1642 len = crlen;
1643 }
1644 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1645 return -TARGET_EFAULT;
1646 }
1647 __put_user(cr.pid, &tcr->pid);
1648 __put_user(cr.uid, &tcr->uid);
1649 __put_user(cr.gid, &tcr->gid);
1650 unlock_user_struct(tcr, optval_addr, 1);
1651 if (put_user_u32(len, optlen)) {
1652 return -TARGET_EFAULT;
1653 }
1654 break;
1655 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001656 /* Options with 'int' argument. */
1657 case TARGET_SO_DEBUG:
1658 optname = SO_DEBUG;
1659 goto int_case;
1660 case TARGET_SO_REUSEADDR:
1661 optname = SO_REUSEADDR;
1662 goto int_case;
1663 case TARGET_SO_TYPE:
1664 optname = SO_TYPE;
1665 goto int_case;
1666 case TARGET_SO_ERROR:
1667 optname = SO_ERROR;
1668 goto int_case;
1669 case TARGET_SO_DONTROUTE:
1670 optname = SO_DONTROUTE;
1671 goto int_case;
1672 case TARGET_SO_BROADCAST:
1673 optname = SO_BROADCAST;
1674 goto int_case;
1675 case TARGET_SO_SNDBUF:
1676 optname = SO_SNDBUF;
1677 goto int_case;
1678 case TARGET_SO_RCVBUF:
1679 optname = SO_RCVBUF;
1680 goto int_case;
1681 case TARGET_SO_KEEPALIVE:
1682 optname = SO_KEEPALIVE;
1683 goto int_case;
1684 case TARGET_SO_OOBINLINE:
1685 optname = SO_OOBINLINE;
1686 goto int_case;
1687 case TARGET_SO_NO_CHECK:
1688 optname = SO_NO_CHECK;
1689 goto int_case;
1690 case TARGET_SO_PRIORITY:
1691 optname = SO_PRIORITY;
1692 goto int_case;
1693#ifdef SO_BSDCOMPAT
1694 case TARGET_SO_BSDCOMPAT:
1695 optname = SO_BSDCOMPAT;
1696 goto int_case;
1697#endif
1698 case TARGET_SO_PASSCRED:
1699 optname = SO_PASSCRED;
1700 goto int_case;
1701 case TARGET_SO_TIMESTAMP:
1702 optname = SO_TIMESTAMP;
1703 goto int_case;
1704 case TARGET_SO_RCVLOWAT:
1705 optname = SO_RCVLOWAT;
1706 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001707 case TARGET_SO_ACCEPTCONN:
1708 optname = SO_ACCEPTCONN;
1709 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001710 default:
bellard2efbe912005-07-23 15:10:20 +00001711 goto int_case;
1712 }
1713 break;
1714 case SOL_TCP:
1715 /* TCP options all take an 'int' value. */
1716 int_case:
bellard2f619692007-11-16 10:46:05 +00001717 if (get_user_u32(len, optlen))
1718 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001719 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001720 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001721 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001722 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1723 if (ret < 0)
1724 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001725 if (optname == SO_TYPE) {
1726 val = host_to_target_sock_type(val);
1727 }
bellard2efbe912005-07-23 15:10:20 +00001728 if (len > lv)
1729 len = lv;
bellard2f619692007-11-16 10:46:05 +00001730 if (len == 4) {
1731 if (put_user_u32(val, optval_addr))
1732 return -TARGET_EFAULT;
1733 } else {
1734 if (put_user_u8(val, optval_addr))
1735 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001736 }
bellard2f619692007-11-16 10:46:05 +00001737 if (put_user_u32(len, optlen))
1738 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001739 break;
1740 case SOL_IP:
1741 switch(optname) {
1742 case IP_TOS:
1743 case IP_TTL:
1744 case IP_HDRINCL:
1745 case IP_ROUTER_ALERT:
1746 case IP_RECVOPTS:
1747 case IP_RETOPTS:
1748 case IP_PKTINFO:
1749 case IP_MTU_DISCOVER:
1750 case IP_RECVERR:
1751 case IP_RECVTOS:
1752#ifdef IP_FREEBIND
1753 case IP_FREEBIND:
1754#endif
1755 case IP_MULTICAST_TTL:
1756 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001757 if (get_user_u32(len, optlen))
1758 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001759 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001760 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001761 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001762 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1763 if (ret < 0)
1764 return ret;
bellard2efbe912005-07-23 15:10:20 +00001765 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001766 len = 1;
bellard2f619692007-11-16 10:46:05 +00001767 if (put_user_u32(len, optlen)
1768 || put_user_u8(val, optval_addr))
1769 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001770 } else {
bellard2efbe912005-07-23 15:10:20 +00001771 if (len > sizeof(int))
1772 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001773 if (put_user_u32(len, optlen)
1774 || put_user_u32(val, optval_addr))
1775 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001776 }
bellard8853f862004-02-22 14:57:26 +00001777 break;
bellard2efbe912005-07-23 15:10:20 +00001778 default:
thsc02f4992007-12-18 02:39:59 +00001779 ret = -TARGET_ENOPROTOOPT;
1780 break;
bellard8853f862004-02-22 14:57:26 +00001781 }
1782 break;
1783 default:
1784 unimplemented:
1785 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1786 level, optname);
thsc02f4992007-12-18 02:39:59 +00001787 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001788 break;
1789 }
1790 return ret;
bellard7854b052003-03-29 17:22:23 +00001791}
1792
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001793static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1794 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001795{
1796 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001797 struct iovec *vec;
1798 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001799 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001800 int err = 0;
pbrook53a59602006-03-25 19:31:22 +00001801
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001802 if (count == 0) {
1803 errno = 0;
1804 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001805 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001806 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001807 errno = EINVAL;
1808 return NULL;
1809 }
1810
1811 vec = calloc(count, sizeof(struct iovec));
1812 if (vec == NULL) {
1813 errno = ENOMEM;
1814 return NULL;
1815 }
1816
1817 target_vec = lock_user(VERIFY_READ, target_addr,
1818 count * sizeof(struct target_iovec), 1);
1819 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001820 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001821 goto fail2;
1822 }
1823
1824 /* ??? If host page size > target page size, this will result in a
1825 value larger than what we can actually support. */
1826 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1827 total_len = 0;
1828
1829 for (i = 0; i < count; i++) {
1830 abi_ulong base = tswapal(target_vec[i].iov_base);
1831 abi_long len = tswapal(target_vec[i].iov_len);
1832
1833 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001834 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001835 goto fail;
1836 } else if (len == 0) {
1837 /* Zero length pointer is ignored. */
1838 vec[i].iov_base = 0;
1839 } else {
1840 vec[i].iov_base = lock_user(type, base, len, copy);
1841 if (!vec[i].iov_base) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001842 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001843 goto fail;
1844 }
1845 if (len > max_len - total_len) {
1846 len = max_len - total_len;
1847 }
1848 }
1849 vec[i].iov_len = len;
1850 total_len += len;
1851 }
1852
1853 unlock_user(target_vec, target_addr, 0);
1854 return vec;
1855
1856 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001857 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001858 fail2:
1859 free(vec);
1860 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001861 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001862}
1863
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001864static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1865 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001866{
1867 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001868 int i;
1869
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001870 target_vec = lock_user(VERIFY_READ, target_addr,
1871 count * sizeof(struct target_iovec), 1);
1872 if (target_vec) {
1873 for (i = 0; i < count; i++) {
1874 abi_ulong base = tswapal(target_vec[i].iov_base);
1875 abi_long len = tswapal(target_vec[i].iov_base);
1876 if (len < 0) {
1877 break;
1878 }
balrogd732dcb2008-10-28 10:21:03 +00001879 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1880 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001881 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001882 }
bellard579a97f2007-11-11 14:26:47 +00001883
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001884 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001885}
1886
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001887static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001888{
1889 int host_type = 0;
1890 int target_type = *type;
1891
1892 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1893 case TARGET_SOCK_DGRAM:
1894 host_type = SOCK_DGRAM;
1895 break;
1896 case TARGET_SOCK_STREAM:
1897 host_type = SOCK_STREAM;
1898 break;
1899 default:
1900 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1901 break;
1902 }
1903 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001904#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001905 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001906#else
1907 return -TARGET_EINVAL;
1908#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001909 }
1910 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001911#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001912 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001913#elif !defined(O_NONBLOCK)
1914 return -TARGET_EINVAL;
1915#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001916 }
1917 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001918 return 0;
1919}
1920
1921/* Try to emulate socket type flags after socket creation. */
1922static int sock_flags_fixup(int fd, int target_type)
1923{
1924#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1925 if (target_type & TARGET_SOCK_NONBLOCK) {
1926 int flags = fcntl(fd, F_GETFL);
1927 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1928 close(fd);
1929 return -TARGET_EINVAL;
1930 }
1931 }
1932#endif
1933 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001934}
1935
ths0da46a62007-10-20 20:23:07 +00001936/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001937static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001938{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001939 int target_type = type;
1940 int ret;
1941
1942 ret = target_to_host_sock_type(&type);
1943 if (ret) {
1944 return ret;
1945 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001946
balrog12bc92a2007-10-30 21:06:14 +00001947 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07001948 return -TARGET_EAFNOSUPPORT;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001949 ret = get_errno(socket(domain, type, protocol));
1950 if (ret >= 0) {
1951 ret = sock_flags_fixup(ret, target_type);
1952 }
1953 return ret;
bellard3532fa72006-06-24 15:06:03 +00001954}
1955
ths0da46a62007-10-20 20:23:07 +00001956/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001957static abi_long do_bind(int sockfd, abi_ulong target_addr,
1958 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001959{
aurel328f7aeaf2009-01-30 19:47:57 +00001960 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001961 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001962
Blue Swirl38724252010-09-18 05:53:14 +00001963 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001964 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001965 }
aurel328f7aeaf2009-01-30 19:47:57 +00001966
aurel32607175e2009-04-15 16:11:59 +00001967 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001968
Arnaud Patard917507b2009-06-19 10:44:45 +03001969 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1970 if (ret)
1971 return ret;
1972
bellard3532fa72006-06-24 15:06:03 +00001973 return get_errno(bind(sockfd, addr, addrlen));
1974}
1975
ths0da46a62007-10-20 20:23:07 +00001976/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001977static abi_long do_connect(int sockfd, abi_ulong target_addr,
1978 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001979{
aurel328f7aeaf2009-01-30 19:47:57 +00001980 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001981 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001982
Blue Swirl38724252010-09-18 05:53:14 +00001983 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001984 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001985 }
aurel328f7aeaf2009-01-30 19:47:57 +00001986
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02001987 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001988
Arnaud Patard917507b2009-06-19 10:44:45 +03001989 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1990 if (ret)
1991 return ret;
1992
bellard3532fa72006-06-24 15:06:03 +00001993 return get_errno(connect(sockfd, addr, addrlen));
1994}
1995
Alexander Graff19e00d2014-03-02 19:36:42 +00001996/* do_sendrecvmsg_locked() Must return target values and target errnos. */
1997static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
1998 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001999{
balrog6de645c2008-10-28 10:26:29 +00002000 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002001 struct msghdr msg;
2002 int count;
2003 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002004 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002005
bellard3532fa72006-06-24 15:06:03 +00002006 if (msgp->msg_name) {
2007 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002008 msg.msg_name = alloca(msg.msg_namelen+1);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002009 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00002010 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002011 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002012 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002013 }
bellard3532fa72006-06-24 15:06:03 +00002014 } else {
2015 msg.msg_name = NULL;
2016 msg.msg_namelen = 0;
2017 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002018 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002019 msg.msg_control = alloca(msg.msg_controllen);
2020 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002021
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002022 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002023 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002024 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2025 target_vec, count, send);
2026 if (vec == NULL) {
2027 ret = -host_to_target_errno(errno);
2028 goto out2;
2029 }
bellard3532fa72006-06-24 15:06:03 +00002030 msg.msg_iovlen = count;
2031 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002032
bellard3532fa72006-06-24 15:06:03 +00002033 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002034 ret = target_to_host_cmsg(&msg, msgp);
2035 if (ret == 0)
2036 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002037 } else {
2038 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002039 if (!is_error(ret)) {
2040 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002041 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002042 if (!is_error(ret)) {
2043 msgp->msg_namelen = tswap32(msg.msg_namelen);
2044 if (msg.msg_name != NULL) {
2045 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2046 msg.msg_name, msg.msg_namelen);
2047 if (ret) {
2048 goto out;
2049 }
2050 }
2051
balrog6de645c2008-10-28 10:26:29 +00002052 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002053 }
balrog6de645c2008-10-28 10:26:29 +00002054 }
bellard3532fa72006-06-24 15:06:03 +00002055 }
Jing Huangca619062012-07-24 13:58:02 +00002056
2057out:
bellard3532fa72006-06-24 15:06:03 +00002058 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002059out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002060 return ret;
2061}
2062
2063static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2064 int flags, int send)
2065{
2066 abi_long ret;
2067 struct target_msghdr *msgp;
2068
2069 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2070 msgp,
2071 target_msg,
2072 send ? 1 : 0)) {
2073 return -TARGET_EFAULT;
2074 }
2075 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002076 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002077 return ret;
2078}
2079
Alexander Graff19e00d2014-03-02 19:36:42 +00002080#ifdef TARGET_NR_sendmmsg
2081/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2082 * so it might not have this *mmsg-specific flag either.
2083 */
2084#ifndef MSG_WAITFORONE
2085#define MSG_WAITFORONE 0x10000
2086#endif
2087
2088static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2089 unsigned int vlen, unsigned int flags,
2090 int send)
2091{
2092 struct target_mmsghdr *mmsgp;
2093 abi_long ret = 0;
2094 int i;
2095
2096 if (vlen > UIO_MAXIOV) {
2097 vlen = UIO_MAXIOV;
2098 }
2099
2100 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2101 if (!mmsgp) {
2102 return -TARGET_EFAULT;
2103 }
2104
2105 for (i = 0; i < vlen; i++) {
2106 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2107 if (is_error(ret)) {
2108 break;
2109 }
2110 mmsgp[i].msg_len = tswap32(ret);
2111 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2112 if (flags & MSG_WAITFORONE) {
2113 flags |= MSG_DONTWAIT;
2114 }
2115 }
2116
2117 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2118
2119 /* Return number of datagrams sent if we sent any at all;
2120 * otherwise return the error.
2121 */
2122 if (i) {
2123 return i;
2124 }
2125 return ret;
2126}
2127#endif
2128
Peter Maydella94b4982013-02-08 04:35:04 +00002129/* If we don't have a system accept4() then just call accept.
2130 * The callsites to do_accept4() will ensure that they don't
2131 * pass a non-zero flags argument in this config.
2132 */
2133#ifndef CONFIG_ACCEPT4
2134static inline int accept4(int sockfd, struct sockaddr *addr,
2135 socklen_t *addrlen, int flags)
2136{
2137 assert(flags == 0);
2138 return accept(sockfd, addr, addrlen);
2139}
2140#endif
2141
2142/* do_accept4() Must return target values and target errnos. */
2143static abi_long do_accept4(int fd, abi_ulong target_addr,
2144 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002145{
bellard2f619692007-11-16 10:46:05 +00002146 socklen_t addrlen;
2147 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002148 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002149 int host_flags;
2150
2151 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002152
Peter Maydella94b4982013-02-08 04:35:04 +00002153 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002154 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002155 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002156
2157 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002158 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002159 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002160
Blue Swirl38724252010-09-18 05:53:14 +00002161 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002162 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002163 }
aurel328f7aeaf2009-01-30 19:47:57 +00002164
Arnaud Patard917507b2009-06-19 10:44:45 +03002165 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2166 return -TARGET_EINVAL;
2167
bellard2f619692007-11-16 10:46:05 +00002168 addr = alloca(addrlen);
2169
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002170 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002171 if (!is_error(ret)) {
2172 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002173 if (put_user_u32(addrlen, target_addrlen_addr))
2174 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002175 }
2176 return ret;
2177}
2178
ths0da46a62007-10-20 20:23:07 +00002179/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002180static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002181 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002182{
bellard2f619692007-11-16 10:46:05 +00002183 socklen_t addrlen;
2184 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002185 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002186
bellard2f619692007-11-16 10:46:05 +00002187 if (get_user_u32(addrlen, target_addrlen_addr))
2188 return -TARGET_EFAULT;
2189
Blue Swirl38724252010-09-18 05:53:14 +00002190 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002191 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002192 }
aurel328f7aeaf2009-01-30 19:47:57 +00002193
Arnaud Patard917507b2009-06-19 10:44:45 +03002194 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2195 return -TARGET_EFAULT;
2196
bellard2f619692007-11-16 10:46:05 +00002197 addr = alloca(addrlen);
2198
pbrook1be9e1d2006-11-19 15:26:04 +00002199 ret = get_errno(getpeername(fd, addr, &addrlen));
2200 if (!is_error(ret)) {
2201 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002202 if (put_user_u32(addrlen, target_addrlen_addr))
2203 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002204 }
2205 return ret;
2206}
2207
ths0da46a62007-10-20 20:23:07 +00002208/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002209static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002210 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002211{
bellard2f619692007-11-16 10:46:05 +00002212 socklen_t addrlen;
2213 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002214 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002215
bellard2f619692007-11-16 10:46:05 +00002216 if (get_user_u32(addrlen, target_addrlen_addr))
2217 return -TARGET_EFAULT;
2218
Blue Swirl38724252010-09-18 05:53:14 +00002219 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002220 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002221 }
aurel328f7aeaf2009-01-30 19:47:57 +00002222
Arnaud Patard917507b2009-06-19 10:44:45 +03002223 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2224 return -TARGET_EFAULT;
2225
bellard2f619692007-11-16 10:46:05 +00002226 addr = alloca(addrlen);
2227
pbrook1be9e1d2006-11-19 15:26:04 +00002228 ret = get_errno(getsockname(fd, addr, &addrlen));
2229 if (!is_error(ret)) {
2230 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002231 if (put_user_u32(addrlen, target_addrlen_addr))
2232 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002233 }
2234 return ret;
2235}
2236
ths0da46a62007-10-20 20:23:07 +00002237/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002238static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002239 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002240{
2241 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002242 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002243
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002244 target_to_host_sock_type(&type);
2245
pbrook1be9e1d2006-11-19 15:26:04 +00002246 ret = get_errno(socketpair(domain, type, protocol, tab));
2247 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002248 if (put_user_s32(tab[0], target_tab_addr)
2249 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2250 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002251 }
2252 return ret;
2253}
2254
ths0da46a62007-10-20 20:23:07 +00002255/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002256static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2257 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002258{
2259 void *addr;
2260 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002261 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002262
Blue Swirl38724252010-09-18 05:53:14 +00002263 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002264 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002265 }
aurel328f7aeaf2009-01-30 19:47:57 +00002266
bellard579a97f2007-11-11 14:26:47 +00002267 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2268 if (!host_msg)
2269 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002270 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002271 addr = alloca(addrlen+1);
Arnaud Patard917507b2009-06-19 10:44:45 +03002272 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2273 if (ret) {
2274 unlock_user(host_msg, msg, 0);
2275 return ret;
2276 }
pbrook1be9e1d2006-11-19 15:26:04 +00002277 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2278 } else {
2279 ret = get_errno(send(fd, host_msg, len, flags));
2280 }
2281 unlock_user(host_msg, msg, 0);
2282 return ret;
2283}
2284
ths0da46a62007-10-20 20:23:07 +00002285/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002286static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2287 abi_ulong target_addr,
2288 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002289{
2290 socklen_t addrlen;
2291 void *addr;
2292 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002293 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002294
bellard579a97f2007-11-11 14:26:47 +00002295 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2296 if (!host_msg)
2297 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002298 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002299 if (get_user_u32(addrlen, target_addrlen)) {
2300 ret = -TARGET_EFAULT;
2301 goto fail;
2302 }
Blue Swirl38724252010-09-18 05:53:14 +00002303 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002304 ret = -TARGET_EINVAL;
2305 goto fail;
2306 }
pbrook1be9e1d2006-11-19 15:26:04 +00002307 addr = alloca(addrlen);
2308 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2309 } else {
2310 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002311 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002312 }
2313 if (!is_error(ret)) {
2314 if (target_addr) {
2315 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002316 if (put_user_u32(addrlen, target_addrlen)) {
2317 ret = -TARGET_EFAULT;
2318 goto fail;
2319 }
pbrook1be9e1d2006-11-19 15:26:04 +00002320 }
2321 unlock_user(host_msg, msg, len);
2322 } else {
bellard2f619692007-11-16 10:46:05 +00002323fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002324 unlock_user(host_msg, msg, 0);
2325 }
2326 return ret;
2327}
2328
j_mayer32407102007-09-26 23:01:49 +00002329#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002330/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002331static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002332{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002333 static const unsigned ac[] = { /* number of arguments per call */
2334 [SOCKOP_socket] = 3, /* domain, type, protocol */
2335 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2336 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2337 [SOCKOP_listen] = 2, /* sockfd, backlog */
2338 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2339 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2340 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2341 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2342 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2343 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2344 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2345 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2346 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2347 [SOCKOP_shutdown] = 2, /* sockfd, how */
2348 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2349 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2350 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2351 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2352 };
2353 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002354
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002355 /* first, collect the arguments in a[] according to ac[] */
2356 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2357 unsigned i;
2358 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2359 for (i = 0; i < ac[num]; ++i) {
2360 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002361 return -TARGET_EFAULT;
2362 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002363 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002364 }
bellard2f619692007-11-16 10:46:05 +00002365
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002366 /* now when we have the args, actually handle the call */
2367 switch (num) {
2368 case SOCKOP_socket: /* domain, type, protocol */
2369 return do_socket(a[0], a[1], a[2]);
2370 case SOCKOP_bind: /* sockfd, addr, addrlen */
2371 return do_bind(a[0], a[1], a[2]);
2372 case SOCKOP_connect: /* sockfd, addr, addrlen */
2373 return do_connect(a[0], a[1], a[2]);
2374 case SOCKOP_listen: /* sockfd, backlog */
2375 return get_errno(listen(a[0], a[1]));
2376 case SOCKOP_accept: /* sockfd, addr, addrlen */
2377 return do_accept4(a[0], a[1], a[2], 0);
2378 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2379 return do_accept4(a[0], a[1], a[2], a[3]);
2380 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2381 return do_getsockname(a[0], a[1], a[2]);
2382 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2383 return do_getpeername(a[0], a[1], a[2]);
2384 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2385 return do_socketpair(a[0], a[1], a[2], a[3]);
2386 case SOCKOP_send: /* sockfd, msg, len, flags */
2387 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2388 case SOCKOP_recv: /* sockfd, msg, len, flags */
2389 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2390 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2391 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2392 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2393 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2394 case SOCKOP_shutdown: /* sockfd, how */
2395 return get_errno(shutdown(a[0], a[1]));
2396 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2397 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2398 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2399 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2400 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2401 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2402 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2403 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002404 default:
2405 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002406 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002407 }
bellard31e31b82003-02-18 22:55:36 +00002408}
j_mayer32407102007-09-26 23:01:49 +00002409#endif
bellard31e31b82003-02-18 22:55:36 +00002410
bellard8853f862004-02-22 14:57:26 +00002411#define N_SHM_REGIONS 32
2412
2413static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002414 abi_ulong start;
2415 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002416} shm_regions[N_SHM_REGIONS];
2417
ths3eb6b042007-06-03 14:26:27 +00002418struct target_semid_ds
2419{
2420 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002421 abi_ulong sem_otime;
2422 abi_ulong __unused1;
2423 abi_ulong sem_ctime;
2424 abi_ulong __unused2;
2425 abi_ulong sem_nsems;
2426 abi_ulong __unused3;
2427 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002428};
2429
bellard579a97f2007-11-11 14:26:47 +00002430static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2431 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002432{
2433 struct target_ipc_perm *target_ip;
2434 struct target_semid_ds *target_sd;
2435
bellard579a97f2007-11-11 14:26:47 +00002436 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2437 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002438 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002439 host_ip->__key = tswap32(target_ip->__key);
2440 host_ip->uid = tswap32(target_ip->uid);
2441 host_ip->gid = tswap32(target_ip->gid);
2442 host_ip->cuid = tswap32(target_ip->cuid);
2443 host_ip->cgid = tswap32(target_ip->cgid);
2444#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2445 host_ip->mode = tswap32(target_ip->mode);
2446#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002447 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002448#endif
2449#if defined(TARGET_PPC)
2450 host_ip->__seq = tswap32(target_ip->__seq);
2451#else
2452 host_ip->__seq = tswap16(target_ip->__seq);
2453#endif
ths3eb6b042007-06-03 14:26:27 +00002454 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002455 return 0;
ths3eb6b042007-06-03 14:26:27 +00002456}
2457
bellard579a97f2007-11-11 14:26:47 +00002458static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2459 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002460{
2461 struct target_ipc_perm *target_ip;
2462 struct target_semid_ds *target_sd;
2463
bellard579a97f2007-11-11 14:26:47 +00002464 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2465 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002466 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002467 target_ip->__key = tswap32(host_ip->__key);
2468 target_ip->uid = tswap32(host_ip->uid);
2469 target_ip->gid = tswap32(host_ip->gid);
2470 target_ip->cuid = tswap32(host_ip->cuid);
2471 target_ip->cgid = tswap32(host_ip->cgid);
2472#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2473 target_ip->mode = tswap32(host_ip->mode);
2474#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002475 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002476#endif
2477#if defined(TARGET_PPC)
2478 target_ip->__seq = tswap32(host_ip->__seq);
2479#else
2480 target_ip->__seq = tswap16(host_ip->__seq);
2481#endif
ths3eb6b042007-06-03 14:26:27 +00002482 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002483 return 0;
ths3eb6b042007-06-03 14:26:27 +00002484}
2485
bellard579a97f2007-11-11 14:26:47 +00002486static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2487 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002488{
2489 struct target_semid_ds *target_sd;
2490
bellard579a97f2007-11-11 14:26:47 +00002491 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2492 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002493 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2494 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002495 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2496 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2497 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002498 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002499 return 0;
ths3eb6b042007-06-03 14:26:27 +00002500}
2501
bellard579a97f2007-11-11 14:26:47 +00002502static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2503 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002504{
2505 struct target_semid_ds *target_sd;
2506
bellard579a97f2007-11-11 14:26:47 +00002507 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2508 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002509 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002510 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002511 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2512 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2513 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002514 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002515 return 0;
ths3eb6b042007-06-03 14:26:27 +00002516}
2517
aurel32e5289082009-04-18 16:16:12 +00002518struct target_seminfo {
2519 int semmap;
2520 int semmni;
2521 int semmns;
2522 int semmnu;
2523 int semmsl;
2524 int semopm;
2525 int semume;
2526 int semusz;
2527 int semvmx;
2528 int semaem;
2529};
2530
2531static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2532 struct seminfo *host_seminfo)
2533{
2534 struct target_seminfo *target_seminfo;
2535 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2536 return -TARGET_EFAULT;
2537 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2538 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2539 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2540 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2541 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2542 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2543 __put_user(host_seminfo->semume, &target_seminfo->semume);
2544 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2545 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2546 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2547 unlock_user_struct(target_seminfo, target_addr, 1);
2548 return 0;
2549}
2550
thsfa294812007-02-02 22:05:00 +00002551union semun {
2552 int val;
ths3eb6b042007-06-03 14:26:27 +00002553 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002554 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002555 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002556};
2557
ths3eb6b042007-06-03 14:26:27 +00002558union target_semun {
2559 int val;
aurel32e5289082009-04-18 16:16:12 +00002560 abi_ulong buf;
2561 abi_ulong array;
2562 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002563};
2564
aurel32e5289082009-04-18 16:16:12 +00002565static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2566 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002567{
aurel32e5289082009-04-18 16:16:12 +00002568 int nsems;
2569 unsigned short *array;
2570 union semun semun;
2571 struct semid_ds semid_ds;
2572 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002573
aurel32e5289082009-04-18 16:16:12 +00002574 semun.buf = &semid_ds;
2575
2576 ret = semctl(semid, 0, IPC_STAT, semun);
2577 if (ret == -1)
2578 return get_errno(ret);
2579
2580 nsems = semid_ds.sem_nsems;
2581
2582 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002583 if (!*host_array) {
2584 return -TARGET_ENOMEM;
2585 }
aurel32e5289082009-04-18 16:16:12 +00002586 array = lock_user(VERIFY_READ, target_addr,
2587 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002588 if (!array) {
2589 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002590 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002591 }
aurel32e5289082009-04-18 16:16:12 +00002592
2593 for(i=0; i<nsems; i++) {
2594 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002595 }
aurel32e5289082009-04-18 16:16:12 +00002596 unlock_user(array, target_addr, 0);
2597
bellard579a97f2007-11-11 14:26:47 +00002598 return 0;
ths3eb6b042007-06-03 14:26:27 +00002599}
2600
aurel32e5289082009-04-18 16:16:12 +00002601static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2602 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002603{
aurel32e5289082009-04-18 16:16:12 +00002604 int nsems;
2605 unsigned short *array;
2606 union semun semun;
2607 struct semid_ds semid_ds;
2608 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002609
aurel32e5289082009-04-18 16:16:12 +00002610 semun.buf = &semid_ds;
2611
2612 ret = semctl(semid, 0, IPC_STAT, semun);
2613 if (ret == -1)
2614 return get_errno(ret);
2615
2616 nsems = semid_ds.sem_nsems;
2617
2618 array = lock_user(VERIFY_WRITE, target_addr,
2619 nsems*sizeof(unsigned short), 0);
2620 if (!array)
2621 return -TARGET_EFAULT;
2622
2623 for(i=0; i<nsems; i++) {
2624 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002625 }
aurel32e5289082009-04-18 16:16:12 +00002626 free(*host_array);
2627 unlock_user(array, target_addr, 1);
2628
bellard579a97f2007-11-11 14:26:47 +00002629 return 0;
ths3eb6b042007-06-03 14:26:27 +00002630}
2631
aurel32e5289082009-04-18 16:16:12 +00002632static inline abi_long do_semctl(int semid, int semnum, int cmd,
2633 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002634{
2635 union semun arg;
2636 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302637 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002638 struct seminfo seminfo;
2639 abi_long ret = -TARGET_EINVAL;
2640 abi_long err;
2641 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002642
2643 switch( cmd ) {
2644 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002645 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002646 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002647 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002648 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002649 break;
2650 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002651 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002652 err = target_to_host_semarray(semid, &array, target_su.array);
2653 if (err)
2654 return err;
2655 arg.array = array;
2656 ret = get_errno(semctl(semid, semnum, cmd, arg));
2657 err = host_to_target_semarray(semid, target_su.array, &array);
2658 if (err)
2659 return err;
ths3eb6b042007-06-03 14:26:27 +00002660 break;
2661 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002662 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002663 case SEM_STAT:
2664 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2665 if (err)
2666 return err;
2667 arg.buf = &dsarg;
2668 ret = get_errno(semctl(semid, semnum, cmd, arg));
2669 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2670 if (err)
2671 return err;
ths3eb6b042007-06-03 14:26:27 +00002672 break;
aurel32e5289082009-04-18 16:16:12 +00002673 case IPC_INFO:
2674 case SEM_INFO:
2675 arg.__buf = &seminfo;
2676 ret = get_errno(semctl(semid, semnum, cmd, arg));
2677 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2678 if (err)
2679 return err;
2680 break;
2681 case IPC_RMID:
2682 case GETPID:
2683 case GETNCNT:
2684 case GETZCNT:
2685 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2686 break;
ths3eb6b042007-06-03 14:26:27 +00002687 }
2688
2689 return ret;
2690}
2691
aurel32e5289082009-04-18 16:16:12 +00002692struct target_sembuf {
2693 unsigned short sem_num;
2694 short sem_op;
2695 short sem_flg;
2696};
2697
2698static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2699 abi_ulong target_addr,
2700 unsigned nsops)
2701{
2702 struct target_sembuf *target_sembuf;
2703 int i;
2704
2705 target_sembuf = lock_user(VERIFY_READ, target_addr,
2706 nsops*sizeof(struct target_sembuf), 1);
2707 if (!target_sembuf)
2708 return -TARGET_EFAULT;
2709
2710 for(i=0; i<nsops; i++) {
2711 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2712 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2713 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2714 }
2715
2716 unlock_user(target_sembuf, target_addr, 0);
2717
2718 return 0;
2719}
2720
2721static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2722{
2723 struct sembuf sops[nsops];
2724
2725 if (target_to_host_sembuf(sops, ptr, nsops))
2726 return -TARGET_EFAULT;
2727
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002728 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002729}
2730
ths1bc012f2007-06-03 14:27:49 +00002731struct target_msqid_ds
2732{
aurel321c54ff92008-10-13 21:08:44 +00002733 struct target_ipc_perm msg_perm;
2734 abi_ulong msg_stime;
2735#if TARGET_ABI_BITS == 32
2736 abi_ulong __unused1;
2737#endif
2738 abi_ulong msg_rtime;
2739#if TARGET_ABI_BITS == 32
2740 abi_ulong __unused2;
2741#endif
2742 abi_ulong msg_ctime;
2743#if TARGET_ABI_BITS == 32
2744 abi_ulong __unused3;
2745#endif
2746 abi_ulong __msg_cbytes;
2747 abi_ulong msg_qnum;
2748 abi_ulong msg_qbytes;
2749 abi_ulong msg_lspid;
2750 abi_ulong msg_lrpid;
2751 abi_ulong __unused4;
2752 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002753};
2754
bellard579a97f2007-11-11 14:26:47 +00002755static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2756 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002757{
2758 struct target_msqid_ds *target_md;
2759
bellard579a97f2007-11-11 14:26:47 +00002760 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2761 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002762 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2763 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002764 host_md->msg_stime = tswapal(target_md->msg_stime);
2765 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2766 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2767 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2768 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2769 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2770 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2771 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002772 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002773 return 0;
ths1bc012f2007-06-03 14:27:49 +00002774}
2775
bellard579a97f2007-11-11 14:26:47 +00002776static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2777 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002778{
2779 struct target_msqid_ds *target_md;
2780
bellard579a97f2007-11-11 14:26:47 +00002781 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2782 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002783 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2784 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002785 target_md->msg_stime = tswapal(host_md->msg_stime);
2786 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2787 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2788 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2789 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2790 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2791 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2792 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002793 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002794 return 0;
ths1bc012f2007-06-03 14:27:49 +00002795}
2796
aurel321c54ff92008-10-13 21:08:44 +00002797struct target_msginfo {
2798 int msgpool;
2799 int msgmap;
2800 int msgmax;
2801 int msgmnb;
2802 int msgmni;
2803 int msgssz;
2804 int msgtql;
2805 unsigned short int msgseg;
2806};
2807
2808static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2809 struct msginfo *host_msginfo)
2810{
2811 struct target_msginfo *target_msginfo;
2812 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2813 return -TARGET_EFAULT;
2814 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2815 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2816 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2817 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2818 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2819 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2820 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2821 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2822 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002823 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002824}
2825
2826static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002827{
2828 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002829 struct msginfo msginfo;
2830 abi_long ret = -TARGET_EINVAL;
2831
2832 cmd &= 0xff;
2833
2834 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002835 case IPC_STAT:
2836 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002837 case MSG_STAT:
2838 if (target_to_host_msqid_ds(&dsarg,ptr))
2839 return -TARGET_EFAULT;
2840 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2841 if (host_to_target_msqid_ds(ptr,&dsarg))
2842 return -TARGET_EFAULT;
2843 break;
2844 case IPC_RMID:
2845 ret = get_errno(msgctl(msgid, cmd, NULL));
2846 break;
2847 case IPC_INFO:
2848 case MSG_INFO:
2849 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2850 if (host_to_target_msginfo(ptr, &msginfo))
2851 return -TARGET_EFAULT;
2852 break;
ths1bc012f2007-06-03 14:27:49 +00002853 }
aurel321c54ff92008-10-13 21:08:44 +00002854
ths1bc012f2007-06-03 14:27:49 +00002855 return ret;
2856}
2857
2858struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002859 abi_long mtype;
2860 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002861};
2862
blueswir1992f48a2007-10-14 16:27:31 +00002863static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2864 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002865{
2866 struct target_msgbuf *target_mb;
2867 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002868 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002869
bellard579a97f2007-11-11 14:26:47 +00002870 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2871 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002872 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002873 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002874 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002875 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2876 free(host_mb);
2877 unlock_user_struct(target_mb, msgp, 0);
2878
2879 return ret;
2880}
2881
blueswir1992f48a2007-10-14 16:27:31 +00002882static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002883 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002884 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002885{
2886 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002887 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002888 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002889 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002890
bellard579a97f2007-11-11 14:26:47 +00002891 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2892 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002893
Jim Meyering0d07fe42012-08-22 13:55:53 +02002894 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002895 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002896
bellard579a97f2007-11-11 14:26:47 +00002897 if (ret > 0) {
2898 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2899 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2900 if (!target_mtext) {
2901 ret = -TARGET_EFAULT;
2902 goto end;
2903 }
aurel321c54ff92008-10-13 21:08:44 +00002904 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002905 unlock_user(target_mtext, target_mtext_addr, ret);
2906 }
aurel321c54ff92008-10-13 21:08:44 +00002907
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002908 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002909
bellard579a97f2007-11-11 14:26:47 +00002910end:
2911 if (target_mb)
2912 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002913 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002914 return ret;
2915}
2916
Riku Voipio88a8c982009-04-03 10:42:00 +03002917static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2918 abi_ulong target_addr)
2919{
2920 struct target_shmid_ds *target_sd;
2921
2922 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2923 return -TARGET_EFAULT;
2924 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2925 return -TARGET_EFAULT;
2926 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2927 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2928 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2929 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2930 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2931 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2932 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2933 unlock_user_struct(target_sd, target_addr, 0);
2934 return 0;
2935}
2936
2937static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2938 struct shmid_ds *host_sd)
2939{
2940 struct target_shmid_ds *target_sd;
2941
2942 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2943 return -TARGET_EFAULT;
2944 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2945 return -TARGET_EFAULT;
2946 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2947 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2948 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2949 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2950 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2951 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2952 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2953 unlock_user_struct(target_sd, target_addr, 1);
2954 return 0;
2955}
2956
2957struct target_shminfo {
2958 abi_ulong shmmax;
2959 abi_ulong shmmin;
2960 abi_ulong shmmni;
2961 abi_ulong shmseg;
2962 abi_ulong shmall;
2963};
2964
2965static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2966 struct shminfo *host_shminfo)
2967{
2968 struct target_shminfo *target_shminfo;
2969 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2970 return -TARGET_EFAULT;
2971 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2972 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2973 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2974 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2975 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2976 unlock_user_struct(target_shminfo, target_addr, 1);
2977 return 0;
2978}
2979
2980struct target_shm_info {
2981 int used_ids;
2982 abi_ulong shm_tot;
2983 abi_ulong shm_rss;
2984 abi_ulong shm_swp;
2985 abi_ulong swap_attempts;
2986 abi_ulong swap_successes;
2987};
2988
2989static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2990 struct shm_info *host_shm_info)
2991{
2992 struct target_shm_info *target_shm_info;
2993 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2994 return -TARGET_EFAULT;
2995 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2996 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2997 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2998 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2999 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
3000 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3001 unlock_user_struct(target_shm_info, target_addr, 1);
3002 return 0;
3003}
3004
3005static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3006{
3007 struct shmid_ds dsarg;
3008 struct shminfo shminfo;
3009 struct shm_info shm_info;
3010 abi_long ret = -TARGET_EINVAL;
3011
3012 cmd &= 0xff;
3013
3014 switch(cmd) {
3015 case IPC_STAT:
3016 case IPC_SET:
3017 case SHM_STAT:
3018 if (target_to_host_shmid_ds(&dsarg, buf))
3019 return -TARGET_EFAULT;
3020 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3021 if (host_to_target_shmid_ds(buf, &dsarg))
3022 return -TARGET_EFAULT;
3023 break;
3024 case IPC_INFO:
3025 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3026 if (host_to_target_shminfo(buf, &shminfo))
3027 return -TARGET_EFAULT;
3028 break;
3029 case SHM_INFO:
3030 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3031 if (host_to_target_shm_info(buf, &shm_info))
3032 return -TARGET_EFAULT;
3033 break;
3034 case IPC_RMID:
3035 case SHM_LOCK:
3036 case SHM_UNLOCK:
3037 ret = get_errno(shmctl(shmid, cmd, NULL));
3038 break;
3039 }
3040
3041 return ret;
3042}
3043
3044static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3045{
3046 abi_long raddr;
3047 void *host_raddr;
3048 struct shmid_ds shm_info;
3049 int i,ret;
3050
3051 /* find out the length of the shared memory segment */
3052 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3053 if (is_error(ret)) {
3054 /* can't get length, bail out */
3055 return ret;
3056 }
3057
3058 mmap_lock();
3059
3060 if (shmaddr)
3061 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3062 else {
3063 abi_ulong mmap_start;
3064
3065 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3066
3067 if (mmap_start == -1) {
3068 errno = ENOMEM;
3069 host_raddr = (void *)-1;
3070 } else
3071 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3072 }
3073
3074 if (host_raddr == (void *)-1) {
3075 mmap_unlock();
3076 return get_errno((long)host_raddr);
3077 }
3078 raddr=h2g((unsigned long)host_raddr);
3079
3080 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3081 PAGE_VALID | PAGE_READ |
3082 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3083
3084 for (i = 0; i < N_SHM_REGIONS; i++) {
3085 if (shm_regions[i].start == 0) {
3086 shm_regions[i].start = raddr;
3087 shm_regions[i].size = shm_info.shm_segsz;
3088 break;
3089 }
3090 }
3091
3092 mmap_unlock();
3093 return raddr;
3094
3095}
3096
3097static inline abi_long do_shmdt(abi_ulong shmaddr)
3098{
3099 int i;
3100
3101 for (i = 0; i < N_SHM_REGIONS; ++i) {
3102 if (shm_regions[i].start == shmaddr) {
3103 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003104 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003105 break;
3106 }
3107 }
3108
3109 return get_errno(shmdt(g2h(shmaddr)));
3110}
3111
aurel321c54ff92008-10-13 21:08:44 +00003112#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003113/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003114/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003115static abi_long do_ipc(unsigned int call, int first,
3116 int second, int third,
3117 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003118{
3119 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003120 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003121
3122 version = call >> 16;
3123 call &= 0xffff;
3124
3125 switch (call) {
thsfa294812007-02-02 22:05:00 +00003126 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003127 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003128 break;
3129
3130 case IPCOP_semget:
3131 ret = get_errno(semget(first, second, third));
3132 break;
3133
3134 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003135 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003136 break;
thsd96372e2007-02-02 22:05:44 +00003137
aurel321c54ff92008-10-13 21:08:44 +00003138 case IPCOP_msgget:
3139 ret = get_errno(msgget(first, second));
3140 break;
thsd96372e2007-02-02 22:05:44 +00003141
aurel321c54ff92008-10-13 21:08:44 +00003142 case IPCOP_msgsnd:
3143 ret = do_msgsnd(first, ptr, second, third);
3144 break;
thsd96372e2007-02-02 22:05:44 +00003145
aurel321c54ff92008-10-13 21:08:44 +00003146 case IPCOP_msgctl:
3147 ret = do_msgctl(first, second, ptr);
3148 break;
thsd96372e2007-02-02 22:05:44 +00003149
aurel321c54ff92008-10-13 21:08:44 +00003150 case IPCOP_msgrcv:
3151 switch (version) {
3152 case 0:
3153 {
3154 struct target_ipc_kludge {
3155 abi_long msgp;
3156 abi_long msgtyp;
3157 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003158
aurel321c54ff92008-10-13 21:08:44 +00003159 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3160 ret = -TARGET_EFAULT;
3161 break;
ths1bc012f2007-06-03 14:27:49 +00003162 }
aurel321c54ff92008-10-13 21:08:44 +00003163
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003164 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003165
3166 unlock_user_struct(tmp, ptr, 0);
3167 break;
3168 }
3169 default:
3170 ret = do_msgrcv(first, ptr, second, fifth, third);
3171 }
3172 break;
thsd96372e2007-02-02 22:05:44 +00003173
bellard8853f862004-02-22 14:57:26 +00003174 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003175 switch (version) {
3176 default:
bellard5a4a8982007-11-11 17:39:18 +00003177 {
3178 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003179 raddr = do_shmat(first, ptr, second);
3180 if (is_error(raddr))
3181 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003182 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003183 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003184 break;
3185 }
3186 case 1:
3187 ret = -TARGET_EINVAL;
3188 break;
bellard5a4a8982007-11-11 17:39:18 +00003189 }
bellard8853f862004-02-22 14:57:26 +00003190 break;
3191 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003192 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003193 break;
3194
3195 case IPCOP_shmget:
3196 /* IPC_* flag values are the same on all linux platforms */
3197 ret = get_errno(shmget(first, second, third));
3198 break;
3199
3200 /* IPC_* and SHM_* command values are the same on all linux platforms */
3201 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003202 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003203 break;
3204 default:
j_mayer32407102007-09-26 23:01:49 +00003205 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003206 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003207 break;
3208 }
3209 return ret;
3210}
j_mayer32407102007-09-26 23:01:49 +00003211#endif
bellard8853f862004-02-22 14:57:26 +00003212
bellard31e31b82003-02-18 22:55:36 +00003213/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003214
Blue Swirl001faf32009-05-13 17:53:17 +00003215#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003216#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3217enum {
3218#include "syscall_types.h"
3219};
3220#undef STRUCT
3221#undef STRUCT_SPECIAL
3222
Blue Swirl001faf32009-05-13 17:53:17 +00003223#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003224#define STRUCT_SPECIAL(name)
3225#include "syscall_types.h"
3226#undef STRUCT
3227#undef STRUCT_SPECIAL
3228
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003229typedef struct IOCTLEntry IOCTLEntry;
3230
3231typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3232 int fd, abi_long cmd, abi_long arg);
3233
3234struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003235 unsigned int target_cmd;
3236 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003237 const char *name;
3238 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003239 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003240 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003241};
bellard31e31b82003-02-18 22:55:36 +00003242
3243#define IOC_R 0x0001
3244#define IOC_W 0x0002
3245#define IOC_RW (IOC_R | IOC_W)
3246
3247#define MAX_STRUCT_SIZE 4096
3248
Peter Maydelldace20d2011-01-10 13:11:24 +00003249#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003250/* So fiemap access checks don't overflow on 32 bit systems.
3251 * This is very slightly smaller than the limit imposed by
3252 * the underlying kernel.
3253 */
3254#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3255 / sizeof(struct fiemap_extent))
3256
3257static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3258 int fd, abi_long cmd, abi_long arg)
3259{
3260 /* The parameter for this ioctl is a struct fiemap followed
3261 * by an array of struct fiemap_extent whose size is set
3262 * in fiemap->fm_extent_count. The array is filled in by the
3263 * ioctl.
3264 */
3265 int target_size_in, target_size_out;
3266 struct fiemap *fm;
3267 const argtype *arg_type = ie->arg_type;
3268 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3269 void *argptr, *p;
3270 abi_long ret;
3271 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3272 uint32_t outbufsz;
3273 int free_fm = 0;
3274
3275 assert(arg_type[0] == TYPE_PTR);
3276 assert(ie->access == IOC_RW);
3277 arg_type++;
3278 target_size_in = thunk_type_size(arg_type, 0);
3279 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3280 if (!argptr) {
3281 return -TARGET_EFAULT;
3282 }
3283 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3284 unlock_user(argptr, arg, 0);
3285 fm = (struct fiemap *)buf_temp;
3286 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3287 return -TARGET_EINVAL;
3288 }
3289
3290 outbufsz = sizeof (*fm) +
3291 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3292
3293 if (outbufsz > MAX_STRUCT_SIZE) {
3294 /* We can't fit all the extents into the fixed size buffer.
3295 * Allocate one that is large enough and use it instead.
3296 */
3297 fm = malloc(outbufsz);
3298 if (!fm) {
3299 return -TARGET_ENOMEM;
3300 }
3301 memcpy(fm, buf_temp, sizeof(struct fiemap));
3302 free_fm = 1;
3303 }
3304 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3305 if (!is_error(ret)) {
3306 target_size_out = target_size_in;
3307 /* An extent_count of 0 means we were only counting the extents
3308 * so there are no structs to copy
3309 */
3310 if (fm->fm_extent_count != 0) {
3311 target_size_out += fm->fm_mapped_extents * extent_size;
3312 }
3313 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3314 if (!argptr) {
3315 ret = -TARGET_EFAULT;
3316 } else {
3317 /* Convert the struct fiemap */
3318 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3319 if (fm->fm_extent_count != 0) {
3320 p = argptr + target_size_in;
3321 /* ...and then all the struct fiemap_extents */
3322 for (i = 0; i < fm->fm_mapped_extents; i++) {
3323 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3324 THUNK_TARGET);
3325 p += extent_size;
3326 }
3327 }
3328 unlock_user(argptr, arg, target_size_out);
3329 }
3330 }
3331 if (free_fm) {
3332 free(fm);
3333 }
3334 return ret;
3335}
Peter Maydelldace20d2011-01-10 13:11:24 +00003336#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003337
Laurent Vivier059c2f22011-03-30 00:12:12 +02003338static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3339 int fd, abi_long cmd, abi_long arg)
3340{
3341 const argtype *arg_type = ie->arg_type;
3342 int target_size;
3343 void *argptr;
3344 int ret;
3345 struct ifconf *host_ifconf;
3346 uint32_t outbufsz;
3347 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3348 int target_ifreq_size;
3349 int nb_ifreq;
3350 int free_buf = 0;
3351 int i;
3352 int target_ifc_len;
3353 abi_long target_ifc_buf;
3354 int host_ifc_len;
3355 char *host_ifc_buf;
3356
3357 assert(arg_type[0] == TYPE_PTR);
3358 assert(ie->access == IOC_RW);
3359
3360 arg_type++;
3361 target_size = thunk_type_size(arg_type, 0);
3362
3363 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3364 if (!argptr)
3365 return -TARGET_EFAULT;
3366 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3367 unlock_user(argptr, arg, 0);
3368
3369 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3370 target_ifc_len = host_ifconf->ifc_len;
3371 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3372
3373 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3374 nb_ifreq = target_ifc_len / target_ifreq_size;
3375 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3376
3377 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3378 if (outbufsz > MAX_STRUCT_SIZE) {
3379 /* We can't fit all the extents into the fixed size buffer.
3380 * Allocate one that is large enough and use it instead.
3381 */
3382 host_ifconf = malloc(outbufsz);
3383 if (!host_ifconf) {
3384 return -TARGET_ENOMEM;
3385 }
3386 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3387 free_buf = 1;
3388 }
3389 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3390
3391 host_ifconf->ifc_len = host_ifc_len;
3392 host_ifconf->ifc_buf = host_ifc_buf;
3393
3394 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3395 if (!is_error(ret)) {
3396 /* convert host ifc_len to target ifc_len */
3397
3398 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3399 target_ifc_len = nb_ifreq * target_ifreq_size;
3400 host_ifconf->ifc_len = target_ifc_len;
3401
3402 /* restore target ifc_buf */
3403
3404 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3405
3406 /* copy struct ifconf to target user */
3407
3408 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3409 if (!argptr)
3410 return -TARGET_EFAULT;
3411 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3412 unlock_user(argptr, arg, target_size);
3413
3414 /* copy ifreq[] to target user */
3415
3416 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3417 for (i = 0; i < nb_ifreq ; i++) {
3418 thunk_convert(argptr + i * target_ifreq_size,
3419 host_ifc_buf + i * sizeof(struct ifreq),
3420 ifreq_arg_type, THUNK_TARGET);
3421 }
3422 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3423 }
3424
3425 if (free_buf) {
3426 free(host_ifconf);
3427 }
3428
3429 return ret;
3430}
3431
Alexander Graf56e904e2012-01-31 18:42:06 +01003432static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3433 abi_long cmd, abi_long arg)
3434{
3435 void *argptr;
3436 struct dm_ioctl *host_dm;
3437 abi_long guest_data;
3438 uint32_t guest_data_size;
3439 int target_size;
3440 const argtype *arg_type = ie->arg_type;
3441 abi_long ret;
3442 void *big_buf = NULL;
3443 char *host_data;
3444
3445 arg_type++;
3446 target_size = thunk_type_size(arg_type, 0);
3447 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3448 if (!argptr) {
3449 ret = -TARGET_EFAULT;
3450 goto out;
3451 }
3452 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3453 unlock_user(argptr, arg, 0);
3454
3455 /* buf_temp is too small, so fetch things into a bigger buffer */
3456 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3457 memcpy(big_buf, buf_temp, target_size);
3458 buf_temp = big_buf;
3459 host_dm = big_buf;
3460
3461 guest_data = arg + host_dm->data_start;
3462 if ((guest_data - arg) < 0) {
3463 ret = -EINVAL;
3464 goto out;
3465 }
3466 guest_data_size = host_dm->data_size - host_dm->data_start;
3467 host_data = (char*)host_dm + host_dm->data_start;
3468
3469 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3470 switch (ie->host_cmd) {
3471 case DM_REMOVE_ALL:
3472 case DM_LIST_DEVICES:
3473 case DM_DEV_CREATE:
3474 case DM_DEV_REMOVE:
3475 case DM_DEV_SUSPEND:
3476 case DM_DEV_STATUS:
3477 case DM_DEV_WAIT:
3478 case DM_TABLE_STATUS:
3479 case DM_TABLE_CLEAR:
3480 case DM_TABLE_DEPS:
3481 case DM_LIST_VERSIONS:
3482 /* no input data */
3483 break;
3484 case DM_DEV_RENAME:
3485 case DM_DEV_SET_GEOMETRY:
3486 /* data contains only strings */
3487 memcpy(host_data, argptr, guest_data_size);
3488 break;
3489 case DM_TARGET_MSG:
3490 memcpy(host_data, argptr, guest_data_size);
3491 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3492 break;
3493 case DM_TABLE_LOAD:
3494 {
3495 void *gspec = argptr;
3496 void *cur_data = host_data;
3497 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3498 int spec_size = thunk_type_size(arg_type, 0);
3499 int i;
3500
3501 for (i = 0; i < host_dm->target_count; i++) {
3502 struct dm_target_spec *spec = cur_data;
3503 uint32_t next;
3504 int slen;
3505
3506 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3507 slen = strlen((char*)gspec + spec_size) + 1;
3508 next = spec->next;
3509 spec->next = sizeof(*spec) + slen;
3510 strcpy((char*)&spec[1], gspec + spec_size);
3511 gspec += next;
3512 cur_data += spec->next;
3513 }
3514 break;
3515 }
3516 default:
3517 ret = -TARGET_EINVAL;
3518 goto out;
3519 }
3520 unlock_user(argptr, guest_data, 0);
3521
3522 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3523 if (!is_error(ret)) {
3524 guest_data = arg + host_dm->data_start;
3525 guest_data_size = host_dm->data_size - host_dm->data_start;
3526 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3527 switch (ie->host_cmd) {
3528 case DM_REMOVE_ALL:
3529 case DM_DEV_CREATE:
3530 case DM_DEV_REMOVE:
3531 case DM_DEV_RENAME:
3532 case DM_DEV_SUSPEND:
3533 case DM_DEV_STATUS:
3534 case DM_TABLE_LOAD:
3535 case DM_TABLE_CLEAR:
3536 case DM_TARGET_MSG:
3537 case DM_DEV_SET_GEOMETRY:
3538 /* no return data */
3539 break;
3540 case DM_LIST_DEVICES:
3541 {
3542 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3543 uint32_t remaining_data = guest_data_size;
3544 void *cur_data = argptr;
3545 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3546 int nl_size = 12; /* can't use thunk_size due to alignment */
3547
3548 while (1) {
3549 uint32_t next = nl->next;
3550 if (next) {
3551 nl->next = nl_size + (strlen(nl->name) + 1);
3552 }
3553 if (remaining_data < nl->next) {
3554 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3555 break;
3556 }
3557 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3558 strcpy(cur_data + nl_size, nl->name);
3559 cur_data += nl->next;
3560 remaining_data -= nl->next;
3561 if (!next) {
3562 break;
3563 }
3564 nl = (void*)nl + next;
3565 }
3566 break;
3567 }
3568 case DM_DEV_WAIT:
3569 case DM_TABLE_STATUS:
3570 {
3571 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3572 void *cur_data = argptr;
3573 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3574 int spec_size = thunk_type_size(arg_type, 0);
3575 int i;
3576
3577 for (i = 0; i < host_dm->target_count; i++) {
3578 uint32_t next = spec->next;
3579 int slen = strlen((char*)&spec[1]) + 1;
3580 spec->next = (cur_data - argptr) + spec_size + slen;
3581 if (guest_data_size < spec->next) {
3582 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3583 break;
3584 }
3585 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3586 strcpy(cur_data + spec_size, (char*)&spec[1]);
3587 cur_data = argptr + spec->next;
3588 spec = (void*)host_dm + host_dm->data_start + next;
3589 }
3590 break;
3591 }
3592 case DM_TABLE_DEPS:
3593 {
3594 void *hdata = (void*)host_dm + host_dm->data_start;
3595 int count = *(uint32_t*)hdata;
3596 uint64_t *hdev = hdata + 8;
3597 uint64_t *gdev = argptr + 8;
3598 int i;
3599
3600 *(uint32_t*)argptr = tswap32(count);
3601 for (i = 0; i < count; i++) {
3602 *gdev = tswap64(*hdev);
3603 gdev++;
3604 hdev++;
3605 }
3606 break;
3607 }
3608 case DM_LIST_VERSIONS:
3609 {
3610 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3611 uint32_t remaining_data = guest_data_size;
3612 void *cur_data = argptr;
3613 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3614 int vers_size = thunk_type_size(arg_type, 0);
3615
3616 while (1) {
3617 uint32_t next = vers->next;
3618 if (next) {
3619 vers->next = vers_size + (strlen(vers->name) + 1);
3620 }
3621 if (remaining_data < vers->next) {
3622 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3623 break;
3624 }
3625 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3626 strcpy(cur_data + vers_size, vers->name);
3627 cur_data += vers->next;
3628 remaining_data -= vers->next;
3629 if (!next) {
3630 break;
3631 }
3632 vers = (void*)vers + next;
3633 }
3634 break;
3635 }
3636 default:
3637 ret = -TARGET_EINVAL;
3638 goto out;
3639 }
3640 unlock_user(argptr, guest_data, guest_data_size);
3641
3642 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3643 if (!argptr) {
3644 ret = -TARGET_EFAULT;
3645 goto out;
3646 }
3647 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3648 unlock_user(argptr, arg, target_size);
3649 }
3650out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003651 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003652 return ret;
3653}
3654
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003655static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3656 int fd, abi_long cmd, abi_long arg)
3657{
3658 const argtype *arg_type = ie->arg_type;
3659 const StructEntry *se;
3660 const argtype *field_types;
3661 const int *dst_offsets, *src_offsets;
3662 int target_size;
3663 void *argptr;
3664 abi_ulong *target_rt_dev_ptr;
3665 unsigned long *host_rt_dev_ptr;
3666 abi_long ret;
3667 int i;
3668
3669 assert(ie->access == IOC_W);
3670 assert(*arg_type == TYPE_PTR);
3671 arg_type++;
3672 assert(*arg_type == TYPE_STRUCT);
3673 target_size = thunk_type_size(arg_type, 0);
3674 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3675 if (!argptr) {
3676 return -TARGET_EFAULT;
3677 }
3678 arg_type++;
3679 assert(*arg_type == (int)STRUCT_rtentry);
3680 se = struct_entries + *arg_type++;
3681 assert(se->convert[0] == NULL);
3682 /* convert struct here to be able to catch rt_dev string */
3683 field_types = se->field_types;
3684 dst_offsets = se->field_offsets[THUNK_HOST];
3685 src_offsets = se->field_offsets[THUNK_TARGET];
3686 for (i = 0; i < se->nb_fields; i++) {
3687 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3688 assert(*field_types == TYPE_PTRVOID);
3689 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3690 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3691 if (*target_rt_dev_ptr != 0) {
3692 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3693 tswapal(*target_rt_dev_ptr));
3694 if (!*host_rt_dev_ptr) {
3695 unlock_user(argptr, arg, 0);
3696 return -TARGET_EFAULT;
3697 }
3698 } else {
3699 *host_rt_dev_ptr = 0;
3700 }
3701 field_types++;
3702 continue;
3703 }
3704 field_types = thunk_convert(buf_temp + dst_offsets[i],
3705 argptr + src_offsets[i],
3706 field_types, THUNK_HOST);
3707 }
3708 unlock_user(argptr, arg, 0);
3709
3710 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3711 if (*host_rt_dev_ptr != 0) {
3712 unlock_user((void *)*host_rt_dev_ptr,
3713 *target_rt_dev_ptr, 0);
3714 }
3715 return ret;
3716}
3717
Paul Burtonca56f5b2014-06-22 11:25:47 +01003718static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
3719 int fd, abi_long cmd, abi_long arg)
3720{
3721 int sig = target_to_host_signal(arg);
3722 return get_errno(ioctl(fd, ie->host_cmd, sig));
3723}
3724
blueswir19f106a72008-10-05 10:52:52 +00003725static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003726#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003727 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3728#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3729 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003730#include "ioctls.h"
3731 { 0, 0, },
3732};
3733
pbrook53a59602006-03-25 19:31:22 +00003734/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003735/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003736static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003737{
3738 const IOCTLEntry *ie;
3739 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003740 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003741 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003742 int target_size;
3743 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003744
3745 ie = ioctl_entries;
3746 for(;;) {
3747 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003748 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003749 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003750 }
3751 if (ie->target_cmd == cmd)
3752 break;
3753 ie++;
3754 }
3755 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003756#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003757 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003758#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003759 if (ie->do_ioctl) {
3760 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3761 }
3762
bellard31e31b82003-02-18 22:55:36 +00003763 switch(arg_type[0]) {
3764 case TYPE_NULL:
3765 /* no argument */
3766 ret = get_errno(ioctl(fd, ie->host_cmd));
3767 break;
3768 case TYPE_PTRVOID:
3769 case TYPE_INT:
3770 /* int argment */
3771 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3772 break;
3773 case TYPE_PTR:
3774 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003775 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003776 switch(ie->access) {
3777 case IOC_R:
3778 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3779 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003780 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3781 if (!argptr)
3782 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003783 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3784 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003785 }
3786 break;
3787 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003788 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3789 if (!argptr)
3790 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003791 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3792 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003793 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3794 break;
3795 default:
3796 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003797 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3798 if (!argptr)
3799 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003800 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3801 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003802 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3803 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003804 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3805 if (!argptr)
3806 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003807 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3808 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003809 }
3810 break;
3811 }
3812 break;
3813 default:
j_mayer32407102007-09-26 23:01:49 +00003814 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3815 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003816 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003817 break;
3818 }
3819 return ret;
3820}
3821
blueswir1b39bc502008-10-05 10:51:10 +00003822static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003823 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3824 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3825 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3826 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3827 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3828 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3829 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3830 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3831 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3832 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3833 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3834 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3835 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3836 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3837 { 0, 0, 0, 0 }
3838};
3839
blueswir1b39bc502008-10-05 10:51:10 +00003840static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003841 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3842 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3843 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3844 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3845 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3846 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3847 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3848 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3849 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3850 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3851 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3852 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3853 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3854 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3855 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3856 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3857 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3858 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3859 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3860 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3861 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3862 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3863 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3864 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3865 { 0, 0, 0, 0 }
3866};
3867
blueswir1b39bc502008-10-05 10:51:10 +00003868static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003869 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3870 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3871 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3872 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3873 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3874 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3875 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3876 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3877 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3878 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3879 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3880 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3881 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3882 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3883 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3884 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3885 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3886 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3887 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3888 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3889 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3890 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3891 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3892 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3893 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3894 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3895 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3896 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3897 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3898 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3899 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3900 { 0, 0, 0, 0 }
3901};
3902
blueswir1b39bc502008-10-05 10:51:10 +00003903static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003904 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3905 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3906 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3907 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3908 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3909 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3910 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3911 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3912 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3913 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3914 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3915 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3916 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3917 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3918 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3919 { 0, 0, 0, 0 }
3920};
3921
3922static void target_to_host_termios (void *dst, const void *src)
3923{
3924 struct host_termios *host = dst;
3925 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003926
ths5fafdf22007-09-16 21:08:06 +00003927 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003928 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003929 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003930 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003931 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003932 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003933 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003934 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3935 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003936
Arnaud Patard44607122009-04-21 17:39:08 +03003937 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003938 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3939 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003940 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003941 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003942 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003943 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003944 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003945 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003946 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003947 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3948 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003949 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3950 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3951 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3952 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3953 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003954 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003955}
ths3b46e622007-09-17 08:09:54 +00003956
bellard31e31b82003-02-18 22:55:36 +00003957static void host_to_target_termios (void *dst, const void *src)
3958{
3959 struct target_termios *target = dst;
3960 const struct host_termios *host = src;
3961
ths5fafdf22007-09-16 21:08:06 +00003962 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003963 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003964 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003965 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003966 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003967 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003968 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003969 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3970 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003971
Arnaud Patard44607122009-04-21 17:39:08 +03003972 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003973 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3974 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3975 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3976 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3977 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3978 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3979 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3980 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3981 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3982 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3983 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3984 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3985 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3986 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3987 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3988 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3989 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3990}
3991
blueswir18e853dc2008-10-05 10:49:32 +00003992static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003993 .convert = { host_to_target_termios, target_to_host_termios },
3994 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3995 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3996};
3997
bellard5286db72003-06-05 00:57:30 +00003998static bitmask_transtbl mmap_flags_tbl[] = {
3999 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
4000 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4001 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4002 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4003 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4004 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4005 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4006 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004007 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4008 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004009 { 0, 0, 0, 0 }
4010};
4011
bellard2ab83ea2003-06-15 19:56:46 +00004012#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004013
4014/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004015static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004016
bellard03acab62007-11-11 14:57:14 +00004017static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004018{
4019 int size;
pbrook53a59602006-03-25 19:31:22 +00004020 void *p;
bellard6dbad632003-03-16 18:05:05 +00004021
4022 if (!ldt_table)
4023 return 0;
4024 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4025 if (size > bytecount)
4026 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004027 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4028 if (!p)
bellard03acab62007-11-11 14:57:14 +00004029 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004030 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004031 memcpy(p, ldt_table, size);
4032 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004033 return size;
4034}
4035
4036/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004037static abi_long write_ldt(CPUX86State *env,
4038 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004039{
4040 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004041 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004042 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004043 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004044 uint32_t *lp, entry_1, entry_2;
4045
4046 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004047 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004048 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004049 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004050 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004051 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004052 ldt_info.limit = tswap32(target_ldt_info->limit);
4053 ldt_info.flags = tswap32(target_ldt_info->flags);
4054 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004055
bellard6dbad632003-03-16 18:05:05 +00004056 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004057 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004058 seg_32bit = ldt_info.flags & 1;
4059 contents = (ldt_info.flags >> 1) & 3;
4060 read_exec_only = (ldt_info.flags >> 3) & 1;
4061 limit_in_pages = (ldt_info.flags >> 4) & 1;
4062 seg_not_present = (ldt_info.flags >> 5) & 1;
4063 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004064#ifdef TARGET_ABI32
4065 lm = 0;
4066#else
4067 lm = (ldt_info.flags >> 7) & 1;
4068#endif
bellard6dbad632003-03-16 18:05:05 +00004069 if (contents == 3) {
4070 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004071 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004072 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004073 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004074 }
4075 /* allocate the LDT */
4076 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004077 env->ldt.base = target_mmap(0,
4078 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4079 PROT_READ|PROT_WRITE,
4080 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4081 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004082 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004083 memset(g2h(env->ldt.base), 0,
4084 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004085 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004086 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004087 }
4088
4089 /* NOTE: same code as Linux kernel */
4090 /* Allow LDTs to be cleared by the user. */
4091 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4092 if (oldmode ||
4093 (contents == 0 &&
4094 read_exec_only == 1 &&
4095 seg_32bit == 0 &&
4096 limit_in_pages == 0 &&
4097 seg_not_present == 1 &&
4098 useable == 0 )) {
4099 entry_1 = 0;
4100 entry_2 = 0;
4101 goto install;
4102 }
4103 }
ths3b46e622007-09-17 08:09:54 +00004104
bellard6dbad632003-03-16 18:05:05 +00004105 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4106 (ldt_info.limit & 0x0ffff);
4107 entry_2 = (ldt_info.base_addr & 0xff000000) |
4108 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4109 (ldt_info.limit & 0xf0000) |
4110 ((read_exec_only ^ 1) << 9) |
4111 (contents << 10) |
4112 ((seg_not_present ^ 1) << 15) |
4113 (seg_32bit << 22) |
4114 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004115 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004116 0x7000;
4117 if (!oldmode)
4118 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004119
bellard6dbad632003-03-16 18:05:05 +00004120 /* Install the new entry ... */
4121install:
4122 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4123 lp[0] = tswap32(entry_1);
4124 lp[1] = tswap32(entry_2);
4125 return 0;
4126}
4127
4128/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004129static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4130 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004131{
bellard03acab62007-11-11 14:57:14 +00004132 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004133
bellard6dbad632003-03-16 18:05:05 +00004134 switch (func) {
4135 case 0:
4136 ret = read_ldt(ptr, bytecount);
4137 break;
4138 case 1:
4139 ret = write_ldt(env, ptr, bytecount, 1);
4140 break;
4141 case 0x11:
4142 ret = write_ldt(env, ptr, bytecount, 0);
4143 break;
bellard03acab62007-11-11 14:57:14 +00004144 default:
4145 ret = -TARGET_ENOSYS;
4146 break;
bellard6dbad632003-03-16 18:05:05 +00004147 }
4148 return ret;
4149}
bellard1b6b0292003-03-22 17:31:38 +00004150
blueswir14583f582008-08-24 10:35:55 +00004151#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004152abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004153{
4154 uint64_t *gdt_table = g2h(env->gdt.base);
4155 struct target_modify_ldt_ldt_s ldt_info;
4156 struct target_modify_ldt_ldt_s *target_ldt_info;
4157 int seg_32bit, contents, read_exec_only, limit_in_pages;
4158 int seg_not_present, useable, lm;
4159 uint32_t *lp, entry_1, entry_2;
4160 int i;
4161
4162 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4163 if (!target_ldt_info)
4164 return -TARGET_EFAULT;
4165 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004166 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004167 ldt_info.limit = tswap32(target_ldt_info->limit);
4168 ldt_info.flags = tswap32(target_ldt_info->flags);
4169 if (ldt_info.entry_number == -1) {
4170 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4171 if (gdt_table[i] == 0) {
4172 ldt_info.entry_number = i;
4173 target_ldt_info->entry_number = tswap32(i);
4174 break;
4175 }
4176 }
4177 }
4178 unlock_user_struct(target_ldt_info, ptr, 1);
4179
4180 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4181 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4182 return -TARGET_EINVAL;
4183 seg_32bit = ldt_info.flags & 1;
4184 contents = (ldt_info.flags >> 1) & 3;
4185 read_exec_only = (ldt_info.flags >> 3) & 1;
4186 limit_in_pages = (ldt_info.flags >> 4) & 1;
4187 seg_not_present = (ldt_info.flags >> 5) & 1;
4188 useable = (ldt_info.flags >> 6) & 1;
4189#ifdef TARGET_ABI32
4190 lm = 0;
4191#else
4192 lm = (ldt_info.flags >> 7) & 1;
4193#endif
4194
4195 if (contents == 3) {
4196 if (seg_not_present == 0)
4197 return -TARGET_EINVAL;
4198 }
4199
4200 /* NOTE: same code as Linux kernel */
4201 /* Allow LDTs to be cleared by the user. */
4202 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4203 if ((contents == 0 &&
4204 read_exec_only == 1 &&
4205 seg_32bit == 0 &&
4206 limit_in_pages == 0 &&
4207 seg_not_present == 1 &&
4208 useable == 0 )) {
4209 entry_1 = 0;
4210 entry_2 = 0;
4211 goto install;
4212 }
4213 }
4214
4215 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4216 (ldt_info.limit & 0x0ffff);
4217 entry_2 = (ldt_info.base_addr & 0xff000000) |
4218 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4219 (ldt_info.limit & 0xf0000) |
4220 ((read_exec_only ^ 1) << 9) |
4221 (contents << 10) |
4222 ((seg_not_present ^ 1) << 15) |
4223 (seg_32bit << 22) |
4224 (limit_in_pages << 23) |
4225 (useable << 20) |
4226 (lm << 21) |
4227 0x7000;
4228
4229 /* Install the new entry ... */
4230install:
4231 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4232 lp[0] = tswap32(entry_1);
4233 lp[1] = tswap32(entry_2);
4234 return 0;
4235}
4236
blueswir18fcd3692008-08-17 20:26:25 +00004237static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004238{
4239 struct target_modify_ldt_ldt_s *target_ldt_info;
4240 uint64_t *gdt_table = g2h(env->gdt.base);
4241 uint32_t base_addr, limit, flags;
4242 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4243 int seg_not_present, useable, lm;
4244 uint32_t *lp, entry_1, entry_2;
4245
4246 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4247 if (!target_ldt_info)
4248 return -TARGET_EFAULT;
4249 idx = tswap32(target_ldt_info->entry_number);
4250 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4251 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4252 unlock_user_struct(target_ldt_info, ptr, 1);
4253 return -TARGET_EINVAL;
4254 }
4255 lp = (uint32_t *)(gdt_table + idx);
4256 entry_1 = tswap32(lp[0]);
4257 entry_2 = tswap32(lp[1]);
4258
4259 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4260 contents = (entry_2 >> 10) & 3;
4261 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4262 seg_32bit = (entry_2 >> 22) & 1;
4263 limit_in_pages = (entry_2 >> 23) & 1;
4264 useable = (entry_2 >> 20) & 1;
4265#ifdef TARGET_ABI32
4266 lm = 0;
4267#else
4268 lm = (entry_2 >> 21) & 1;
4269#endif
4270 flags = (seg_32bit << 0) | (contents << 1) |
4271 (read_exec_only << 3) | (limit_in_pages << 4) |
4272 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4273 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4274 base_addr = (entry_1 >> 16) |
4275 (entry_2 & 0xff000000) |
4276 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004277 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004278 target_ldt_info->limit = tswap32(limit);
4279 target_ldt_info->flags = tswap32(flags);
4280 unlock_user_struct(target_ldt_info, ptr, 1);
4281 return 0;
4282}
blueswir14583f582008-08-24 10:35:55 +00004283#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004284
bellardd2fd1af2007-11-14 18:08:56 +00004285#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004286abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004287{
Juan Quintela1add8692011-06-16 17:37:09 +01004288 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004289 abi_ulong val;
4290 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004291
bellardd2fd1af2007-11-14 18:08:56 +00004292 switch(code) {
4293 case TARGET_ARCH_SET_GS:
4294 case TARGET_ARCH_SET_FS:
4295 if (code == TARGET_ARCH_SET_GS)
4296 idx = R_GS;
4297 else
4298 idx = R_FS;
4299 cpu_x86_load_seg(env, idx, 0);
4300 env->segs[idx].base = addr;
4301 break;
4302 case TARGET_ARCH_GET_GS:
4303 case TARGET_ARCH_GET_FS:
4304 if (code == TARGET_ARCH_GET_GS)
4305 idx = R_GS;
4306 else
4307 idx = R_FS;
4308 val = env->segs[idx].base;
4309 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004310 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004311 break;
4312 default:
4313 ret = -TARGET_EINVAL;
4314 break;
4315 }
Juan Quintela1add8692011-06-16 17:37:09 +01004316 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004317}
4318#endif
4319
bellard2ab83ea2003-06-15 19:56:46 +00004320#endif /* defined(TARGET_I386) */
4321
Riku Voipio05098a92011-03-04 15:27:29 +02004322#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004323
pbrookd865bab2008-06-07 22:12:17 +00004324
4325static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4326typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004327 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004328 pthread_mutex_t mutex;
4329 pthread_cond_t cond;
4330 pthread_t thread;
4331 uint32_t tid;
4332 abi_ulong child_tidptr;
4333 abi_ulong parent_tidptr;
4334 sigset_t sigmask;
4335} new_thread_info;
4336
4337static void *clone_func(void *arg)
4338{
4339 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004340 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004341 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004342 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004343
4344 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004345 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004346 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004347 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004348 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004349 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004350 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004351 if (info->child_tidptr)
4352 put_user_u32(info->tid, info->child_tidptr);
4353 if (info->parent_tidptr)
4354 put_user_u32(info->tid, info->parent_tidptr);
4355 /* Enable signals. */
4356 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4357 /* Signal to the parent that we're ready. */
4358 pthread_mutex_lock(&info->mutex);
4359 pthread_cond_broadcast(&info->cond);
4360 pthread_mutex_unlock(&info->mutex);
4361 /* Wait until the parent has finshed initializing the tls state. */
4362 pthread_mutex_lock(&clone_lock);
4363 pthread_mutex_unlock(&clone_lock);
4364 cpu_loop(env);
4365 /* never exits */
4366 return NULL;
4367}
bellard1b6b0292003-03-22 17:31:38 +00004368
ths0da46a62007-10-20 20:23:07 +00004369/* do_fork() Must return host values and target errnos (unlike most
4370 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004371static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004372 abi_ulong parent_tidptr, target_ulong newtls,
4373 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004374{
Andreas Färber0429a972013-08-26 18:14:44 +02004375 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004376 int ret;
bellard5cd43932003-03-29 16:54:36 +00004377 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004378 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004379 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004380 unsigned int nptl_flags;
4381 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004382
balrog436d1242008-09-21 02:39:45 +00004383 /* Emulate vfork() with fork() */
4384 if (flags & CLONE_VFORK)
4385 flags &= ~(CLONE_VFORK | CLONE_VM);
4386
bellard1b6b0292003-03-22 17:31:38 +00004387 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004388 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004389 new_thread_info info;
4390 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004391
Anthony Liguori7267c092011-08-20 22:09:37 -05004392 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004393 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004394 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004395 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004396 /* Init regs that differ from the parent. */
4397 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004398 new_cpu = ENV_GET_CPU(new_env);
4399 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004400 ts->bprm = parent_ts->bprm;
4401 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004402 nptl_flags = flags;
4403 flags &= ~CLONE_NPTL_FLAGS2;
4404
pbrookc2764712009-03-07 15:24:59 +00004405 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4406 ts->child_tidptr = child_tidptr;
4407 }
4408
pbrookd865bab2008-06-07 22:12:17 +00004409 if (nptl_flags & CLONE_SETTLS)
4410 cpu_set_tls (new_env, newtls);
4411
4412 /* Grab a mutex so that thread setup appears atomic. */
4413 pthread_mutex_lock(&clone_lock);
4414
4415 memset(&info, 0, sizeof(info));
4416 pthread_mutex_init(&info.mutex, NULL);
4417 pthread_mutex_lock(&info.mutex);
4418 pthread_cond_init(&info.cond, NULL);
4419 info.env = new_env;
4420 if (nptl_flags & CLONE_CHILD_SETTID)
4421 info.child_tidptr = child_tidptr;
4422 if (nptl_flags & CLONE_PARENT_SETTID)
4423 info.parent_tidptr = parent_tidptr;
4424
4425 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004426 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4427 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004428 /* It is not safe to deliver signals until the child has finished
4429 initializing, so temporarily block all signals. */
4430 sigfillset(&sigmask);
4431 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4432
4433 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004434 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004435
4436 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4437 pthread_attr_destroy(&attr);
4438 if (ret == 0) {
4439 /* Wait for the child to initialize. */
4440 pthread_cond_wait(&info.cond, &info.mutex);
4441 ret = info.tid;
4442 if (flags & CLONE_PARENT_SETTID)
4443 put_user_u32(ret, parent_tidptr);
4444 } else {
4445 ret = -1;
4446 }
4447 pthread_mutex_unlock(&info.mutex);
4448 pthread_cond_destroy(&info.cond);
4449 pthread_mutex_destroy(&info.mutex);
4450 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004451 } else {
4452 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004453 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004454 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004455 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004456 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004457 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004458 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004459 cpu_clone_regs(env, newsp);
4460 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004461 /* There is a race condition here. The parent process could
4462 theoretically read the TID in the child process before the child
4463 tid is set. This would require using either ptrace
4464 (not implemented) or having *_tidptr to point at a shared memory
4465 mapping. We can't repeat the spinlock hack used above because
4466 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004467 if (flags & CLONE_CHILD_SETTID)
4468 put_user_u32(gettid(), child_tidptr);
4469 if (flags & CLONE_PARENT_SETTID)
4470 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004471 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004472 if (flags & CLONE_SETTLS)
4473 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004474 if (flags & CLONE_CHILD_CLEARTID)
4475 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004476 } else {
4477 fork_end(0);
4478 }
bellard1b6b0292003-03-22 17:31:38 +00004479 }
4480 return ret;
4481}
4482
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004483/* warning : doesn't handle linux specific flags... */
4484static int target_to_host_fcntl_cmd(int cmd)
4485{
4486 switch(cmd) {
4487 case TARGET_F_DUPFD:
4488 case TARGET_F_GETFD:
4489 case TARGET_F_SETFD:
4490 case TARGET_F_GETFL:
4491 case TARGET_F_SETFL:
4492 return cmd;
4493 case TARGET_F_GETLK:
4494 return F_GETLK;
4495 case TARGET_F_SETLK:
4496 return F_SETLK;
4497 case TARGET_F_SETLKW:
4498 return F_SETLKW;
4499 case TARGET_F_GETOWN:
4500 return F_GETOWN;
4501 case TARGET_F_SETOWN:
4502 return F_SETOWN;
4503 case TARGET_F_GETSIG:
4504 return F_GETSIG;
4505 case TARGET_F_SETSIG:
4506 return F_SETSIG;
4507#if TARGET_ABI_BITS == 32
4508 case TARGET_F_GETLK64:
4509 return F_GETLK64;
4510 case TARGET_F_SETLK64:
4511 return F_SETLK64;
4512 case TARGET_F_SETLKW64:
4513 return F_SETLKW64;
4514#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004515 case TARGET_F_SETLEASE:
4516 return F_SETLEASE;
4517 case TARGET_F_GETLEASE:
4518 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004519#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004520 case TARGET_F_DUPFD_CLOEXEC:
4521 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004522#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004523 case TARGET_F_NOTIFY:
4524 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004525#ifdef F_GETOWN_EX
4526 case TARGET_F_GETOWN_EX:
4527 return F_GETOWN_EX;
4528#endif
4529#ifdef F_SETOWN_EX
4530 case TARGET_F_SETOWN_EX:
4531 return F_SETOWN_EX;
4532#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004533 default:
4534 return -TARGET_EINVAL;
4535 }
4536 return -TARGET_EINVAL;
4537}
4538
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004539#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4540static const bitmask_transtbl flock_tbl[] = {
4541 TRANSTBL_CONVERT(F_RDLCK),
4542 TRANSTBL_CONVERT(F_WRLCK),
4543 TRANSTBL_CONVERT(F_UNLCK),
4544 TRANSTBL_CONVERT(F_EXLCK),
4545 TRANSTBL_CONVERT(F_SHLCK),
4546 { 0, 0, 0, 0 }
4547};
4548
blueswir1992f48a2007-10-14 16:27:31 +00004549static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004550{
4551 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004552 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004553 struct flock64 fl64;
4554 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004555#ifdef F_GETOWN_EX
4556 struct f_owner_ex fox;
4557 struct target_f_owner_ex *target_fox;
4558#endif
blueswir1992f48a2007-10-14 16:27:31 +00004559 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004560 int host_cmd = target_to_host_fcntl_cmd(cmd);
4561
4562 if (host_cmd == -TARGET_EINVAL)
4563 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004564
bellard7775e9e2003-05-14 22:46:48 +00004565 switch(cmd) {
4566 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004567 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4568 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004569 fl.l_type =
4570 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004571 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004572 fl.l_start = tswapal(target_fl->l_start);
4573 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004574 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004575 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004576 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004577 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004578 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4579 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004580 target_fl->l_type =
4581 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004582 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004583 target_fl->l_start = tswapal(fl.l_start);
4584 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004585 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004586 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004587 }
4588 break;
ths3b46e622007-09-17 08:09:54 +00004589
bellard7775e9e2003-05-14 22:46:48 +00004590 case TARGET_F_SETLK:
4591 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004592 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4593 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004594 fl.l_type =
4595 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004596 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004597 fl.l_start = tswapal(target_fl->l_start);
4598 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004599 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004600 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004601 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004602 break;
ths3b46e622007-09-17 08:09:54 +00004603
bellard7775e9e2003-05-14 22:46:48 +00004604 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004605 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4606 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004607 fl64.l_type =
4608 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004609 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004610 fl64.l_start = tswap64(target_fl64->l_start);
4611 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004612 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004613 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004614 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004615 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004616 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4617 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004618 target_fl64->l_type =
4619 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004620 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004621 target_fl64->l_start = tswap64(fl64.l_start);
4622 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004623 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004624 unlock_user_struct(target_fl64, arg, 1);
4625 }
bellard9ee1fa22007-11-11 15:11:19 +00004626 break;
bellard7775e9e2003-05-14 22:46:48 +00004627 case TARGET_F_SETLK64:
4628 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004629 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4630 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004631 fl64.l_type =
4632 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004633 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004634 fl64.l_start = tswap64(target_fl64->l_start);
4635 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004636 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004637 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004638 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004639 break;
4640
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004641 case TARGET_F_GETFL:
4642 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004643 if (ret >= 0) {
4644 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4645 }
bellardffa65c32004-01-04 23:57:22 +00004646 break;
4647
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004648 case TARGET_F_SETFL:
4649 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4650 break;
4651
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004652#ifdef F_GETOWN_EX
4653 case TARGET_F_GETOWN_EX:
4654 ret = get_errno(fcntl(fd, host_cmd, &fox));
4655 if (ret >= 0) {
4656 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4657 return -TARGET_EFAULT;
4658 target_fox->type = tswap32(fox.type);
4659 target_fox->pid = tswap32(fox.pid);
4660 unlock_user_struct(target_fox, arg, 1);
4661 }
4662 break;
4663#endif
4664
4665#ifdef F_SETOWN_EX
4666 case TARGET_F_SETOWN_EX:
4667 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4668 return -TARGET_EFAULT;
4669 fox.type = tswap32(target_fox->type);
4670 fox.pid = tswap32(target_fox->pid);
4671 unlock_user_struct(target_fox, arg, 0);
4672 ret = get_errno(fcntl(fd, host_cmd, &fox));
4673 break;
4674#endif
4675
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004676 case TARGET_F_SETOWN:
4677 case TARGET_F_GETOWN:
4678 case TARGET_F_SETSIG:
4679 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004680 case TARGET_F_SETLEASE:
4681 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004682 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004683 break;
4684
bellard7775e9e2003-05-14 22:46:48 +00004685 default:
bellard9ee1fa22007-11-11 15:11:19 +00004686 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004687 break;
4688 }
4689 return ret;
4690}
4691
bellard67867302003-11-23 17:05:30 +00004692#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004693
bellard67867302003-11-23 17:05:30 +00004694static inline int high2lowuid(int uid)
4695{
4696 if (uid > 65535)
4697 return 65534;
4698 else
4699 return uid;
4700}
4701
4702static inline int high2lowgid(int gid)
4703{
4704 if (gid > 65535)
4705 return 65534;
4706 else
4707 return gid;
4708}
4709
4710static inline int low2highuid(int uid)
4711{
4712 if ((int16_t)uid == -1)
4713 return -1;
4714 else
4715 return uid;
4716}
4717
4718static inline int low2highgid(int gid)
4719{
4720 if ((int16_t)gid == -1)
4721 return -1;
4722 else
4723 return gid;
4724}
Riku Voipio0c866a72011-04-18 15:23:06 +03004725static inline int tswapid(int id)
4726{
4727 return tswap16(id);
4728}
Peter Maydell76ca3102014-03-02 19:36:41 +00004729
4730#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4731
Riku Voipio0c866a72011-04-18 15:23:06 +03004732#else /* !USE_UID16 */
4733static inline int high2lowuid(int uid)
4734{
4735 return uid;
4736}
4737static inline int high2lowgid(int gid)
4738{
4739 return gid;
4740}
4741static inline int low2highuid(int uid)
4742{
4743 return uid;
4744}
4745static inline int low2highgid(int gid)
4746{
4747 return gid;
4748}
4749static inline int tswapid(int id)
4750{
4751 return tswap32(id);
4752}
Peter Maydell76ca3102014-03-02 19:36:41 +00004753
4754#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4755
bellard67867302003-11-23 17:05:30 +00004756#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004757
bellard31e31b82003-02-18 22:55:36 +00004758void syscall_init(void)
4759{
bellard2ab83ea2003-06-15 19:56:46 +00004760 IOCTLEntry *ie;
4761 const argtype *arg_type;
4762 int size;
thsb92c47c2007-11-01 00:07:38 +00004763 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004764
Blue Swirl001faf32009-05-13 17:53:17 +00004765#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004766#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004767#include "syscall_types.h"
4768#undef STRUCT
4769#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004770
Peter Maydelldd6e9572012-07-23 08:07:22 +00004771 /* Build target_to_host_errno_table[] table from
4772 * host_to_target_errno_table[]. */
4773 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4774 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4775 }
4776
bellard2ab83ea2003-06-15 19:56:46 +00004777 /* we patch the ioctl size if necessary. We rely on the fact that
4778 no ioctl has all the bits at '1' in the size field */
4779 ie = ioctl_entries;
4780 while (ie->target_cmd != 0) {
4781 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4782 TARGET_IOC_SIZEMASK) {
4783 arg_type = ie->arg_type;
4784 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004785 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004786 ie->target_cmd);
4787 exit(1);
4788 }
4789 arg_type++;
4790 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004791 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004792 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4793 (size << TARGET_IOC_SIZESHIFT);
4794 }
thsb92c47c2007-11-01 00:07:38 +00004795
bellard2ab83ea2003-06-15 19:56:46 +00004796 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004797#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4798 (defined(__x86_64__) && defined(TARGET_X86_64))
4799 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4800 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4801 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004802 }
4803#endif
4804 ie++;
4805 }
bellard31e31b82003-02-18 22:55:36 +00004806}
bellardc573ff62004-01-04 15:51:36 +00004807
blueswir1992f48a2007-10-14 16:27:31 +00004808#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004809static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4810{
thsaf325d32008-06-10 15:29:15 +00004811#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004812 return ((uint64_t)word0 << 32) | word1;
4813#else
4814 return ((uint64_t)word1 << 32) | word0;
4815#endif
4816}
blueswir1992f48a2007-10-14 16:27:31 +00004817#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004818static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4819{
4820 return word0;
4821}
blueswir1992f48a2007-10-14 16:27:31 +00004822#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004823
4824#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004825static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4826 abi_long arg2,
4827 abi_long arg3,
4828 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004829{
Riku Voipio48e515d2011-07-12 15:40:51 +03004830 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004831 arg2 = arg3;
4832 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004833 }
pbrookce4defa2006-02-09 16:49:55 +00004834 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4835}
4836#endif
4837
4838#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004839static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4840 abi_long arg2,
4841 abi_long arg3,
4842 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004843{
Riku Voipio48e515d2011-07-12 15:40:51 +03004844 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004845 arg2 = arg3;
4846 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004847 }
pbrookce4defa2006-02-09 16:49:55 +00004848 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4849}
4850#endif
4851
bellard579a97f2007-11-11 14:26:47 +00004852static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4853 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004854{
4855 struct target_timespec *target_ts;
4856
bellard579a97f2007-11-11 14:26:47 +00004857 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4858 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004859 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4860 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004861 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004862 return 0;
pbrook53a59602006-03-25 19:31:22 +00004863}
4864
bellard579a97f2007-11-11 14:26:47 +00004865static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4866 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004867{
4868 struct target_timespec *target_ts;
4869
bellard579a97f2007-11-11 14:26:47 +00004870 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4871 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004872 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4873 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004874 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004875 return 0;
pbrook53a59602006-03-25 19:31:22 +00004876}
4877
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004878static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4879 abi_ulong target_addr)
4880{
4881 struct target_itimerspec *target_itspec;
4882
4883 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4884 return -TARGET_EFAULT;
4885 }
4886
4887 host_itspec->it_interval.tv_sec =
4888 tswapal(target_itspec->it_interval.tv_sec);
4889 host_itspec->it_interval.tv_nsec =
4890 tswapal(target_itspec->it_interval.tv_nsec);
4891 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4892 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4893
4894 unlock_user_struct(target_itspec, target_addr, 1);
4895 return 0;
4896}
4897
4898static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4899 struct itimerspec *host_its)
4900{
4901 struct target_itimerspec *target_itspec;
4902
4903 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4904 return -TARGET_EFAULT;
4905 }
4906
4907 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4908 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4909
4910 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4911 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4912
4913 unlock_user_struct(target_itspec, target_addr, 0);
4914 return 0;
4915}
4916
aurel329d33b762009-04-08 23:07:05 +00004917#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004918static inline abi_long host_to_target_stat64(void *cpu_env,
4919 abi_ulong target_addr,
4920 struct stat *host_st)
4921{
Alexander Graf09701192013-09-03 20:12:15 +01004922#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004923 if (((CPUARMState *)cpu_env)->eabi) {
4924 struct target_eabi_stat64 *target_st;
4925
4926 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4927 return -TARGET_EFAULT;
4928 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4929 __put_user(host_st->st_dev, &target_st->st_dev);
4930 __put_user(host_st->st_ino, &target_st->st_ino);
4931#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4932 __put_user(host_st->st_ino, &target_st->__st_ino);
4933#endif
4934 __put_user(host_st->st_mode, &target_st->st_mode);
4935 __put_user(host_st->st_nlink, &target_st->st_nlink);
4936 __put_user(host_st->st_uid, &target_st->st_uid);
4937 __put_user(host_st->st_gid, &target_st->st_gid);
4938 __put_user(host_st->st_rdev, &target_st->st_rdev);
4939 __put_user(host_st->st_size, &target_st->st_size);
4940 __put_user(host_st->st_blksize, &target_st->st_blksize);
4941 __put_user(host_st->st_blocks, &target_st->st_blocks);
4942 __put_user(host_st->st_atime, &target_st->target_st_atime);
4943 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4944 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4945 unlock_user_struct(target_st, target_addr, 1);
4946 } else
4947#endif
4948 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004949#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004950 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004951#else
4952 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004953#endif
balrog6a24a772008-09-20 02:23:36 +00004954
4955 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4956 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004957 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004958 __put_user(host_st->st_dev, &target_st->st_dev);
4959 __put_user(host_st->st_ino, &target_st->st_ino);
4960#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4961 __put_user(host_st->st_ino, &target_st->__st_ino);
4962#endif
4963 __put_user(host_st->st_mode, &target_st->st_mode);
4964 __put_user(host_st->st_nlink, &target_st->st_nlink);
4965 __put_user(host_st->st_uid, &target_st->st_uid);
4966 __put_user(host_st->st_gid, &target_st->st_gid);
4967 __put_user(host_st->st_rdev, &target_st->st_rdev);
4968 /* XXX: better use of kernel struct */
4969 __put_user(host_st->st_size, &target_st->st_size);
4970 __put_user(host_st->st_blksize, &target_st->st_blksize);
4971 __put_user(host_st->st_blocks, &target_st->st_blocks);
4972 __put_user(host_st->st_atime, &target_st->target_st_atime);
4973 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4974 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4975 unlock_user_struct(target_st, target_addr, 1);
4976 }
4977
4978 return 0;
4979}
4980#endif
4981
pbrookbd0c5662008-05-29 14:34:11 +00004982/* ??? Using host futex calls even when target atomic operations
4983 are not really atomic probably breaks things. However implementing
4984 futexes locally would make futexes shared between multiple processes
4985 tricky. However they're probably useless because guest atomic
4986 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004987static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4988 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004989{
4990 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004991 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004992
4993 /* ??? We assume FUTEX_* constants are the same on both host
4994 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004995#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004996 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004997#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004998 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004999#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005000 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005001 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005002 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005003 if (timeout) {
5004 pts = &ts;
5005 target_to_host_timespec(pts, timeout);
5006 } else {
5007 pts = NULL;
5008 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005009 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005010 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005011 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005012 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005013 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005014 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005015 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005016 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005017 case FUTEX_WAKE_OP:
5018 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5019 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5020 But the prototype takes a `struct timespec *'; insert casts
5021 to satisfy the compiler. We do not need to tswap TIMEOUT
5022 since it's not compared to guest memory. */
5023 pts = (struct timespec *)(uintptr_t) timeout;
5024 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5025 g2h(uaddr2),
5026 (base_op == FUTEX_CMP_REQUEUE
5027 ? tswap32(val3)
5028 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005029 default:
5030 return -TARGET_ENOSYS;
5031 }
5032}
pbrookbd0c5662008-05-29 14:34:11 +00005033
pbrook1d9d8b52009-04-16 15:17:02 +00005034/* Map host to target signal numbers for the wait family of syscalls.
5035 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005036int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005037{
5038 if (WIFSIGNALED(status)) {
5039 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5040 }
5041 if (WIFSTOPPED(status)) {
5042 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5043 | (status & 0xff);
5044 }
5045 return status;
5046}
5047
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005048static int open_self_cmdline(void *cpu_env, int fd)
5049{
5050 int fd_orig = -1;
5051 bool word_skipped = false;
5052
5053 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5054 if (fd_orig < 0) {
5055 return fd_orig;
5056 }
5057
5058 while (true) {
5059 ssize_t nb_read;
5060 char buf[128];
5061 char *cp_buf = buf;
5062
5063 nb_read = read(fd_orig, buf, sizeof(buf));
5064 if (nb_read < 0) {
5065 fd_orig = close(fd_orig);
5066 return -1;
5067 } else if (nb_read == 0) {
5068 break;
5069 }
5070
5071 if (!word_skipped) {
5072 /* Skip the first string, which is the path to qemu-*-static
5073 instead of the actual command. */
5074 cp_buf = memchr(buf, 0, sizeof(buf));
5075 if (cp_buf) {
5076 /* Null byte found, skip one string */
5077 cp_buf++;
5078 nb_read -= cp_buf - buf;
5079 word_skipped = true;
5080 }
5081 }
5082
5083 if (word_skipped) {
5084 if (write(fd, cp_buf, nb_read) != nb_read) {
5085 return -1;
5086 }
5087 }
5088 }
5089
5090 return close(fd_orig);
5091}
5092
Alexander Graf36c08d42011-11-02 20:23:24 +01005093static int open_self_maps(void *cpu_env, int fd)
5094{
Andreas Färber0429a972013-08-26 18:14:44 +02005095 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5096 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005097 FILE *fp;
5098 char *line = NULL;
5099 size_t len = 0;
5100 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005101
Alexander Graf1a49ef22012-05-01 16:30:28 +01005102 fp = fopen("/proc/self/maps", "r");
5103 if (fp == NULL) {
5104 return -EACCES;
5105 }
5106
5107 while ((read = getline(&line, &len, fp)) != -1) {
5108 int fields, dev_maj, dev_min, inode;
5109 uint64_t min, max, offset;
5110 char flag_r, flag_w, flag_x, flag_p;
5111 char path[512] = "";
5112 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5113 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5114 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5115
5116 if ((fields < 10) || (fields > 11)) {
5117 continue;
5118 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005119 if (h2g_valid(min)) {
5120 int flags = page_get_flags(h2g(min));
5121 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5122 if (page_check_range(h2g(min), max - min, flags) == -1) {
5123 continue;
5124 }
5125 if (h2g(min) == ts->info->stack_limit) {
5126 pstrcpy(path, sizeof(path), " [stack]");
5127 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005128 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005129 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005130 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005131 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005132 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005133 }
5134 }
5135
5136 free(line);
5137 fclose(fp);
5138
Alexander Graf36c08d42011-11-02 20:23:24 +01005139 return 0;
5140}
5141
Alexander Graf480b8e72011-11-02 20:23:25 +01005142static int open_self_stat(void *cpu_env, int fd)
5143{
Andreas Färber0429a972013-08-26 18:14:44 +02005144 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5145 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005146 abi_ulong start_stack = ts->info->start_stack;
5147 int i;
5148
5149 for (i = 0; i < 44; i++) {
5150 char buf[128];
5151 int len;
5152 uint64_t val = 0;
5153
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005154 if (i == 0) {
5155 /* pid */
5156 val = getpid();
5157 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5158 } else if (i == 1) {
5159 /* app name */
5160 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5161 } else if (i == 27) {
5162 /* stack bottom */
5163 val = start_stack;
5164 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5165 } else {
5166 /* for the rest, there is MasterCard */
5167 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005168 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005169
Alexander Graf480b8e72011-11-02 20:23:25 +01005170 len = strlen(buf);
5171 if (write(fd, buf, len) != len) {
5172 return -1;
5173 }
5174 }
5175
5176 return 0;
5177}
5178
Alexander Graf257450e2011-11-02 20:23:26 +01005179static int open_self_auxv(void *cpu_env, int fd)
5180{
Andreas Färber0429a972013-08-26 18:14:44 +02005181 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5182 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005183 abi_ulong auxv = ts->info->saved_auxv;
5184 abi_ulong len = ts->info->auxv_len;
5185 char *ptr;
5186
5187 /*
5188 * Auxiliary vector is stored in target process stack.
5189 * read in whole auxv vector and copy it to file
5190 */
5191 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5192 if (ptr != NULL) {
5193 while (len > 0) {
5194 ssize_t r;
5195 r = write(fd, ptr, len);
5196 if (r <= 0) {
5197 break;
5198 }
5199 len -= r;
5200 ptr += r;
5201 }
5202 lseek(fd, 0, SEEK_SET);
5203 unlock_user(ptr, auxv, len);
5204 }
5205
5206 return 0;
5207}
5208
Andreas Schwab463d8e72013-07-02 14:04:12 +01005209static int is_proc_myself(const char *filename, const char *entry)
5210{
5211 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5212 filename += strlen("/proc/");
5213 if (!strncmp(filename, "self/", strlen("self/"))) {
5214 filename += strlen("self/");
5215 } else if (*filename >= '1' && *filename <= '9') {
5216 char myself[80];
5217 snprintf(myself, sizeof(myself), "%d/", getpid());
5218 if (!strncmp(filename, myself, strlen(myself))) {
5219 filename += strlen(myself);
5220 } else {
5221 return 0;
5222 }
5223 } else {
5224 return 0;
5225 }
5226 if (!strcmp(filename, entry)) {
5227 return 1;
5228 }
5229 }
5230 return 0;
5231}
5232
Laurent Vivierde6b9932013-08-30 01:46:40 +02005233#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5234static int is_proc(const char *filename, const char *entry)
5235{
5236 return strcmp(filename, entry) == 0;
5237}
5238
5239static int open_net_route(void *cpu_env, int fd)
5240{
5241 FILE *fp;
5242 char *line = NULL;
5243 size_t len = 0;
5244 ssize_t read;
5245
5246 fp = fopen("/proc/net/route", "r");
5247 if (fp == NULL) {
5248 return -EACCES;
5249 }
5250
5251 /* read header */
5252
5253 read = getline(&line, &len, fp);
5254 dprintf(fd, "%s", line);
5255
5256 /* read routes */
5257
5258 while ((read = getline(&line, &len, fp)) != -1) {
5259 char iface[16];
5260 uint32_t dest, gw, mask;
5261 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5262 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5263 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5264 &mask, &mtu, &window, &irtt);
5265 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5266 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5267 metric, tswap32(mask), mtu, window, irtt);
5268 }
5269
5270 free(line);
5271 fclose(fp);
5272
5273 return 0;
5274}
5275#endif
5276
Alexander Graf3be14d02011-11-02 20:23:23 +01005277static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5278{
5279 struct fake_open {
5280 const char *filename;
5281 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005282 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005283 };
5284 const struct fake_open *fake_open;
5285 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005286 { "maps", open_self_maps, is_proc_myself },
5287 { "stat", open_self_stat, is_proc_myself },
5288 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005289 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005290#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5291 { "/proc/net/route", open_net_route, is_proc },
5292#endif
5293 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005294 };
5295
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005296 if (is_proc_myself(pathname, "exe")) {
5297 int execfd = qemu_getauxval(AT_EXECFD);
5298 return execfd ? execfd : get_errno(open(exec_path, flags, mode));
5299 }
5300
Alexander Graf3be14d02011-11-02 20:23:23 +01005301 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005302 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005303 break;
5304 }
5305 }
5306
5307 if (fake_open->filename) {
5308 const char *tmpdir;
5309 char filename[PATH_MAX];
5310 int fd, r;
5311
5312 /* create temporary file to map stat to */
5313 tmpdir = getenv("TMPDIR");
5314 if (!tmpdir)
5315 tmpdir = "/tmp";
5316 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5317 fd = mkstemp(filename);
5318 if (fd < 0) {
5319 return fd;
5320 }
5321 unlink(filename);
5322
5323 if ((r = fake_open->fill(cpu_env, fd))) {
5324 close(fd);
5325 return r;
5326 }
5327 lseek(fd, 0, SEEK_SET);
5328
5329 return fd;
5330 }
5331
5332 return get_errno(open(path(pathname), flags, mode));
5333}
5334
ths0da46a62007-10-20 20:23:07 +00005335/* do_syscall() should always have a single exit point at the end so
5336 that actions, such as logging of syscall results, can be performed.
5337 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005338abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5339 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005340 abi_long arg5, abi_long arg6, abi_long arg7,
5341 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005342{
Andreas Färber182735e2013-05-29 22:29:20 +02005343 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005344 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005345 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005346 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005347 void *p;
ths3b46e622007-09-17 08:09:54 +00005348
bellard72f03902003-02-18 23:33:18 +00005349#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005350 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005351#endif
thsb92c47c2007-11-01 00:07:38 +00005352 if(do_strace)
5353 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5354
bellard31e31b82003-02-18 22:55:36 +00005355 switch(num) {
5356 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005357 /* In old applications this may be used to implement _exit(2).
5358 However in threaded applictions it is used for thread termination,
5359 and _exit_group is used for application termination.
5360 Do thread termination if we have more then one thread. */
5361 /* FIXME: This probably breaks if a signal arrives. We should probably
5362 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005363 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005364 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005365
Andreas Färber9b056fc2013-06-24 23:53:10 +02005366 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005367 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005368 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005369 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005370 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005371 if (ts->child_tidptr) {
5372 put_user_u32(0, ts->child_tidptr);
5373 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5374 NULL, NULL, 0);
5375 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005376 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005377 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005378 g_free(ts);
5379 pthread_exit(NULL);
5380 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005381#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005382 _mcleanup();
5383#endif
bellarde9009672005-04-26 20:42:36 +00005384 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005385 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005386 ret = 0; /* avoid warning */
5387 break;
5388 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005389 if (arg3 == 0)
5390 ret = 0;
5391 else {
5392 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5393 goto efault;
5394 ret = get_errno(read(arg1, p, arg3));
5395 unlock_user(p, arg2, ret);
5396 }
bellard31e31b82003-02-18 22:55:36 +00005397 break;
5398 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005399 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5400 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005401 ret = get_errno(write(arg1, p, arg3));
5402 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005403 break;
5404 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005405 if (!(p = lock_user_string(arg1)))
5406 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005407 ret = get_errno(do_open(cpu_env, p,
5408 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5409 arg3));
pbrook53a59602006-03-25 19:31:22 +00005410 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005411 break;
ths82424832007-09-24 09:21:55 +00005412#if defined(TARGET_NR_openat) && defined(__NR_openat)
5413 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005414 if (!(p = lock_user_string(arg2)))
5415 goto efault;
5416 ret = get_errno(sys_openat(arg1,
5417 path(p),
5418 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5419 arg4));
5420 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005421 break;
5422#endif
bellard31e31b82003-02-18 22:55:36 +00005423 case TARGET_NR_close:
5424 ret = get_errno(close(arg1));
5425 break;
5426 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005427 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005428 break;
5429 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005430 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005431 break;
thse5febef2007-04-01 18:31:35 +00005432#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005433 case TARGET_NR_waitpid:
5434 {
pbrook53a59602006-03-25 19:31:22 +00005435 int status;
5436 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005437 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005438 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005439 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005440 }
5441 break;
thse5febef2007-04-01 18:31:35 +00005442#endif
pbrookf0cbb612008-05-30 18:20:05 +00005443#ifdef TARGET_NR_waitid
5444 case TARGET_NR_waitid:
5445 {
5446 siginfo_t info;
5447 info.si_pid = 0;
5448 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5449 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005450 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005451 goto efault;
5452 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005453 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005454 }
5455 }
5456 break;
5457#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005458#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005459 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005460 if (!(p = lock_user_string(arg1)))
5461 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005462 ret = get_errno(creat(p, arg2));
5463 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005464 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005465#endif
bellard31e31b82003-02-18 22:55:36 +00005466 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005467 {
5468 void * p2;
5469 p = lock_user_string(arg1);
5470 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005471 if (!p || !p2)
5472 ret = -TARGET_EFAULT;
5473 else
5474 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005475 unlock_user(p2, arg2, 0);
5476 unlock_user(p, arg1, 0);
5477 }
bellard31e31b82003-02-18 22:55:36 +00005478 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005479#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005480 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005481 {
5482 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005483 if (!arg2 || !arg4)
5484 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005485 p = lock_user_string(arg2);
5486 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005487 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005488 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005489 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005490 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005491 unlock_user(p, arg2, 0);
5492 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005493 }
5494 break;
5495#endif
bellard31e31b82003-02-18 22:55:36 +00005496 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005497 if (!(p = lock_user_string(arg1)))
5498 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005499 ret = get_errno(unlink(p));
5500 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005501 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005502#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005503 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005504 if (!(p = lock_user_string(arg2)))
5505 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005506 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005507 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005508 break;
balrogb7d35e62007-12-12 00:40:24 +00005509#endif
bellard31e31b82003-02-18 22:55:36 +00005510 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005511 {
5512 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005513 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005514 abi_ulong gp;
5515 abi_ulong guest_argp;
5516 abi_ulong guest_envp;
5517 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005518 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005519 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005520
bellardf7341ff2003-03-30 21:00:25 +00005521 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005522 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005523 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005524 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005525 goto efault;
ths03aa1972007-12-02 06:28:08 +00005526 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005527 break;
bellard7854b052003-03-29 17:22:23 +00005528 argc++;
bellard2f619692007-11-16 10:46:05 +00005529 }
bellardf7341ff2003-03-30 21:00:25 +00005530 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005531 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005532 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005533 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005534 goto efault;
ths03aa1972007-12-02 06:28:08 +00005535 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005536 break;
bellard7854b052003-03-29 17:22:23 +00005537 envc++;
bellard2f619692007-11-16 10:46:05 +00005538 }
bellard7854b052003-03-29 17:22:23 +00005539
bellardf7341ff2003-03-30 21:00:25 +00005540 argp = alloca((argc + 1) * sizeof(void *));
5541 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005542
pbrookda94d262008-05-30 18:24:00 +00005543 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005544 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005545 if (get_user_ual(addr, gp))
5546 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005547 if (!addr)
5548 break;
bellard2f619692007-11-16 10:46:05 +00005549 if (!(*q = lock_user_string(addr)))
5550 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005551 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005552 }
bellardf7341ff2003-03-30 21:00:25 +00005553 *q = NULL;
5554
pbrookda94d262008-05-30 18:24:00 +00005555 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005556 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005557 if (get_user_ual(addr, gp))
5558 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005559 if (!addr)
5560 break;
bellard2f619692007-11-16 10:46:05 +00005561 if (!(*q = lock_user_string(addr)))
5562 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005563 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005564 }
bellardf7341ff2003-03-30 21:00:25 +00005565 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005566
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005567 /* This case will not be caught by the host's execve() if its
5568 page size is bigger than the target's. */
5569 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5570 ret = -TARGET_E2BIG;
5571 goto execve_end;
5572 }
bellard2f619692007-11-16 10:46:05 +00005573 if (!(p = lock_user_string(arg1)))
5574 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005575 ret = get_errno(execve(p, argp, envp));
5576 unlock_user(p, arg1, 0);
5577
bellard2f619692007-11-16 10:46:05 +00005578 goto execve_end;
5579
5580 execve_efault:
5581 ret = -TARGET_EFAULT;
5582
5583 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005584 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005585 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005586 if (get_user_ual(addr, gp)
5587 || !addr)
5588 break;
pbrook53a59602006-03-25 19:31:22 +00005589 unlock_user(*q, addr, 0);
5590 }
5591 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005592 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005593 if (get_user_ual(addr, gp)
5594 || !addr)
5595 break;
pbrook53a59602006-03-25 19:31:22 +00005596 unlock_user(*q, addr, 0);
5597 }
bellard7854b052003-03-29 17:22:23 +00005598 }
bellard31e31b82003-02-18 22:55:36 +00005599 break;
5600 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005601 if (!(p = lock_user_string(arg1)))
5602 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005603 ret = get_errno(chdir(p));
5604 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005605 break;
bellarda315a142005-01-30 22:59:18 +00005606#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005607 case TARGET_NR_time:
5608 {
pbrook53a59602006-03-25 19:31:22 +00005609 time_t host_time;
5610 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005611 if (!is_error(ret)
5612 && arg1
5613 && put_user_sal(host_time, arg1))
5614 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005615 }
5616 break;
bellarda315a142005-01-30 22:59:18 +00005617#endif
bellard31e31b82003-02-18 22:55:36 +00005618 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005619 if (!(p = lock_user_string(arg1)))
5620 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005621 ret = get_errno(mknod(p, arg2, arg3));
5622 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005623 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005624#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005625 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005626 if (!(p = lock_user_string(arg2)))
5627 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005628 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005629 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005630 break;
5631#endif
bellard31e31b82003-02-18 22:55:36 +00005632 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005633 if (!(p = lock_user_string(arg1)))
5634 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005635 ret = get_errno(chmod(p, arg2));
5636 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005637 break;
bellardebc05482003-09-30 21:08:41 +00005638#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005639 case TARGET_NR_break:
5640 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005641#endif
5642#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005643 case TARGET_NR_oldstat:
5644 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005645#endif
bellard31e31b82003-02-18 22:55:36 +00005646 case TARGET_NR_lseek:
5647 ret = get_errno(lseek(arg1, arg2, arg3));
5648 break;
Richard Henderson92317332010-05-03 10:07:53 -07005649#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5650 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005651 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005652 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005653 ret = get_errno(getpid());
5654 break;
Richard Henderson92317332010-05-03 10:07:53 -07005655#endif
5656#ifdef TARGET_NR_getpid
5657 case TARGET_NR_getpid:
5658 ret = get_errno(getpid());
5659 break;
5660#endif
bellard31e31b82003-02-18 22:55:36 +00005661 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01005662 {
5663 /* need to look at the data field */
5664 void *p2, *p3;
5665
5666 if (arg1) {
5667 p = lock_user_string(arg1);
5668 if (!p) {
5669 goto efault;
5670 }
5671 } else {
5672 p = NULL;
5673 }
5674
5675 p2 = lock_user_string(arg2);
5676 if (!p2) {
5677 if (arg1) {
5678 unlock_user(p, arg1, 0);
5679 }
5680 goto efault;
5681 }
5682
5683 if (arg3) {
5684 p3 = lock_user_string(arg3);
5685 if (!p3) {
5686 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005687 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01005688 }
5689 unlock_user(p2, arg2, 0);
5690 goto efault;
5691 }
5692 } else {
5693 p3 = NULL;
5694 }
5695
5696 /* FIXME - arg5 should be locked, but it isn't clear how to
5697 * do that since it's not guaranteed to be a NULL-terminated
5698 * string.
5699 */
5700 if (!arg5) {
5701 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
5702 } else {
5703 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
5704 }
5705 ret = get_errno(ret);
5706
5707 if (arg1) {
5708 unlock_user(p, arg1, 0);
5709 }
5710 unlock_user(p2, arg2, 0);
5711 if (arg3) {
5712 unlock_user(p3, arg3, 0);
5713 }
5714 }
5715 break;
thse5febef2007-04-01 18:31:35 +00005716#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005717 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005718 if (!(p = lock_user_string(arg1)))
5719 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005720 ret = get_errno(umount(p));
5721 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005722 break;
thse5febef2007-04-01 18:31:35 +00005723#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005724#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005725 case TARGET_NR_stime:
5726 {
pbrook53a59602006-03-25 19:31:22 +00005727 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005728 if (get_user_sal(host_time, arg1))
5729 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005730 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005731 }
5732 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005733#endif
bellard31e31b82003-02-18 22:55:36 +00005734 case TARGET_NR_ptrace:
5735 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005736#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005737 case TARGET_NR_alarm:
5738 ret = alarm(arg1);
5739 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005740#endif
bellardebc05482003-09-30 21:08:41 +00005741#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005742 case TARGET_NR_oldfstat:
5743 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005744#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005745#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005746 case TARGET_NR_pause:
5747 ret = get_errno(pause());
5748 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005749#endif
thse5febef2007-04-01 18:31:35 +00005750#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005751 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005752 {
pbrook53a59602006-03-25 19:31:22 +00005753 struct utimbuf tbuf, *host_tbuf;
5754 struct target_utimbuf *target_tbuf;
5755 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005756 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5757 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005758 tbuf.actime = tswapal(target_tbuf->actime);
5759 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005760 unlock_user_struct(target_tbuf, arg2, 0);
5761 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005762 } else {
pbrook53a59602006-03-25 19:31:22 +00005763 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005764 }
bellard579a97f2007-11-11 14:26:47 +00005765 if (!(p = lock_user_string(arg1)))
5766 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005767 ret = get_errno(utime(p, host_tbuf));
5768 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005769 }
5770 break;
thse5febef2007-04-01 18:31:35 +00005771#endif
bellard978a66f2004-12-06 22:58:05 +00005772 case TARGET_NR_utimes:
5773 {
bellard978a66f2004-12-06 22:58:05 +00005774 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005775 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005776 if (copy_from_user_timeval(&tv[0], arg2)
5777 || copy_from_user_timeval(&tv[1],
5778 arg2 + sizeof(struct target_timeval)))
5779 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005780 tvp = tv;
5781 } else {
5782 tvp = NULL;
5783 }
bellard579a97f2007-11-11 14:26:47 +00005784 if (!(p = lock_user_string(arg1)))
5785 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005786 ret = get_errno(utimes(p, tvp));
5787 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005788 }
5789 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005790#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005791 case TARGET_NR_futimesat:
5792 {
5793 struct timeval *tvp, tv[2];
5794 if (arg3) {
5795 if (copy_from_user_timeval(&tv[0], arg3)
5796 || copy_from_user_timeval(&tv[1],
5797 arg3 + sizeof(struct target_timeval)))
5798 goto efault;
5799 tvp = tv;
5800 } else {
5801 tvp = NULL;
5802 }
5803 if (!(p = lock_user_string(arg2)))
5804 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005805 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005806 unlock_user(p, arg2, 0);
5807 }
5808 break;
5809#endif
bellardebc05482003-09-30 21:08:41 +00005810#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005811 case TARGET_NR_stty:
5812 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005813#endif
5814#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005815 case TARGET_NR_gtty:
5816 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005817#endif
bellard31e31b82003-02-18 22:55:36 +00005818 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005819 if (!(p = lock_user_string(arg1)))
5820 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005821 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005822 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005823 break;
ths92a34c12007-09-24 09:27:49 +00005824#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5825 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005826 if (!(p = lock_user_string(arg2)))
5827 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005828 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005829 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005830 break;
5831#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005832#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005833 case TARGET_NR_nice:
5834 ret = get_errno(nice(arg1));
5835 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005836#endif
bellardebc05482003-09-30 21:08:41 +00005837#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005838 case TARGET_NR_ftime:
5839 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005840#endif
bellard31e31b82003-02-18 22:55:36 +00005841 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005842 sync();
5843 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005844 break;
5845 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005846 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005847 break;
5848 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005849 {
5850 void *p2;
5851 p = lock_user_string(arg1);
5852 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005853 if (!p || !p2)
5854 ret = -TARGET_EFAULT;
5855 else
5856 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005857 unlock_user(p2, arg2, 0);
5858 unlock_user(p, arg1, 0);
5859 }
bellard31e31b82003-02-18 22:55:36 +00005860 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005861#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005862 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005863 {
bellard579a97f2007-11-11 14:26:47 +00005864 void *p2;
ths722183f2007-09-24 09:24:37 +00005865 p = lock_user_string(arg2);
5866 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005867 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005868 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005869 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005870 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005871 unlock_user(p2, arg4, 0);
5872 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005873 }
5874 break;
5875#endif
bellard31e31b82003-02-18 22:55:36 +00005876 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005877 if (!(p = lock_user_string(arg1)))
5878 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005879 ret = get_errno(mkdir(p, arg2));
5880 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005881 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005882#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005883 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005884 if (!(p = lock_user_string(arg2)))
5885 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005886 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005887 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005888 break;
5889#endif
bellard31e31b82003-02-18 22:55:36 +00005890 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005891 if (!(p = lock_user_string(arg1)))
5892 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005893 ret = get_errno(rmdir(p));
5894 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005895 break;
5896 case TARGET_NR_dup:
5897 ret = get_errno(dup(arg1));
5898 break;
5899 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005900 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005901 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005902#ifdef TARGET_NR_pipe2
5903 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005904 ret = do_pipe(cpu_env, arg1,
5905 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005906 break;
5907#endif
bellard31e31b82003-02-18 22:55:36 +00005908 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005909 {
pbrook53a59602006-03-25 19:31:22 +00005910 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005911 struct tms tms;
5912 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005913 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005914 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5915 if (!tmsp)
5916 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005917 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5918 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5919 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5920 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005921 }
bellardc596ed12003-07-13 17:32:31 +00005922 if (!is_error(ret))
5923 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005924 }
5925 break;
bellardebc05482003-09-30 21:08:41 +00005926#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005927 case TARGET_NR_prof:
5928 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005929#endif
thse5febef2007-04-01 18:31:35 +00005930#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005931 case TARGET_NR_signal:
5932 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005933#endif
bellard31e31b82003-02-18 22:55:36 +00005934 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005935 if (arg1 == 0) {
5936 ret = get_errno(acct(NULL));
5937 } else {
5938 if (!(p = lock_user_string(arg1)))
5939 goto efault;
5940 ret = get_errno(acct(path(p)));
5941 unlock_user(p, arg1, 0);
5942 }
pbrook24836682006-04-16 14:14:53 +00005943 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005944#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005945 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005946 if (!(p = lock_user_string(arg1)))
5947 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005948 ret = get_errno(umount2(p, arg2));
5949 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005950 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005951#endif
bellardebc05482003-09-30 21:08:41 +00005952#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005953 case TARGET_NR_lock:
5954 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005955#endif
bellard31e31b82003-02-18 22:55:36 +00005956 case TARGET_NR_ioctl:
5957 ret = do_ioctl(arg1, arg2, arg3);
5958 break;
5959 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005960 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005961 break;
bellardebc05482003-09-30 21:08:41 +00005962#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005963 case TARGET_NR_mpx:
5964 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005965#endif
bellard31e31b82003-02-18 22:55:36 +00005966 case TARGET_NR_setpgid:
5967 ret = get_errno(setpgid(arg1, arg2));
5968 break;
bellardebc05482003-09-30 21:08:41 +00005969#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005970 case TARGET_NR_ulimit:
5971 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005972#endif
5973#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005974 case TARGET_NR_oldolduname:
5975 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005976#endif
bellard31e31b82003-02-18 22:55:36 +00005977 case TARGET_NR_umask:
5978 ret = get_errno(umask(arg1));
5979 break;
5980 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005981 if (!(p = lock_user_string(arg1)))
5982 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005983 ret = get_errno(chroot(p));
5984 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005985 break;
5986 case TARGET_NR_ustat:
5987 goto unimplemented;
5988 case TARGET_NR_dup2:
5989 ret = get_errno(dup2(arg1, arg2));
5990 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005991#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5992 case TARGET_NR_dup3:
5993 ret = get_errno(dup3(arg1, arg2, arg3));
5994 break;
5995#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005996#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005997 case TARGET_NR_getppid:
5998 ret = get_errno(getppid());
5999 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006000#endif
bellard31e31b82003-02-18 22:55:36 +00006001 case TARGET_NR_getpgrp:
6002 ret = get_errno(getpgrp());
6003 break;
6004 case TARGET_NR_setsid:
6005 ret = get_errno(setsid());
6006 break;
thse5febef2007-04-01 18:31:35 +00006007#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006008 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006009 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006010#if defined(TARGET_ALPHA)
6011 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006012 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006013 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006014 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6015 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006016 act._sa_handler = old_act->_sa_handler;
6017 target_siginitset(&act.sa_mask, old_act->sa_mask);
6018 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006019 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006020 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006021 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006022 }
6023 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006024 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006025 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6026 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006027 old_act->_sa_handler = oact._sa_handler;
6028 old_act->sa_mask = oact.sa_mask.sig[0];
6029 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006030 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006031 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006032#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006033 struct target_sigaction act, oact, *pact, *old_act;
6034
6035 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006036 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6037 goto efault;
bellard106ec872006-06-27 21:08:10 +00006038 act._sa_handler = old_act->_sa_handler;
6039 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6040 act.sa_flags = old_act->sa_flags;
6041 unlock_user_struct(old_act, arg2, 0);
6042 pact = &act;
6043 } else {
6044 pact = NULL;
6045 }
6046
6047 ret = get_errno(do_sigaction(arg1, pact, &oact));
6048
6049 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006050 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6051 goto efault;
bellard106ec872006-06-27 21:08:10 +00006052 old_act->_sa_handler = oact._sa_handler;
6053 old_act->sa_flags = oact.sa_flags;
6054 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6055 old_act->sa_mask.sig[1] = 0;
6056 old_act->sa_mask.sig[2] = 0;
6057 old_act->sa_mask.sig[3] = 0;
6058 unlock_user_struct(old_act, arg3, 1);
6059 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006060#else
6061 struct target_old_sigaction *old_act;
6062 struct target_sigaction act, oact, *pact;
6063 if (arg2) {
6064 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6065 goto efault;
6066 act._sa_handler = old_act->_sa_handler;
6067 target_siginitset(&act.sa_mask, old_act->sa_mask);
6068 act.sa_flags = old_act->sa_flags;
6069 act.sa_restorer = old_act->sa_restorer;
6070 unlock_user_struct(old_act, arg2, 0);
6071 pact = &act;
6072 } else {
6073 pact = NULL;
6074 }
6075 ret = get_errno(do_sigaction(arg1, pact, &oact));
6076 if (!is_error(ret) && arg3) {
6077 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6078 goto efault;
6079 old_act->_sa_handler = oact._sa_handler;
6080 old_act->sa_mask = oact.sa_mask.sig[0];
6081 old_act->sa_flags = oact.sa_flags;
6082 old_act->sa_restorer = oact.sa_restorer;
6083 unlock_user_struct(old_act, arg3, 1);
6084 }
ths388bb212007-05-13 13:58:00 +00006085#endif
bellard31e31b82003-02-18 22:55:36 +00006086 }
6087 break;
thse5febef2007-04-01 18:31:35 +00006088#endif
bellard66fb9762003-03-23 01:06:05 +00006089 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006090 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006091#if defined(TARGET_ALPHA)
6092 struct target_sigaction act, oact, *pact = 0;
6093 struct target_rt_sigaction *rt_act;
6094 /* ??? arg4 == sizeof(sigset_t). */
6095 if (arg2) {
6096 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6097 goto efault;
6098 act._sa_handler = rt_act->_sa_handler;
6099 act.sa_mask = rt_act->sa_mask;
6100 act.sa_flags = rt_act->sa_flags;
6101 act.sa_restorer = arg5;
6102 unlock_user_struct(rt_act, arg2, 0);
6103 pact = &act;
6104 }
6105 ret = get_errno(do_sigaction(arg1, pact, &oact));
6106 if (!is_error(ret) && arg3) {
6107 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6108 goto efault;
6109 rt_act->_sa_handler = oact._sa_handler;
6110 rt_act->sa_mask = oact.sa_mask;
6111 rt_act->sa_flags = oact.sa_flags;
6112 unlock_user_struct(rt_act, arg3, 1);
6113 }
6114#else
pbrook53a59602006-03-25 19:31:22 +00006115 struct target_sigaction *act;
6116 struct target_sigaction *oact;
6117
bellard579a97f2007-11-11 14:26:47 +00006118 if (arg2) {
6119 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6120 goto efault;
6121 } else
pbrook53a59602006-03-25 19:31:22 +00006122 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006123 if (arg3) {
6124 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6125 ret = -TARGET_EFAULT;
6126 goto rt_sigaction_fail;
6127 }
6128 } else
pbrook53a59602006-03-25 19:31:22 +00006129 oact = NULL;
6130 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006131 rt_sigaction_fail:
6132 if (act)
pbrook53a59602006-03-25 19:31:22 +00006133 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006134 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006135 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006136#endif
pbrook53a59602006-03-25 19:31:22 +00006137 }
bellard66fb9762003-03-23 01:06:05 +00006138 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006139#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006140 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006141 {
6142 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006143 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006144 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006145 host_to_target_old_sigset(&target_set, &cur_set);
6146 ret = target_set;
6147 }
6148 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006149#endif
6150#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006151 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006152 {
6153 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006154 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006155 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006156 target_to_host_old_sigset(&set, &target_set);
6157 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006158 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006159 host_to_target_old_sigset(&target_set, &oset);
6160 ret = target_set;
6161 }
6162 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006163#endif
thse5febef2007-04-01 18:31:35 +00006164#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006165 case TARGET_NR_sigprocmask:
6166 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006167#if defined(TARGET_ALPHA)
6168 sigset_t set, oldset;
6169 abi_ulong mask;
6170 int how;
6171
6172 switch (arg1) {
6173 case TARGET_SIG_BLOCK:
6174 how = SIG_BLOCK;
6175 break;
6176 case TARGET_SIG_UNBLOCK:
6177 how = SIG_UNBLOCK;
6178 break;
6179 case TARGET_SIG_SETMASK:
6180 how = SIG_SETMASK;
6181 break;
6182 default:
6183 ret = -TARGET_EINVAL;
6184 goto fail;
6185 }
6186 mask = arg2;
6187 target_to_host_old_sigset(&set, &mask);
6188
Alex Barcelo1c275922014-03-14 14:36:55 +00006189 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006190 if (!is_error(ret)) {
6191 host_to_target_old_sigset(&mask, &oldset);
6192 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006193 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006194 }
6195#else
bellard66fb9762003-03-23 01:06:05 +00006196 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006197 int how;
ths3b46e622007-09-17 08:09:54 +00006198
pbrook53a59602006-03-25 19:31:22 +00006199 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006200 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006201 case TARGET_SIG_BLOCK:
6202 how = SIG_BLOCK;
6203 break;
6204 case TARGET_SIG_UNBLOCK:
6205 how = SIG_UNBLOCK;
6206 break;
6207 case TARGET_SIG_SETMASK:
6208 how = SIG_SETMASK;
6209 break;
6210 default:
ths0da46a62007-10-20 20:23:07 +00006211 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006212 goto fail;
6213 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006214 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006215 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006216 target_to_host_old_sigset(&set, p);
6217 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006218 set_ptr = &set;
6219 } else {
6220 how = 0;
6221 set_ptr = NULL;
6222 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006223 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006224 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006225 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006226 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006227 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006228 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006229 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006230#endif
bellard66fb9762003-03-23 01:06:05 +00006231 }
6232 break;
thse5febef2007-04-01 18:31:35 +00006233#endif
bellard66fb9762003-03-23 01:06:05 +00006234 case TARGET_NR_rt_sigprocmask:
6235 {
6236 int how = arg1;
6237 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006238
pbrook53a59602006-03-25 19:31:22 +00006239 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006240 switch(how) {
6241 case TARGET_SIG_BLOCK:
6242 how = SIG_BLOCK;
6243 break;
6244 case TARGET_SIG_UNBLOCK:
6245 how = SIG_UNBLOCK;
6246 break;
6247 case TARGET_SIG_SETMASK:
6248 how = SIG_SETMASK;
6249 break;
6250 default:
ths0da46a62007-10-20 20:23:07 +00006251 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006252 goto fail;
6253 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006254 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006255 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006256 target_to_host_sigset(&set, p);
6257 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006258 set_ptr = &set;
6259 } else {
6260 how = 0;
6261 set_ptr = NULL;
6262 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006263 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006264 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006265 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006266 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006267 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006268 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006269 }
6270 }
6271 break;
thse5febef2007-04-01 18:31:35 +00006272#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006273 case TARGET_NR_sigpending:
6274 {
6275 sigset_t set;
6276 ret = get_errno(sigpending(&set));
6277 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006278 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006279 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006280 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006281 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006282 }
6283 }
6284 break;
thse5febef2007-04-01 18:31:35 +00006285#endif
bellard66fb9762003-03-23 01:06:05 +00006286 case TARGET_NR_rt_sigpending:
6287 {
6288 sigset_t set;
6289 ret = get_errno(sigpending(&set));
6290 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006291 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006292 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006293 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006294 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006295 }
6296 }
6297 break;
thse5febef2007-04-01 18:31:35 +00006298#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006299 case TARGET_NR_sigsuspend:
6300 {
6301 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006302#if defined(TARGET_ALPHA)
6303 abi_ulong mask = arg1;
6304 target_to_host_old_sigset(&set, &mask);
6305#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006306 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006307 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006308 target_to_host_old_sigset(&set, p);
6309 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006310#endif
bellard66fb9762003-03-23 01:06:05 +00006311 ret = get_errno(sigsuspend(&set));
6312 }
6313 break;
thse5febef2007-04-01 18:31:35 +00006314#endif
bellard66fb9762003-03-23 01:06:05 +00006315 case TARGET_NR_rt_sigsuspend:
6316 {
6317 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006318 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006319 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006320 target_to_host_sigset(&set, p);
6321 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006322 ret = get_errno(sigsuspend(&set));
6323 }
6324 break;
6325 case TARGET_NR_rt_sigtimedwait:
6326 {
bellard66fb9762003-03-23 01:06:05 +00006327 sigset_t set;
6328 struct timespec uts, *puts;
6329 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006330
Anthony Liguoric227f092009-10-01 16:12:16 -05006331 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006332 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006333 target_to_host_sigset(&set, p);
6334 unlock_user(p, arg1, 0);
6335 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006336 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006337 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006338 } else {
6339 puts = NULL;
6340 }
6341 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006342 if (!is_error(ret)) {
6343 if (arg2) {
6344 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6345 0);
6346 if (!p) {
6347 goto efault;
6348 }
6349 host_to_target_siginfo(p, &uinfo);
6350 unlock_user(p, arg2, sizeof(target_siginfo_t));
6351 }
6352 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006353 }
6354 }
6355 break;
6356 case TARGET_NR_rt_sigqueueinfo:
6357 {
6358 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006359 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006360 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006361 target_to_host_siginfo(&uinfo, p);
6362 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006363 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6364 }
6365 break;
thse5febef2007-04-01 18:31:35 +00006366#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006367 case TARGET_NR_sigreturn:
6368 /* NOTE: ret is eax, so not transcoding must be done */
6369 ret = do_sigreturn(cpu_env);
6370 break;
thse5febef2007-04-01 18:31:35 +00006371#endif
bellard66fb9762003-03-23 01:06:05 +00006372 case TARGET_NR_rt_sigreturn:
6373 /* NOTE: ret is eax, so not transcoding must be done */
6374 ret = do_rt_sigreturn(cpu_env);
6375 break;
bellard31e31b82003-02-18 22:55:36 +00006376 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006377 if (!(p = lock_user_string(arg1)))
6378 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006379 ret = get_errno(sethostname(p, arg2));
6380 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006381 break;
6382 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006383 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006384 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006385 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006386 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006387 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6388 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006389 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6390 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006391 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006392 ret = get_errno(setrlimit(resource, &rlim));
6393 }
6394 break;
bellard31e31b82003-02-18 22:55:36 +00006395 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006396 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006397 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006398 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006399 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006400
bellard9de5e442003-03-23 16:49:39 +00006401 ret = get_errno(getrlimit(resource, &rlim));
6402 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006403 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6404 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006405 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6406 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006407 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006408 }
6409 }
6410 break;
bellard31e31b82003-02-18 22:55:36 +00006411 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006412 {
6413 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006414 ret = get_errno(getrusage(arg1, &rusage));
6415 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006416 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006417 }
6418 }
6419 break;
bellard31e31b82003-02-18 22:55:36 +00006420 case TARGET_NR_gettimeofday:
6421 {
bellard31e31b82003-02-18 22:55:36 +00006422 struct timeval tv;
6423 ret = get_errno(gettimeofday(&tv, NULL));
6424 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006425 if (copy_to_user_timeval(arg1, &tv))
6426 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006427 }
6428 }
6429 break;
6430 case TARGET_NR_settimeofday:
6431 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006432 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006433 struct timezone tz, *ptz = NULL;
6434
Paul Burtonb67d8032014-06-22 11:25:41 +01006435 if (arg1) {
6436 if (copy_from_user_timeval(&tv, arg1)) {
6437 goto efault;
6438 }
6439 ptv = &tv;
6440 }
Paul Burtonef4467e2014-06-22 11:25:40 +01006441
6442 if (arg2) {
6443 if (copy_from_user_timezone(&tz, arg2)) {
6444 goto efault;
6445 }
6446 ptz = &tz;
6447 }
6448
Paul Burtonb67d8032014-06-22 11:25:41 +01006449 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00006450 }
6451 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006452#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006453 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006454#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6455 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6456#else
bellardf2674e32003-07-09 12:26:09 +00006457 {
pbrook53a59602006-03-25 19:31:22 +00006458 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006459 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006460 long nsel;
6461
bellard579a97f2007-11-11 14:26:47 +00006462 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6463 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006464 nsel = tswapal(sel->n);
6465 inp = tswapal(sel->inp);
6466 outp = tswapal(sel->outp);
6467 exp = tswapal(sel->exp);
6468 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006469 unlock_user_struct(sel, arg1, 0);
6470 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006471 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006472#endif
bellardf2674e32003-07-09 12:26:09 +00006473 break;
bellard048f6b42005-11-26 18:47:20 +00006474#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006475#ifdef TARGET_NR_pselect6
6476 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006477 {
6478 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6479 fd_set rfds, wfds, efds;
6480 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6481 struct timespec ts, *ts_ptr;
6482
6483 /*
6484 * The 6th arg is actually two args smashed together,
6485 * so we cannot use the C library.
6486 */
6487 sigset_t set;
6488 struct {
6489 sigset_t *set;
6490 size_t size;
6491 } sig, *sig_ptr;
6492
6493 abi_ulong arg_sigset, arg_sigsize, *arg7;
6494 target_sigset_t *target_sigset;
6495
6496 n = arg1;
6497 rfd_addr = arg2;
6498 wfd_addr = arg3;
6499 efd_addr = arg4;
6500 ts_addr = arg5;
6501
6502 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6503 if (ret) {
6504 goto fail;
6505 }
6506 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6507 if (ret) {
6508 goto fail;
6509 }
6510 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6511 if (ret) {
6512 goto fail;
6513 }
6514
6515 /*
6516 * This takes a timespec, and not a timeval, so we cannot
6517 * use the do_select() helper ...
6518 */
6519 if (ts_addr) {
6520 if (target_to_host_timespec(&ts, ts_addr)) {
6521 goto efault;
6522 }
6523 ts_ptr = &ts;
6524 } else {
6525 ts_ptr = NULL;
6526 }
6527
6528 /* Extract the two packed args for the sigset */
6529 if (arg6) {
6530 sig_ptr = &sig;
6531 sig.size = _NSIG / 8;
6532
6533 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6534 if (!arg7) {
6535 goto efault;
6536 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006537 arg_sigset = tswapal(arg7[0]);
6538 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006539 unlock_user(arg7, arg6, 0);
6540
6541 if (arg_sigset) {
6542 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006543 if (arg_sigsize != sizeof(*target_sigset)) {
6544 /* Like the kernel, we enforce correct size sigsets */
6545 ret = -TARGET_EINVAL;
6546 goto fail;
6547 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006548 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6549 sizeof(*target_sigset), 1);
6550 if (!target_sigset) {
6551 goto efault;
6552 }
6553 target_to_host_sigset(&set, target_sigset);
6554 unlock_user(target_sigset, arg_sigset, 0);
6555 } else {
6556 sig.set = NULL;
6557 }
6558 } else {
6559 sig_ptr = NULL;
6560 }
6561
6562 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6563 ts_ptr, sig_ptr));
6564
6565 if (!is_error(ret)) {
6566 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6567 goto efault;
6568 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6569 goto efault;
6570 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6571 goto efault;
6572
6573 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6574 goto efault;
6575 }
6576 }
6577 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006578#endif
bellard31e31b82003-02-18 22:55:36 +00006579 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006580 {
6581 void *p2;
6582 p = lock_user_string(arg1);
6583 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006584 if (!p || !p2)
6585 ret = -TARGET_EFAULT;
6586 else
6587 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006588 unlock_user(p2, arg2, 0);
6589 unlock_user(p, arg1, 0);
6590 }
bellard31e31b82003-02-18 22:55:36 +00006591 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006592#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006593 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006594 {
bellard579a97f2007-11-11 14:26:47 +00006595 void *p2;
thsf0b62432007-09-24 09:25:40 +00006596 p = lock_user_string(arg1);
6597 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006598 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006599 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006600 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006601 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006602 unlock_user(p2, arg3, 0);
6603 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006604 }
6605 break;
6606#endif
bellardebc05482003-09-30 21:08:41 +00006607#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006608 case TARGET_NR_oldlstat:
6609 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006610#endif
bellard31e31b82003-02-18 22:55:36 +00006611 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006612 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006613 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006614 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006615 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006616 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006617 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006618 } else if (is_proc_myself((const char *)p, "exe")) {
6619 char real[PATH_MAX], *temp;
6620 temp = realpath(exec_path, real);
6621 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6622 snprintf((char *)p2, arg3, "%s", real);
6623 } else {
6624 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006625 }
pbrook53a59602006-03-25 19:31:22 +00006626 unlock_user(p2, arg2, ret);
6627 unlock_user(p, arg1, 0);
6628 }
bellard31e31b82003-02-18 22:55:36 +00006629 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006630#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006631 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006632 {
bellard579a97f2007-11-11 14:26:47 +00006633 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006634 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006635 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006636 if (!p || !p2) {
6637 ret = -TARGET_EFAULT;
6638 } else if (is_proc_myself((const char *)p, "exe")) {
6639 char real[PATH_MAX], *temp;
6640 temp = realpath(exec_path, real);
6641 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6642 snprintf((char *)p2, arg4, "%s", real);
6643 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006644 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006645 }
bellard579a97f2007-11-11 14:26:47 +00006646 unlock_user(p2, arg3, ret);
6647 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006648 }
6649 break;
6650#endif
thse5febef2007-04-01 18:31:35 +00006651#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006652 case TARGET_NR_uselib:
6653 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006654#endif
6655#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006656 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006657 if (!(p = lock_user_string(arg1)))
6658 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006659 ret = get_errno(swapon(p, arg2));
6660 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006661 break;
thse5febef2007-04-01 18:31:35 +00006662#endif
bellard31e31b82003-02-18 22:55:36 +00006663 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006664 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6665 /* arg4 must be ignored in all other cases */
6666 p = lock_user_string(arg4);
6667 if (!p) {
6668 goto efault;
6669 }
6670 ret = get_errno(reboot(arg1, arg2, arg3, p));
6671 unlock_user(p, arg4, 0);
6672 } else {
6673 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6674 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006675 break;
thse5febef2007-04-01 18:31:35 +00006676#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006677 case TARGET_NR_readdir:
6678 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006679#endif
6680#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006681 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006682#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6683 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006684 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6685 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006686 {
blueswir1992f48a2007-10-14 16:27:31 +00006687 abi_ulong *v;
6688 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006689 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6690 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006691 v1 = tswapal(v[0]);
6692 v2 = tswapal(v[1]);
6693 v3 = tswapal(v[2]);
6694 v4 = tswapal(v[3]);
6695 v5 = tswapal(v[4]);
6696 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006697 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006698 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006699 target_to_host_bitmask(v4, mmap_flags_tbl),
6700 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006701 }
bellard31e31b82003-02-18 22:55:36 +00006702#else
ths5fafdf22007-09-16 21:08:06 +00006703 ret = get_errno(target_mmap(arg1, arg2, arg3,
6704 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006705 arg5,
6706 arg6));
bellard31e31b82003-02-18 22:55:36 +00006707#endif
bellard6fb883e2003-07-09 17:12:39 +00006708 break;
thse5febef2007-04-01 18:31:35 +00006709#endif
bellarda315a142005-01-30 22:59:18 +00006710#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006711 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006712#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006713#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006714#endif
ths5fafdf22007-09-16 21:08:06 +00006715 ret = get_errno(target_mmap(arg1, arg2, arg3,
6716 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006717 arg5,
bellardc573ff62004-01-04 15:51:36 +00006718 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006719 break;
bellarda315a142005-01-30 22:59:18 +00006720#endif
bellard31e31b82003-02-18 22:55:36 +00006721 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006722 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006723 break;
bellard9de5e442003-03-23 16:49:39 +00006724 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006725 {
Andreas Färber0429a972013-08-26 18:14:44 +02006726 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006727 /* Special hack to detect libc making the stack executable. */
6728 if ((arg3 & PROT_GROWSDOWN)
6729 && arg1 >= ts->info->stack_limit
6730 && arg1 <= ts->info->start_stack) {
6731 arg3 &= ~PROT_GROWSDOWN;
6732 arg2 = arg2 + arg1 - ts->info->stack_limit;
6733 arg1 = ts->info->stack_limit;
6734 }
6735 }
bellard54936002003-05-13 00:25:15 +00006736 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006737 break;
thse5febef2007-04-01 18:31:35 +00006738#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006739 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006740 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006741 break;
thse5febef2007-04-01 18:31:35 +00006742#endif
pbrook53a59602006-03-25 19:31:22 +00006743 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006744#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006745 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006746 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006747 break;
thse5febef2007-04-01 18:31:35 +00006748#endif
6749#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006750 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006751 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006752 break;
thse5febef2007-04-01 18:31:35 +00006753#endif
6754#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006755 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006756 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006757 break;
thse5febef2007-04-01 18:31:35 +00006758#endif
6759#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006760 case TARGET_NR_mlockall:
6761 ret = get_errno(mlockall(arg1));
6762 break;
thse5febef2007-04-01 18:31:35 +00006763#endif
6764#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006765 case TARGET_NR_munlockall:
6766 ret = get_errno(munlockall());
6767 break;
thse5febef2007-04-01 18:31:35 +00006768#endif
bellard31e31b82003-02-18 22:55:36 +00006769 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006770 if (!(p = lock_user_string(arg1)))
6771 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006772 ret = get_errno(truncate(p, arg2));
6773 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006774 break;
6775 case TARGET_NR_ftruncate:
6776 ret = get_errno(ftruncate(arg1, arg2));
6777 break;
6778 case TARGET_NR_fchmod:
6779 ret = get_errno(fchmod(arg1, arg2));
6780 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006781#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006782 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006783 if (!(p = lock_user_string(arg2)))
6784 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006785 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006786 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006787 break;
6788#endif
bellard31e31b82003-02-18 22:55:36 +00006789 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006790 /* Note that negative values are valid for getpriority, so we must
6791 differentiate based on errno settings. */
6792 errno = 0;
6793 ret = getpriority(arg1, arg2);
6794 if (ret == -1 && errno != 0) {
6795 ret = -host_to_target_errno(errno);
6796 break;
6797 }
6798#ifdef TARGET_ALPHA
6799 /* Return value is the unbiased priority. Signal no error. */
6800 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6801#else
6802 /* Return value is a biased priority to avoid negative numbers. */
6803 ret = 20 - ret;
6804#endif
bellard31e31b82003-02-18 22:55:36 +00006805 break;
6806 case TARGET_NR_setpriority:
6807 ret = get_errno(setpriority(arg1, arg2, arg3));
6808 break;
bellardebc05482003-09-30 21:08:41 +00006809#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006810 case TARGET_NR_profil:
6811 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006812#endif
bellard31e31b82003-02-18 22:55:36 +00006813 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006814 if (!(p = lock_user_string(arg1)))
6815 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006816 ret = get_errno(statfs(path(p), &stfs));
6817 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006818 convert_statfs:
6819 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006820 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006821
bellard579a97f2007-11-11 14:26:47 +00006822 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6823 goto efault;
6824 __put_user(stfs.f_type, &target_stfs->f_type);
6825 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6826 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6827 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6828 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6829 __put_user(stfs.f_files, &target_stfs->f_files);
6830 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6831 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6832 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6833 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006834 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6835 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006836 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006837 }
6838 break;
6839 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006840 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006841 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006842#ifdef TARGET_NR_statfs64
6843 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006844 if (!(p = lock_user_string(arg1)))
6845 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006846 ret = get_errno(statfs(path(p), &stfs));
6847 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006848 convert_statfs64:
6849 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006850 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006851
bellard579a97f2007-11-11 14:26:47 +00006852 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6853 goto efault;
6854 __put_user(stfs.f_type, &target_stfs->f_type);
6855 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6856 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6857 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6858 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6859 __put_user(stfs.f_files, &target_stfs->f_files);
6860 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6861 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6862 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6863 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006864 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6865 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006866 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006867 }
6868 break;
6869 case TARGET_NR_fstatfs64:
6870 ret = get_errno(fstatfs(arg1, &stfs));
6871 goto convert_statfs64;
6872#endif
bellardebc05482003-09-30 21:08:41 +00006873#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006874 case TARGET_NR_ioperm:
6875 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006876#endif
thse5febef2007-04-01 18:31:35 +00006877#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006878 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006879 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006880 break;
thse5febef2007-04-01 18:31:35 +00006881#endif
bellard3532fa72006-06-24 15:06:03 +00006882#ifdef TARGET_NR_accept
6883 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006884 ret = do_accept4(arg1, arg2, arg3, 0);
6885 break;
6886#endif
6887#ifdef TARGET_NR_accept4
6888 case TARGET_NR_accept4:
6889#ifdef CONFIG_ACCEPT4
6890 ret = do_accept4(arg1, arg2, arg3, arg4);
6891#else
6892 goto unimplemented;
6893#endif
bellard3532fa72006-06-24 15:06:03 +00006894 break;
6895#endif
6896#ifdef TARGET_NR_bind
6897 case TARGET_NR_bind:
6898 ret = do_bind(arg1, arg2, arg3);
6899 break;
6900#endif
6901#ifdef TARGET_NR_connect
6902 case TARGET_NR_connect:
6903 ret = do_connect(arg1, arg2, arg3);
6904 break;
6905#endif
6906#ifdef TARGET_NR_getpeername
6907 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006908 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006909 break;
6910#endif
6911#ifdef TARGET_NR_getsockname
6912 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006913 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006914 break;
6915#endif
6916#ifdef TARGET_NR_getsockopt
6917 case TARGET_NR_getsockopt:
6918 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6919 break;
6920#endif
6921#ifdef TARGET_NR_listen
6922 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006923 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006924 break;
6925#endif
6926#ifdef TARGET_NR_recv
6927 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006928 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006929 break;
6930#endif
6931#ifdef TARGET_NR_recvfrom
6932 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006933 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006934 break;
6935#endif
6936#ifdef TARGET_NR_recvmsg
6937 case TARGET_NR_recvmsg:
6938 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6939 break;
6940#endif
6941#ifdef TARGET_NR_send
6942 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006943 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006944 break;
6945#endif
6946#ifdef TARGET_NR_sendmsg
6947 case TARGET_NR_sendmsg:
6948 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6949 break;
6950#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006951#ifdef TARGET_NR_sendmmsg
6952 case TARGET_NR_sendmmsg:
6953 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6954 break;
6955 case TARGET_NR_recvmmsg:
6956 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6957 break;
6958#endif
bellard3532fa72006-06-24 15:06:03 +00006959#ifdef TARGET_NR_sendto
6960 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006961 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006962 break;
6963#endif
6964#ifdef TARGET_NR_shutdown
6965 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006966 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006967 break;
6968#endif
6969#ifdef TARGET_NR_socket
6970 case TARGET_NR_socket:
6971 ret = do_socket(arg1, arg2, arg3);
6972 break;
6973#endif
6974#ifdef TARGET_NR_socketpair
6975 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006976 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006977 break;
6978#endif
6979#ifdef TARGET_NR_setsockopt
6980 case TARGET_NR_setsockopt:
6981 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6982 break;
6983#endif
ths7494b0f2007-02-11 18:26:53 +00006984
bellard31e31b82003-02-18 22:55:36 +00006985 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006986 if (!(p = lock_user_string(arg2)))
6987 goto efault;
thse5574482007-02-11 20:03:13 +00006988 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6989 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006990 break;
6991
bellard31e31b82003-02-18 22:55:36 +00006992 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006993 {
bellard66fb9762003-03-23 01:06:05 +00006994 struct itimerval value, ovalue, *pvalue;
6995
pbrook53a59602006-03-25 19:31:22 +00006996 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006997 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006998 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6999 || copy_from_user_timeval(&pvalue->it_value,
7000 arg2 + sizeof(struct target_timeval)))
7001 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007002 } else {
7003 pvalue = NULL;
7004 }
7005 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007006 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007007 if (copy_to_user_timeval(arg3,
7008 &ovalue.it_interval)
7009 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7010 &ovalue.it_value))
7011 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007012 }
7013 }
7014 break;
bellard31e31b82003-02-18 22:55:36 +00007015 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007016 {
bellard66fb9762003-03-23 01:06:05 +00007017 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007018
bellard66fb9762003-03-23 01:06:05 +00007019 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007020 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007021 if (copy_to_user_timeval(arg2,
7022 &value.it_interval)
7023 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7024 &value.it_value))
7025 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007026 }
7027 }
7028 break;
bellard31e31b82003-02-18 22:55:36 +00007029 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007030 if (!(p = lock_user_string(arg1)))
7031 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007032 ret = get_errno(stat(path(p), &st));
7033 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007034 goto do_stat;
7035 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007036 if (!(p = lock_user_string(arg1)))
7037 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007038 ret = get_errno(lstat(path(p), &st));
7039 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007040 goto do_stat;
7041 case TARGET_NR_fstat:
7042 {
7043 ret = get_errno(fstat(arg1, &st));
7044 do_stat:
7045 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007046 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007047
bellard579a97f2007-11-11 14:26:47 +00007048 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7049 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007050 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007051 __put_user(st.st_dev, &target_st->st_dev);
7052 __put_user(st.st_ino, &target_st->st_ino);
7053 __put_user(st.st_mode, &target_st->st_mode);
7054 __put_user(st.st_uid, &target_st->st_uid);
7055 __put_user(st.st_gid, &target_st->st_gid);
7056 __put_user(st.st_nlink, &target_st->st_nlink);
7057 __put_user(st.st_rdev, &target_st->st_rdev);
7058 __put_user(st.st_size, &target_st->st_size);
7059 __put_user(st.st_blksize, &target_st->st_blksize);
7060 __put_user(st.st_blocks, &target_st->st_blocks);
7061 __put_user(st.st_atime, &target_st->target_st_atime);
7062 __put_user(st.st_mtime, &target_st->target_st_mtime);
7063 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007064 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007065 }
7066 }
7067 break;
bellardebc05482003-09-30 21:08:41 +00007068#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007069 case TARGET_NR_olduname:
7070 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007071#endif
7072#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007073 case TARGET_NR_iopl:
7074 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007075#endif
bellard31e31b82003-02-18 22:55:36 +00007076 case TARGET_NR_vhangup:
7077 ret = get_errno(vhangup());
7078 break;
bellardebc05482003-09-30 21:08:41 +00007079#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007080 case TARGET_NR_idle:
7081 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007082#endif
bellard42ad6ae2005-01-03 22:48:11 +00007083#ifdef TARGET_NR_syscall
7084 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007085 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7086 arg6, arg7, arg8, 0);
7087 break;
bellard42ad6ae2005-01-03 22:48:11 +00007088#endif
bellard31e31b82003-02-18 22:55:36 +00007089 case TARGET_NR_wait4:
7090 {
7091 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007092 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007093 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007094 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007095 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007096 if (target_rusage)
7097 rusage_ptr = &rusage;
7098 else
7099 rusage_ptr = NULL;
7100 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7101 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007102 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007103 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007104 if (put_user_s32(status, status_ptr))
7105 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007106 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007107 if (target_rusage) {
7108 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7109 if (rusage_err) {
7110 ret = rusage_err;
7111 }
7112 }
bellard31e31b82003-02-18 22:55:36 +00007113 }
7114 }
7115 break;
thse5febef2007-04-01 18:31:35 +00007116#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007117 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007118 if (!(p = lock_user_string(arg1)))
7119 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007120 ret = get_errno(swapoff(p));
7121 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007122 break;
thse5febef2007-04-01 18:31:35 +00007123#endif
bellard31e31b82003-02-18 22:55:36 +00007124 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007125 {
pbrook53a59602006-03-25 19:31:22 +00007126 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007127 struct sysinfo value;
7128 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007129 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007130 {
bellard579a97f2007-11-11 14:26:47 +00007131 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7132 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007133 __put_user(value.uptime, &target_value->uptime);
7134 __put_user(value.loads[0], &target_value->loads[0]);
7135 __put_user(value.loads[1], &target_value->loads[1]);
7136 __put_user(value.loads[2], &target_value->loads[2]);
7137 __put_user(value.totalram, &target_value->totalram);
7138 __put_user(value.freeram, &target_value->freeram);
7139 __put_user(value.sharedram, &target_value->sharedram);
7140 __put_user(value.bufferram, &target_value->bufferram);
7141 __put_user(value.totalswap, &target_value->totalswap);
7142 __put_user(value.freeswap, &target_value->freeswap);
7143 __put_user(value.procs, &target_value->procs);
7144 __put_user(value.totalhigh, &target_value->totalhigh);
7145 __put_user(value.freehigh, &target_value->freehigh);
7146 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007147 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007148 }
7149 }
7150 break;
thse5febef2007-04-01 18:31:35 +00007151#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007152 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007153 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7154 break;
thse5febef2007-04-01 18:31:35 +00007155#endif
aurel32e5289082009-04-18 16:16:12 +00007156#ifdef TARGET_NR_semget
7157 case TARGET_NR_semget:
7158 ret = get_errno(semget(arg1, arg2, arg3));
7159 break;
7160#endif
7161#ifdef TARGET_NR_semop
7162 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007163 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007164 break;
7165#endif
7166#ifdef TARGET_NR_semctl
7167 case TARGET_NR_semctl:
7168 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7169 break;
7170#endif
aurel32eeb438c2008-10-13 21:08:55 +00007171#ifdef TARGET_NR_msgctl
7172 case TARGET_NR_msgctl:
7173 ret = do_msgctl(arg1, arg2, arg3);
7174 break;
7175#endif
7176#ifdef TARGET_NR_msgget
7177 case TARGET_NR_msgget:
7178 ret = get_errno(msgget(arg1, arg2));
7179 break;
7180#endif
7181#ifdef TARGET_NR_msgrcv
7182 case TARGET_NR_msgrcv:
7183 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7184 break;
7185#endif
7186#ifdef TARGET_NR_msgsnd
7187 case TARGET_NR_msgsnd:
7188 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7189 break;
7190#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007191#ifdef TARGET_NR_shmget
7192 case TARGET_NR_shmget:
7193 ret = get_errno(shmget(arg1, arg2, arg3));
7194 break;
7195#endif
7196#ifdef TARGET_NR_shmctl
7197 case TARGET_NR_shmctl:
7198 ret = do_shmctl(arg1, arg2, arg3);
7199 break;
7200#endif
7201#ifdef TARGET_NR_shmat
7202 case TARGET_NR_shmat:
7203 ret = do_shmat(arg1, arg2, arg3);
7204 break;
7205#endif
7206#ifdef TARGET_NR_shmdt
7207 case TARGET_NR_shmdt:
7208 ret = do_shmdt(arg1);
7209 break;
7210#endif
bellard31e31b82003-02-18 22:55:36 +00007211 case TARGET_NR_fsync:
7212 ret = get_errno(fsync(arg1));
7213 break;
bellard31e31b82003-02-18 22:55:36 +00007214 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007215 /* Linux manages to have three different orderings for its
7216 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7217 * match the kernel's CONFIG_CLONE_* settings.
7218 * Microblaze is further special in that it uses a sixth
7219 * implicit argument to clone for the TLS pointer.
7220 */
7221#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007222 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007223#elif defined(TARGET_CLONE_BACKWARDS)
7224 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7225#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007226 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007227#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007228 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007229#endif
bellard1b6b0292003-03-22 17:31:38 +00007230 break;
bellardec86b0f2003-04-11 00:15:04 +00007231#ifdef __NR_exit_group
7232 /* new thread calls */
7233 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007234#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007235 _mcleanup();
7236#endif
bellarde9009672005-04-26 20:42:36 +00007237 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007238 ret = get_errno(exit_group(arg1));
7239 break;
7240#endif
bellard31e31b82003-02-18 22:55:36 +00007241 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007242 if (!(p = lock_user_string(arg1)))
7243 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007244 ret = get_errno(setdomainname(p, arg2));
7245 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007246 break;
7247 case TARGET_NR_uname:
7248 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007249 {
7250 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007251
bellard579a97f2007-11-11 14:26:47 +00007252 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7253 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007254 ret = get_errno(sys_uname(buf));
7255 if (!is_error(ret)) {
7256 /* Overrite the native machine name with whatever is being
7257 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007258 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007259 /* Allow the user to override the reported release. */
7260 if (qemu_uname_release && *qemu_uname_release)
7261 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007262 }
pbrook53a59602006-03-25 19:31:22 +00007263 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007264 }
bellard31e31b82003-02-18 22:55:36 +00007265 break;
bellard6dbad632003-03-16 18:05:05 +00007266#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007267 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007268 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007269 break;
j_mayer84409dd2007-04-06 08:56:50 +00007270#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007271 case TARGET_NR_vm86old:
7272 goto unimplemented;
7273 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007274 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007275 break;
7276#endif
j_mayer84409dd2007-04-06 08:56:50 +00007277#endif
bellard31e31b82003-02-18 22:55:36 +00007278 case TARGET_NR_adjtimex:
7279 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007280#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007281 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007282#endif
bellard31e31b82003-02-18 22:55:36 +00007283 case TARGET_NR_init_module:
7284 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007285#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007286 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007287#endif
bellard31e31b82003-02-18 22:55:36 +00007288 goto unimplemented;
7289 case TARGET_NR_quotactl:
7290 goto unimplemented;
7291 case TARGET_NR_getpgid:
7292 ret = get_errno(getpgid(arg1));
7293 break;
7294 case TARGET_NR_fchdir:
7295 ret = get_errno(fchdir(arg1));
7296 break;
j_mayer84409dd2007-04-06 08:56:50 +00007297#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007298 case TARGET_NR_bdflush:
7299 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007300#endif
thse5febef2007-04-01 18:31:35 +00007301#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007302 case TARGET_NR_sysfs:
7303 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007304#endif
bellard31e31b82003-02-18 22:55:36 +00007305 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007306 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007307 break;
thse5febef2007-04-01 18:31:35 +00007308#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007309 case TARGET_NR_afs_syscall:
7310 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007311#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007312#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007313 case TARGET_NR__llseek:
7314 {
7315 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007316#if !defined(__NR_llseek)
7317 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7318 if (res == -1) {
7319 ret = get_errno(res);
7320 } else {
7321 ret = 0;
7322 }
7323#else
bellard31e31b82003-02-18 22:55:36 +00007324 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007325#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007326 if ((ret == 0) && put_user_s64(res, arg4)) {
7327 goto efault;
7328 }
bellard31e31b82003-02-18 22:55:36 +00007329 }
7330 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007331#endif
bellard31e31b82003-02-18 22:55:36 +00007332 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007333#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007334#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007335 {
pbrook53a59602006-03-25 19:31:22 +00007336 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007337 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007338 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007339
7340 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007341 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007342 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007343 goto fail;
7344 }
ths3b46e622007-09-17 08:09:54 +00007345
bellard4add45b2003-06-05 01:52:59 +00007346 ret = get_errno(sys_getdents(arg1, dirp, count));
7347 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007348 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007349 struct target_dirent *tde;
7350 int len = ret;
7351 int reclen, treclen;
7352 int count1, tnamelen;
7353
7354 count1 = 0;
7355 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007356 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7357 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007358 tde = target_dirp;
7359 while (len > 0) {
7360 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007361 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7362 assert(tnamelen >= 0);
7363 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7364 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007365 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007366 tde->d_ino = tswapal(de->d_ino);
7367 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007368 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007369 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007370 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007371 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007372 count1 += treclen;
7373 }
7374 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007375 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007376 }
7377 free(dirp);
7378 }
7379#else
bellard31e31b82003-02-18 22:55:36 +00007380 {
aurel326556a832008-10-13 21:08:17 +00007381 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007382 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007383
bellard579a97f2007-11-11 14:26:47 +00007384 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7385 goto efault;
bellard72f03902003-02-18 23:33:18 +00007386 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007387 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007388 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007389 int len = ret;
7390 int reclen;
7391 de = dirp;
7392 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007393 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007394 if (reclen > len)
7395 break;
bellard8083a3e2003-03-24 23:12:16 +00007396 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007397 tswapls(&de->d_ino);
7398 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007399 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007400 len -= reclen;
7401 }
7402 }
pbrook53a59602006-03-25 19:31:22 +00007403 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007404 }
bellard4add45b2003-06-05 01:52:59 +00007405#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007406#else
7407 /* Implement getdents in terms of getdents64 */
7408 {
7409 struct linux_dirent64 *dirp;
7410 abi_long count = arg3;
7411
7412 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7413 if (!dirp) {
7414 goto efault;
7415 }
7416 ret = get_errno(sys_getdents64(arg1, dirp, count));
7417 if (!is_error(ret)) {
7418 /* Convert the dirent64 structs to target dirent. We do this
7419 * in-place, since we can guarantee that a target_dirent is no
7420 * larger than a dirent64; however this means we have to be
7421 * careful to read everything before writing in the new format.
7422 */
7423 struct linux_dirent64 *de;
7424 struct target_dirent *tde;
7425 int len = ret;
7426 int tlen = 0;
7427
7428 de = dirp;
7429 tde = (struct target_dirent *)dirp;
7430 while (len > 0) {
7431 int namelen, treclen;
7432 int reclen = de->d_reclen;
7433 uint64_t ino = de->d_ino;
7434 int64_t off = de->d_off;
7435 uint8_t type = de->d_type;
7436
7437 namelen = strlen(de->d_name);
7438 treclen = offsetof(struct target_dirent, d_name)
7439 + namelen + 2;
7440 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7441
7442 memmove(tde->d_name, de->d_name, namelen + 1);
7443 tde->d_ino = tswapal(ino);
7444 tde->d_off = tswapal(off);
7445 tde->d_reclen = tswap16(treclen);
7446 /* The target_dirent type is in what was formerly a padding
7447 * byte at the end of the structure:
7448 */
7449 *(((char *)tde) + treclen - 1) = type;
7450
7451 de = (struct linux_dirent64 *)((char *)de + reclen);
7452 tde = (struct target_dirent *)((char *)tde + treclen);
7453 len -= reclen;
7454 tlen += treclen;
7455 }
7456 ret = tlen;
7457 }
7458 unlock_user(dirp, arg2, ret);
7459 }
7460#endif
bellard31e31b82003-02-18 22:55:36 +00007461 break;
ths3ae43202007-09-16 21:39:48 +00007462#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007463 case TARGET_NR_getdents64:
7464 {
aurel326556a832008-10-13 21:08:17 +00007465 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007466 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007467 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7468 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007469 ret = get_errno(sys_getdents64(arg1, dirp, count));
7470 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007471 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007472 int len = ret;
7473 int reclen;
7474 de = dirp;
7475 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007476 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007477 if (reclen > len)
7478 break;
bellard8083a3e2003-03-24 23:12:16 +00007479 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007480 tswap64s((uint64_t *)&de->d_ino);
7481 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007482 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007483 len -= reclen;
7484 }
7485 }
pbrook53a59602006-03-25 19:31:22 +00007486 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007487 }
7488 break;
bellarda541f292004-04-12 20:39:29 +00007489#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007490#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007491 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007492 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007493 break;
thse5febef2007-04-01 18:31:35 +00007494#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007495#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7496# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007497 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007498# endif
7499# ifdef TARGET_NR_ppoll
7500 case TARGET_NR_ppoll:
7501# endif
bellard9de5e442003-03-23 16:49:39 +00007502 {
pbrook53a59602006-03-25 19:31:22 +00007503 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007504 unsigned int nfds = arg2;
7505 int timeout = arg3;
7506 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007507 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007508
bellard579a97f2007-11-11 14:26:47 +00007509 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7510 if (!target_pfd)
7511 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007512
bellard9de5e442003-03-23 16:49:39 +00007513 pfd = alloca(sizeof(struct pollfd) * nfds);
7514 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007515 pfd[i].fd = tswap32(target_pfd[i].fd);
7516 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007517 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007518
7519# ifdef TARGET_NR_ppoll
7520 if (num == TARGET_NR_ppoll) {
7521 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7522 target_sigset_t *target_set;
7523 sigset_t _set, *set = &_set;
7524
7525 if (arg3) {
7526 if (target_to_host_timespec(timeout_ts, arg3)) {
7527 unlock_user(target_pfd, arg1, 0);
7528 goto efault;
7529 }
7530 } else {
7531 timeout_ts = NULL;
7532 }
7533
7534 if (arg4) {
7535 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7536 if (!target_set) {
7537 unlock_user(target_pfd, arg1, 0);
7538 goto efault;
7539 }
7540 target_to_host_sigset(set, target_set);
7541 } else {
7542 set = NULL;
7543 }
7544
7545 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7546
7547 if (!is_error(ret) && arg3) {
7548 host_to_target_timespec(arg3, timeout_ts);
7549 }
7550 if (arg4) {
7551 unlock_user(target_set, arg4, 0);
7552 }
7553 } else
7554# endif
7555 ret = get_errno(poll(pfd, nfds, timeout));
7556
bellard9de5e442003-03-23 16:49:39 +00007557 if (!is_error(ret)) {
7558 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007559 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007560 }
7561 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007562 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007563 }
7564 break;
thse5febef2007-04-01 18:31:35 +00007565#endif
bellard31e31b82003-02-18 22:55:36 +00007566 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007567 /* NOTE: the flock constant seems to be the same for every
7568 Linux platform */
7569 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007570 break;
7571 case TARGET_NR_readv:
7572 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007573 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7574 if (vec != NULL) {
7575 ret = get_errno(readv(arg1, vec, arg3));
7576 unlock_iovec(vec, arg2, arg3, 1);
7577 } else {
7578 ret = -host_to_target_errno(errno);
7579 }
bellard31e31b82003-02-18 22:55:36 +00007580 }
7581 break;
7582 case TARGET_NR_writev:
7583 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007584 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7585 if (vec != NULL) {
7586 ret = get_errno(writev(arg1, vec, arg3));
7587 unlock_iovec(vec, arg2, arg3, 0);
7588 } else {
7589 ret = -host_to_target_errno(errno);
7590 }
bellard31e31b82003-02-18 22:55:36 +00007591 }
7592 break;
7593 case TARGET_NR_getsid:
7594 ret = get_errno(getsid(arg1));
7595 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007596#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007597 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007598 ret = get_errno(fdatasync(arg1));
7599 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007600#endif
bellard31e31b82003-02-18 22:55:36 +00007601 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007602 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007603 return value. */
ths0da46a62007-10-20 20:23:07 +00007604 ret = -TARGET_ENOTDIR;
7605 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007606 case TARGET_NR_sched_getaffinity:
7607 {
7608 unsigned int mask_size;
7609 unsigned long *mask;
7610
7611 /*
7612 * sched_getaffinity needs multiples of ulong, so need to take
7613 * care of mismatches between target ulong and host ulong sizes.
7614 */
7615 if (arg2 & (sizeof(abi_ulong) - 1)) {
7616 ret = -TARGET_EINVAL;
7617 break;
7618 }
7619 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7620
7621 mask = alloca(mask_size);
7622 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7623
7624 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007625 if (ret > arg2) {
7626 /* More data returned than the caller's buffer will fit.
7627 * This only happens if sizeof(abi_long) < sizeof(long)
7628 * and the caller passed us a buffer holding an odd number
7629 * of abi_longs. If the host kernel is actually using the
7630 * extra 4 bytes then fail EINVAL; otherwise we can just
7631 * ignore them and only copy the interesting part.
7632 */
7633 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7634 if (numcpus > arg2 * 8) {
7635 ret = -TARGET_EINVAL;
7636 break;
7637 }
7638 ret = arg2;
7639 }
7640
Mike McCormackcd18f052011-04-18 14:43:36 +09007641 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007642 goto efault;
7643 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007644 }
7645 }
7646 break;
7647 case TARGET_NR_sched_setaffinity:
7648 {
7649 unsigned int mask_size;
7650 unsigned long *mask;
7651
7652 /*
7653 * sched_setaffinity needs multiples of ulong, so need to take
7654 * care of mismatches between target ulong and host ulong sizes.
7655 */
7656 if (arg2 & (sizeof(abi_ulong) - 1)) {
7657 ret = -TARGET_EINVAL;
7658 break;
7659 }
7660 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7661
7662 mask = alloca(mask_size);
7663 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7664 goto efault;
7665 }
7666 memcpy(mask, p, arg2);
7667 unlock_user_struct(p, arg2, 0);
7668
7669 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7670 }
7671 break;
bellard31e31b82003-02-18 22:55:36 +00007672 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007673 {
pbrook53a59602006-03-25 19:31:22 +00007674 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007675 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007676
bellard579a97f2007-11-11 14:26:47 +00007677 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7678 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007679 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007680 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007681 ret = get_errno(sched_setparam(arg1, &schp));
7682 }
7683 break;
bellard31e31b82003-02-18 22:55:36 +00007684 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007685 {
pbrook53a59602006-03-25 19:31:22 +00007686 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007687 struct sched_param schp;
7688 ret = get_errno(sched_getparam(arg1, &schp));
7689 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007690 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7691 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007692 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007693 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007694 }
7695 }
7696 break;
bellard31e31b82003-02-18 22:55:36 +00007697 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007698 {
pbrook53a59602006-03-25 19:31:22 +00007699 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007700 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007701 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7702 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007703 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007704 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007705 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7706 }
7707 break;
bellard31e31b82003-02-18 22:55:36 +00007708 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007709 ret = get_errno(sched_getscheduler(arg1));
7710 break;
bellard31e31b82003-02-18 22:55:36 +00007711 case TARGET_NR_sched_yield:
7712 ret = get_errno(sched_yield());
7713 break;
7714 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007715 ret = get_errno(sched_get_priority_max(arg1));
7716 break;
bellard31e31b82003-02-18 22:55:36 +00007717 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007718 ret = get_errno(sched_get_priority_min(arg1));
7719 break;
bellard31e31b82003-02-18 22:55:36 +00007720 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007721 {
bellard5cd43932003-03-29 16:54:36 +00007722 struct timespec ts;
7723 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7724 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007725 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007726 }
7727 }
7728 break;
bellard31e31b82003-02-18 22:55:36 +00007729 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007730 {
bellard1b6b0292003-03-22 17:31:38 +00007731 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007732 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007733 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007734 if (is_error(ret) && arg2) {
7735 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007736 }
7737 }
7738 break;
thse5febef2007-04-01 18:31:35 +00007739#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007740 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007741 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007742#endif
7743#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007744 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007745 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007746#endif
bellard31e31b82003-02-18 22:55:36 +00007747 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007748 switch (arg1) {
7749 case PR_GET_PDEATHSIG:
7750 {
7751 int deathsig;
7752 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7753 if (!is_error(ret) && arg2
7754 && put_user_ual(deathsig, arg2)) {
7755 goto efault;
thse5574482007-02-11 20:03:13 +00007756 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007757 break;
7758 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007759#ifdef PR_GET_NAME
7760 case PR_GET_NAME:
7761 {
7762 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7763 if (!name) {
7764 goto efault;
7765 }
7766 ret = get_errno(prctl(arg1, (unsigned long)name,
7767 arg3, arg4, arg5));
7768 unlock_user(name, arg2, 16);
7769 break;
7770 }
7771 case PR_SET_NAME:
7772 {
7773 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7774 if (!name) {
7775 goto efault;
7776 }
7777 ret = get_errno(prctl(arg1, (unsigned long)name,
7778 arg3, arg4, arg5));
7779 unlock_user(name, arg2, 0);
7780 break;
7781 }
7782#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007783 default:
7784 /* Most prctl options have no pointer arguments */
7785 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7786 break;
7787 }
ths39b9aae2007-02-11 18:36:44 +00007788 break;
bellardd2fd1af2007-11-14 18:08:56 +00007789#ifdef TARGET_NR_arch_prctl
7790 case TARGET_NR_arch_prctl:
7791#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7792 ret = do_arch_prctl(cpu_env, arg1, arg2);
7793 break;
7794#else
7795 goto unimplemented;
7796#endif
7797#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007798#ifdef TARGET_NR_pread64
7799 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007800 if (regpairs_aligned(cpu_env)) {
7801 arg4 = arg5;
7802 arg5 = arg6;
7803 }
aurel32f2c7ba12008-03-28 22:32:06 +00007804 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7805 goto efault;
7806 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7807 unlock_user(p, arg2, ret);
7808 break;
7809 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007810 if (regpairs_aligned(cpu_env)) {
7811 arg4 = arg5;
7812 arg5 = arg6;
7813 }
aurel32f2c7ba12008-03-28 22:32:06 +00007814 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7815 goto efault;
7816 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7817 unlock_user(p, arg2, 0);
7818 break;
7819#endif
bellard31e31b82003-02-18 22:55:36 +00007820 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007821 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7822 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007823 ret = get_errno(sys_getcwd1(p, arg2));
7824 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007825 break;
7826 case TARGET_NR_capget:
7827 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007828 {
7829 struct target_user_cap_header *target_header;
7830 struct target_user_cap_data *target_data = NULL;
7831 struct __user_cap_header_struct header;
7832 struct __user_cap_data_struct data[2];
7833 struct __user_cap_data_struct *dataptr = NULL;
7834 int i, target_datalen;
7835 int data_items = 1;
7836
7837 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7838 goto efault;
7839 }
7840 header.version = tswap32(target_header->version);
7841 header.pid = tswap32(target_header->pid);
7842
Peter Maydellec864872014-03-19 16:07:30 +00007843 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007844 /* Version 2 and up takes pointer to two user_data structs */
7845 data_items = 2;
7846 }
7847
7848 target_datalen = sizeof(*target_data) * data_items;
7849
7850 if (arg2) {
7851 if (num == TARGET_NR_capget) {
7852 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7853 } else {
7854 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7855 }
7856 if (!target_data) {
7857 unlock_user_struct(target_header, arg1, 0);
7858 goto efault;
7859 }
7860
7861 if (num == TARGET_NR_capset) {
7862 for (i = 0; i < data_items; i++) {
7863 data[i].effective = tswap32(target_data[i].effective);
7864 data[i].permitted = tswap32(target_data[i].permitted);
7865 data[i].inheritable = tswap32(target_data[i].inheritable);
7866 }
7867 }
7868
7869 dataptr = data;
7870 }
7871
7872 if (num == TARGET_NR_capget) {
7873 ret = get_errno(capget(&header, dataptr));
7874 } else {
7875 ret = get_errno(capset(&header, dataptr));
7876 }
7877
7878 /* The kernel always updates version for both capget and capset */
7879 target_header->version = tswap32(header.version);
7880 unlock_user_struct(target_header, arg1, 1);
7881
7882 if (arg2) {
7883 if (num == TARGET_NR_capget) {
7884 for (i = 0; i < data_items; i++) {
7885 target_data[i].effective = tswap32(data[i].effective);
7886 target_data[i].permitted = tswap32(data[i].permitted);
7887 target_data[i].inheritable = tswap32(data[i].inheritable);
7888 }
7889 unlock_user(target_data, arg2, target_datalen);
7890 } else {
7891 unlock_user(target_data, arg2, 0);
7892 }
7893 }
7894 break;
7895 }
bellard31e31b82003-02-18 22:55:36 +00007896 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007897#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007898 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007899 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007900 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007901 break;
7902#else
bellard5cd43932003-03-29 16:54:36 +00007903 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007904#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007905
7906#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007907 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007908 {
7909 off_t *offp = NULL;
7910 off_t off;
7911 if (arg3) {
7912 ret = get_user_sal(off, arg3);
7913 if (is_error(ret)) {
7914 break;
7915 }
7916 offp = &off;
7917 }
7918 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7919 if (!is_error(ret) && arg3) {
7920 abi_long ret2 = put_user_sal(off, arg3);
7921 if (is_error(ret2)) {
7922 ret = ret2;
7923 }
7924 }
7925 break;
7926 }
7927#ifdef TARGET_NR_sendfile64
7928 case TARGET_NR_sendfile64:
7929 {
7930 off_t *offp = NULL;
7931 off_t off;
7932 if (arg3) {
7933 ret = get_user_s64(off, arg3);
7934 if (is_error(ret)) {
7935 break;
7936 }
7937 offp = &off;
7938 }
7939 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7940 if (!is_error(ret) && arg3) {
7941 abi_long ret2 = put_user_s64(off, arg3);
7942 if (is_error(ret2)) {
7943 ret = ret2;
7944 }
7945 }
7946 break;
7947 }
7948#endif
7949#else
7950 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007951#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007952 case TARGET_NR_sendfile64:
7953#endif
bellard5cd43932003-03-29 16:54:36 +00007954 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007955#endif
7956
bellardebc05482003-09-30 21:08:41 +00007957#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007958 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007959 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007960#endif
7961#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007962 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007963 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007964#endif
bellard048f6b42005-11-26 18:47:20 +00007965#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007966 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007967 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7968 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007969 break;
bellard048f6b42005-11-26 18:47:20 +00007970#endif
bellardebc05482003-09-30 21:08:41 +00007971#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007972 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007973 {
7974 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007975 int resource = target_to_host_resource(arg1);
7976 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007977 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007978 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007979 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7980 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007981 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7982 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007983 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007984 }
7985 break;
7986 }
bellardebc05482003-09-30 21:08:41 +00007987#endif
bellarda315a142005-01-30 22:59:18 +00007988#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007989 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007990 if (!(p = lock_user_string(arg1)))
7991 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007992 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7993 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007994 break;
bellarda315a142005-01-30 22:59:18 +00007995#endif
7996#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007997 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007998 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007999 break;
bellarda315a142005-01-30 22:59:18 +00008000#endif
8001#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008002 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008003 if (!(p = lock_user_string(arg1)))
8004 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008005 ret = get_errno(stat(path(p), &st));
8006 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008007 if (!is_error(ret))
8008 ret = host_to_target_stat64(cpu_env, arg2, &st);
8009 break;
bellarda315a142005-01-30 22:59:18 +00008010#endif
8011#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008012 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008013 if (!(p = lock_user_string(arg1)))
8014 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008015 ret = get_errno(lstat(path(p), &st));
8016 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008017 if (!is_error(ret))
8018 ret = host_to_target_stat64(cpu_env, arg2, &st);
8019 break;
bellarda315a142005-01-30 22:59:18 +00008020#endif
8021#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008022 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008023 ret = get_errno(fstat(arg1, &st));
8024 if (!is_error(ret))
8025 ret = host_to_target_stat64(cpu_env, arg2, &st);
8026 break;
bellardec86b0f2003-04-11 00:15:04 +00008027#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008028#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008029#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008030 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008031#endif
8032#ifdef TARGET_NR_newfstatat
8033 case TARGET_NR_newfstatat:
8034#endif
balrog6a24a772008-09-20 02:23:36 +00008035 if (!(p = lock_user_string(arg2)))
8036 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008037 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008038 if (!is_error(ret))
8039 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008040 break;
bellarda315a142005-01-30 22:59:18 +00008041#endif
bellard67867302003-11-23 17:05:30 +00008042 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008043 if (!(p = lock_user_string(arg1)))
8044 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008045 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8046 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008047 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008048#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008049 case TARGET_NR_getuid:
8050 ret = get_errno(high2lowuid(getuid()));
8051 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008052#endif
8053#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008054 case TARGET_NR_getgid:
8055 ret = get_errno(high2lowgid(getgid()));
8056 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008057#endif
8058#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008059 case TARGET_NR_geteuid:
8060 ret = get_errno(high2lowuid(geteuid()));
8061 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008062#endif
8063#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008064 case TARGET_NR_getegid:
8065 ret = get_errno(high2lowgid(getegid()));
8066 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008067#endif
bellard67867302003-11-23 17:05:30 +00008068 case TARGET_NR_setreuid:
8069 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8070 break;
8071 case TARGET_NR_setregid:
8072 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8073 break;
8074 case TARGET_NR_getgroups:
8075 {
8076 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008077 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008078 gid_t *grouplist;
8079 int i;
8080
8081 grouplist = alloca(gidsetsize * sizeof(gid_t));
8082 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008083 if (gidsetsize == 0)
8084 break;
bellard67867302003-11-23 17:05:30 +00008085 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008086 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008087 if (!target_grouplist)
8088 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008089 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008090 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008091 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008092 }
8093 }
8094 break;
8095 case TARGET_NR_setgroups:
8096 {
8097 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008098 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008099 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008100 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008101 if (gidsetsize) {
8102 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008103 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008104 if (!target_grouplist) {
8105 ret = -TARGET_EFAULT;
8106 goto fail;
8107 }
8108 for (i = 0; i < gidsetsize; i++) {
8109 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8110 }
8111 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008112 }
bellard67867302003-11-23 17:05:30 +00008113 ret = get_errno(setgroups(gidsetsize, grouplist));
8114 }
8115 break;
8116 case TARGET_NR_fchown:
8117 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8118 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008119#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008120 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008121 if (!(p = lock_user_string(arg2)))
8122 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008123 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8124 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008125 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008126 break;
8127#endif
bellard67867302003-11-23 17:05:30 +00008128#ifdef TARGET_NR_setresuid
8129 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008130 ret = get_errno(setresuid(low2highuid(arg1),
8131 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008132 low2highuid(arg3)));
8133 break;
8134#endif
8135#ifdef TARGET_NR_getresuid
8136 case TARGET_NR_getresuid:
8137 {
pbrook53a59602006-03-25 19:31:22 +00008138 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008139 ret = get_errno(getresuid(&ruid, &euid, &suid));
8140 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008141 if (put_user_id(high2lowuid(ruid), arg1)
8142 || put_user_id(high2lowuid(euid), arg2)
8143 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008144 goto efault;
bellard67867302003-11-23 17:05:30 +00008145 }
8146 }
8147 break;
8148#endif
8149#ifdef TARGET_NR_getresgid
8150 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008151 ret = get_errno(setresgid(low2highgid(arg1),
8152 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008153 low2highgid(arg3)));
8154 break;
8155#endif
8156#ifdef TARGET_NR_getresgid
8157 case TARGET_NR_getresgid:
8158 {
pbrook53a59602006-03-25 19:31:22 +00008159 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008160 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8161 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008162 if (put_user_id(high2lowgid(rgid), arg1)
8163 || put_user_id(high2lowgid(egid), arg2)
8164 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008165 goto efault;
bellard67867302003-11-23 17:05:30 +00008166 }
8167 }
8168 break;
8169#endif
8170 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008171 if (!(p = lock_user_string(arg1)))
8172 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008173 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8174 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008175 break;
8176 case TARGET_NR_setuid:
8177 ret = get_errno(setuid(low2highuid(arg1)));
8178 break;
8179 case TARGET_NR_setgid:
8180 ret = get_errno(setgid(low2highgid(arg1)));
8181 break;
8182 case TARGET_NR_setfsuid:
8183 ret = get_errno(setfsuid(arg1));
8184 break;
8185 case TARGET_NR_setfsgid:
8186 ret = get_errno(setfsgid(arg1));
8187 break;
bellard67867302003-11-23 17:05:30 +00008188
bellarda315a142005-01-30 22:59:18 +00008189#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008190 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008191 if (!(p = lock_user_string(arg1)))
8192 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008193 ret = get_errno(lchown(p, arg2, arg3));
8194 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008195 break;
bellarda315a142005-01-30 22:59:18 +00008196#endif
8197#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008198 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008199 ret = get_errno(getuid());
8200 break;
bellarda315a142005-01-30 22:59:18 +00008201#endif
aurel3264b4d282008-11-14 17:20:15 +00008202
8203#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8204 /* Alpha specific */
8205 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008206 {
8207 uid_t euid;
8208 euid=geteuid();
8209 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8210 }
aurel3264b4d282008-11-14 17:20:15 +00008211 ret = get_errno(getuid());
8212 break;
8213#endif
8214#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8215 /* Alpha specific */
8216 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008217 {
8218 uid_t egid;
8219 egid=getegid();
8220 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8221 }
aurel3264b4d282008-11-14 17:20:15 +00008222 ret = get_errno(getgid());
8223 break;
8224#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008225#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8226 /* Alpha specific */
8227 case TARGET_NR_osf_getsysinfo:
8228 ret = -TARGET_EOPNOTSUPP;
8229 switch (arg1) {
8230 case TARGET_GSI_IEEE_FP_CONTROL:
8231 {
8232 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8233
8234 /* Copied from linux ieee_fpcr_to_swcr. */
8235 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8236 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8237 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8238 | SWCR_TRAP_ENABLE_DZE
8239 | SWCR_TRAP_ENABLE_OVF);
8240 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8241 | SWCR_TRAP_ENABLE_INE);
8242 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8243 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8244
8245 if (put_user_u64 (swcr, arg2))
8246 goto efault;
8247 ret = 0;
8248 }
8249 break;
8250
8251 /* case GSI_IEEE_STATE_AT_SIGNAL:
8252 -- Not implemented in linux kernel.
8253 case GSI_UACPROC:
8254 -- Retrieves current unaligned access state; not much used.
8255 case GSI_PROC_TYPE:
8256 -- Retrieves implver information; surely not used.
8257 case GSI_GET_HWRPB:
8258 -- Grabs a copy of the HWRPB; surely not used.
8259 */
8260 }
8261 break;
8262#endif
8263#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8264 /* Alpha specific */
8265 case TARGET_NR_osf_setsysinfo:
8266 ret = -TARGET_EOPNOTSUPP;
8267 switch (arg1) {
8268 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008269 {
8270 uint64_t swcr, fpcr, orig_fpcr;
8271
Richard Henderson6e06d512012-06-01 09:08:21 -07008272 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008273 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008274 }
8275 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008276 fpcr = orig_fpcr & FPCR_DYN_MASK;
8277
8278 /* Copied from linux ieee_swcr_to_fpcr. */
8279 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8280 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8281 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8282 | SWCR_TRAP_ENABLE_DZE
8283 | SWCR_TRAP_ENABLE_OVF)) << 48;
8284 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8285 | SWCR_TRAP_ENABLE_INE)) << 57;
8286 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8287 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8288
Richard Henderson6e06d512012-06-01 09:08:21 -07008289 cpu_alpha_store_fpcr(cpu_env, fpcr);
8290 ret = 0;
8291 }
8292 break;
8293
8294 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8295 {
8296 uint64_t exc, fpcr, orig_fpcr;
8297 int si_code;
8298
8299 if (get_user_u64(exc, arg2)) {
8300 goto efault;
8301 }
8302
8303 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8304
8305 /* We only add to the exception status here. */
8306 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8307
8308 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008309 ret = 0;
8310
Richard Henderson6e06d512012-06-01 09:08:21 -07008311 /* Old exceptions are not signaled. */
8312 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008313
Richard Henderson6e06d512012-06-01 09:08:21 -07008314 /* If any exceptions set by this call,
8315 and are unmasked, send a signal. */
8316 si_code = 0;
8317 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8318 si_code = TARGET_FPE_FLTRES;
8319 }
8320 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8321 si_code = TARGET_FPE_FLTUND;
8322 }
8323 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8324 si_code = TARGET_FPE_FLTOVF;
8325 }
8326 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8327 si_code = TARGET_FPE_FLTDIV;
8328 }
8329 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8330 si_code = TARGET_FPE_FLTINV;
8331 }
8332 if (si_code != 0) {
8333 target_siginfo_t info;
8334 info.si_signo = SIGFPE;
8335 info.si_errno = 0;
8336 info.si_code = si_code;
8337 info._sifields._sigfault._addr
8338 = ((CPUArchState *)cpu_env)->pc;
8339 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008340 }
8341 }
8342 break;
8343
8344 /* case SSI_NVPAIRS:
8345 -- Used with SSIN_UACPROC to enable unaligned accesses.
8346 case SSI_IEEE_STATE_AT_SIGNAL:
8347 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8348 -- Not implemented in linux kernel
8349 */
8350 }
8351 break;
8352#endif
8353#ifdef TARGET_NR_osf_sigprocmask
8354 /* Alpha specific. */
8355 case TARGET_NR_osf_sigprocmask:
8356 {
8357 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008358 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008359 sigset_t set, oldset;
8360
8361 switch(arg1) {
8362 case TARGET_SIG_BLOCK:
8363 how = SIG_BLOCK;
8364 break;
8365 case TARGET_SIG_UNBLOCK:
8366 how = SIG_UNBLOCK;
8367 break;
8368 case TARGET_SIG_SETMASK:
8369 how = SIG_SETMASK;
8370 break;
8371 default:
8372 ret = -TARGET_EINVAL;
8373 goto fail;
8374 }
8375 mask = arg2;
8376 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008377 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008378 host_to_target_old_sigset(&mask, &oldset);
8379 ret = mask;
8380 }
8381 break;
8382#endif
aurel3264b4d282008-11-14 17:20:15 +00008383
bellarda315a142005-01-30 22:59:18 +00008384#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008385 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008386 ret = get_errno(getgid());
8387 break;
bellarda315a142005-01-30 22:59:18 +00008388#endif
8389#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008390 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008391 ret = get_errno(geteuid());
8392 break;
bellarda315a142005-01-30 22:59:18 +00008393#endif
8394#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008395 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008396 ret = get_errno(getegid());
8397 break;
bellarda315a142005-01-30 22:59:18 +00008398#endif
8399#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008400 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008401 ret = get_errno(setreuid(arg1, arg2));
8402 break;
bellarda315a142005-01-30 22:59:18 +00008403#endif
8404#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008405 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008406 ret = get_errno(setregid(arg1, arg2));
8407 break;
bellarda315a142005-01-30 22:59:18 +00008408#endif
8409#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008410 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008411 {
8412 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008413 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008414 gid_t *grouplist;
8415 int i;
8416
8417 grouplist = alloca(gidsetsize * sizeof(gid_t));
8418 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008419 if (gidsetsize == 0)
8420 break;
bellard99c475a2005-01-31 20:45:13 +00008421 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008422 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8423 if (!target_grouplist) {
8424 ret = -TARGET_EFAULT;
8425 goto fail;
8426 }
balroga2155fc2008-09-20 02:12:08 +00008427 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008428 target_grouplist[i] = tswap32(grouplist[i]);
8429 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008430 }
8431 }
8432 break;
bellarda315a142005-01-30 22:59:18 +00008433#endif
8434#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008435 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008436 {
8437 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008438 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008439 gid_t *grouplist;
8440 int i;
ths3b46e622007-09-17 08:09:54 +00008441
bellard99c475a2005-01-31 20:45:13 +00008442 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008443 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8444 if (!target_grouplist) {
8445 ret = -TARGET_EFAULT;
8446 goto fail;
8447 }
bellard99c475a2005-01-31 20:45:13 +00008448 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008449 grouplist[i] = tswap32(target_grouplist[i]);
8450 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008451 ret = get_errno(setgroups(gidsetsize, grouplist));
8452 }
8453 break;
bellarda315a142005-01-30 22:59:18 +00008454#endif
8455#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008456 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008457 ret = get_errno(fchown(arg1, arg2, arg3));
8458 break;
bellarda315a142005-01-30 22:59:18 +00008459#endif
8460#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008461 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008462 ret = get_errno(setresuid(arg1, arg2, arg3));
8463 break;
bellarda315a142005-01-30 22:59:18 +00008464#endif
8465#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008466 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008467 {
pbrook53a59602006-03-25 19:31:22 +00008468 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008469 ret = get_errno(getresuid(&ruid, &euid, &suid));
8470 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008471 if (put_user_u32(ruid, arg1)
8472 || put_user_u32(euid, arg2)
8473 || put_user_u32(suid, arg3))
8474 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008475 }
8476 }
8477 break;
bellarda315a142005-01-30 22:59:18 +00008478#endif
8479#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008480 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008481 ret = get_errno(setresgid(arg1, arg2, arg3));
8482 break;
bellarda315a142005-01-30 22:59:18 +00008483#endif
8484#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008485 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008486 {
pbrook53a59602006-03-25 19:31:22 +00008487 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008488 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8489 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008490 if (put_user_u32(rgid, arg1)
8491 || put_user_u32(egid, arg2)
8492 || put_user_u32(sgid, arg3))
8493 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008494 }
8495 }
8496 break;
bellarda315a142005-01-30 22:59:18 +00008497#endif
8498#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008499 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008500 if (!(p = lock_user_string(arg1)))
8501 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008502 ret = get_errno(chown(p, arg2, arg3));
8503 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008504 break;
bellarda315a142005-01-30 22:59:18 +00008505#endif
8506#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008507 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008508 ret = get_errno(setuid(arg1));
8509 break;
bellarda315a142005-01-30 22:59:18 +00008510#endif
8511#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008512 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008513 ret = get_errno(setgid(arg1));
8514 break;
bellarda315a142005-01-30 22:59:18 +00008515#endif
8516#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008517 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008518 ret = get_errno(setfsuid(arg1));
8519 break;
bellarda315a142005-01-30 22:59:18 +00008520#endif
8521#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008522 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008523 ret = get_errno(setfsgid(arg1));
8524 break;
bellarda315a142005-01-30 22:59:18 +00008525#endif
bellard67867302003-11-23 17:05:30 +00008526
bellard31e31b82003-02-18 22:55:36 +00008527 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008528 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008529#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008530 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008531 {
8532 void *a;
8533 ret = -TARGET_EFAULT;
8534 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8535 goto efault;
8536 if (!(p = lock_user_string(arg3)))
8537 goto mincore_fail;
8538 ret = get_errno(mincore(a, arg2, p));
8539 unlock_user(p, arg3, ret);
8540 mincore_fail:
8541 unlock_user(a, arg1, 0);
8542 }
8543 break;
bellardffa65c32004-01-04 23:57:22 +00008544#endif
aurel32408321b2008-10-01 21:46:32 +00008545#ifdef TARGET_NR_arm_fadvise64_64
8546 case TARGET_NR_arm_fadvise64_64:
8547 {
8548 /*
8549 * arm_fadvise64_64 looks like fadvise64_64 but
8550 * with different argument order
8551 */
8552 abi_long temp;
8553 temp = arg3;
8554 arg3 = arg4;
8555 arg4 = temp;
8556 }
8557#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008558#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008559#ifdef TARGET_NR_fadvise64_64
8560 case TARGET_NR_fadvise64_64:
8561#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008562#ifdef TARGET_NR_fadvise64
8563 case TARGET_NR_fadvise64:
8564#endif
8565#ifdef TARGET_S390X
8566 switch (arg4) {
8567 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8568 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8569 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8570 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8571 default: break;
8572 }
8573#endif
8574 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008575 break;
8576#endif
bellardffa65c32004-01-04 23:57:22 +00008577#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008578 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008579 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008580 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008581 This will break MADV_DONTNEED.
8582 This is a hint, so ignoring and returning success is ok. */
8583 ret = get_errno(0);
8584 break;
bellardffa65c32004-01-04 23:57:22 +00008585#endif
blueswir1992f48a2007-10-14 16:27:31 +00008586#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008587 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008588 {
thsb1e341e2007-03-20 21:50:52 +00008589 int cmd;
bellard77e46722003-04-29 20:39:06 +00008590 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008591 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008592#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008593 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008594#endif
bellard77e46722003-04-29 20:39:06 +00008595
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008596 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008597 if (cmd == -TARGET_EINVAL) {
8598 ret = cmd;
8599 break;
8600 }
thsb1e341e2007-03-20 21:50:52 +00008601
bellard60cd49d2003-03-16 22:53:56 +00008602 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008603 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008604#ifdef TARGET_ARM
8605 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008606 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8607 goto efault;
ths58134272007-03-31 18:59:32 +00008608 fl.l_type = tswap16(target_efl->l_type);
8609 fl.l_whence = tswap16(target_efl->l_whence);
8610 fl.l_start = tswap64(target_efl->l_start);
8611 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008612 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008613 unlock_user_struct(target_efl, arg3, 0);
8614 } else
8615#endif
8616 {
bellard9ee1fa22007-11-11 15:11:19 +00008617 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8618 goto efault;
ths58134272007-03-31 18:59:32 +00008619 fl.l_type = tswap16(target_fl->l_type);
8620 fl.l_whence = tswap16(target_fl->l_whence);
8621 fl.l_start = tswap64(target_fl->l_start);
8622 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008623 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008624 unlock_user_struct(target_fl, arg3, 0);
8625 }
thsb1e341e2007-03-20 21:50:52 +00008626 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008627 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008628#ifdef TARGET_ARM
8629 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008630 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8631 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008632 target_efl->l_type = tswap16(fl.l_type);
8633 target_efl->l_whence = tswap16(fl.l_whence);
8634 target_efl->l_start = tswap64(fl.l_start);
8635 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008636 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008637 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008638 } else
8639#endif
8640 {
bellard9ee1fa22007-11-11 15:11:19 +00008641 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8642 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008643 target_fl->l_type = tswap16(fl.l_type);
8644 target_fl->l_whence = tswap16(fl.l_whence);
8645 target_fl->l_start = tswap64(fl.l_start);
8646 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008647 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008648 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008649 }
bellard77e46722003-04-29 20:39:06 +00008650 }
8651 break;
8652
thsb1e341e2007-03-20 21:50:52 +00008653 case TARGET_F_SETLK64:
8654 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008655#ifdef TARGET_ARM
8656 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008657 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8658 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008659 fl.l_type = tswap16(target_efl->l_type);
8660 fl.l_whence = tswap16(target_efl->l_whence);
8661 fl.l_start = tswap64(target_efl->l_start);
8662 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008663 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008664 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008665 } else
8666#endif
8667 {
bellard9ee1fa22007-11-11 15:11:19 +00008668 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8669 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008670 fl.l_type = tswap16(target_fl->l_type);
8671 fl.l_whence = tswap16(target_fl->l_whence);
8672 fl.l_start = tswap64(target_fl->l_start);
8673 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008674 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008675 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008676 }
thsb1e341e2007-03-20 21:50:52 +00008677 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008678 break;
bellard60cd49d2003-03-16 22:53:56 +00008679 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008680 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008681 break;
8682 }
bellard77e46722003-04-29 20:39:06 +00008683 break;
8684 }
bellard60cd49d2003-03-16 22:53:56 +00008685#endif
ths7d600c82006-12-08 01:32:58 +00008686#ifdef TARGET_NR_cacheflush
8687 case TARGET_NR_cacheflush:
8688 /* self-modifying code is handled automatically, so nothing needed */
8689 ret = 0;
8690 break;
8691#endif
bellardebc05482003-09-30 21:08:41 +00008692#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008693 case TARGET_NR_security:
8694 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008695#endif
bellardc573ff62004-01-04 15:51:36 +00008696#ifdef TARGET_NR_getpagesize
8697 case TARGET_NR_getpagesize:
8698 ret = TARGET_PAGE_SIZE;
8699 break;
8700#endif
bellard31e31b82003-02-18 22:55:36 +00008701 case TARGET_NR_gettid:
8702 ret = get_errno(gettid());
8703 break;
thse5febef2007-04-01 18:31:35 +00008704#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008705 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008706#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008707 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008708 arg2 = arg3;
8709 arg3 = arg4;
8710 arg4 = arg5;
8711 }
aurel322054ac92008-10-13 21:08:07 +00008712 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8713#else
8714 ret = get_errno(readahead(arg1, arg2, arg3));
8715#endif
8716 break;
thse5febef2007-04-01 18:31:35 +00008717#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008718#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008719#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008720 case TARGET_NR_listxattr:
8721 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008722 {
8723 void *p, *b = 0;
8724 if (arg2) {
8725 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8726 if (!b) {
8727 ret = -TARGET_EFAULT;
8728 break;
8729 }
8730 }
8731 p = lock_user_string(arg1);
8732 if (p) {
8733 if (num == TARGET_NR_listxattr) {
8734 ret = get_errno(listxattr(p, b, arg3));
8735 } else {
8736 ret = get_errno(llistxattr(p, b, arg3));
8737 }
8738 } else {
8739 ret = -TARGET_EFAULT;
8740 }
8741 unlock_user(p, arg1, 0);
8742 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008743 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008744 }
8745 case TARGET_NR_flistxattr:
8746 {
8747 void *b = 0;
8748 if (arg2) {
8749 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8750 if (!b) {
8751 ret = -TARGET_EFAULT;
8752 break;
8753 }
8754 }
8755 ret = get_errno(flistxattr(arg1, b, arg3));
8756 unlock_user(b, arg2, arg3);
8757 break;
8758 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008759 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008760 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008761 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008762 void *p, *n, *v = 0;
8763 if (arg3) {
8764 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8765 if (!v) {
8766 ret = -TARGET_EFAULT;
8767 break;
8768 }
8769 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008770 p = lock_user_string(arg1);
8771 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008772 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008773 if (num == TARGET_NR_setxattr) {
8774 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8775 } else {
8776 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8777 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008778 } else {
8779 ret = -TARGET_EFAULT;
8780 }
8781 unlock_user(p, arg1, 0);
8782 unlock_user(n, arg2, 0);
8783 unlock_user(v, arg3, 0);
8784 }
8785 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008786 case TARGET_NR_fsetxattr:
8787 {
8788 void *n, *v = 0;
8789 if (arg3) {
8790 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8791 if (!v) {
8792 ret = -TARGET_EFAULT;
8793 break;
8794 }
8795 }
8796 n = lock_user_string(arg2);
8797 if (n) {
8798 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8799 } else {
8800 ret = -TARGET_EFAULT;
8801 }
8802 unlock_user(n, arg2, 0);
8803 unlock_user(v, arg3, 0);
8804 }
8805 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008806 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008807 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008808 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008809 void *p, *n, *v = 0;
8810 if (arg3) {
8811 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8812 if (!v) {
8813 ret = -TARGET_EFAULT;
8814 break;
8815 }
8816 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008817 p = lock_user_string(arg1);
8818 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008819 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008820 if (num == TARGET_NR_getxattr) {
8821 ret = get_errno(getxattr(p, n, v, arg4));
8822 } else {
8823 ret = get_errno(lgetxattr(p, n, v, arg4));
8824 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008825 } else {
8826 ret = -TARGET_EFAULT;
8827 }
8828 unlock_user(p, arg1, 0);
8829 unlock_user(n, arg2, 0);
8830 unlock_user(v, arg3, arg4);
8831 }
8832 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008833 case TARGET_NR_fgetxattr:
8834 {
8835 void *n, *v = 0;
8836 if (arg3) {
8837 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8838 if (!v) {
8839 ret = -TARGET_EFAULT;
8840 break;
8841 }
8842 }
8843 n = lock_user_string(arg2);
8844 if (n) {
8845 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8846 } else {
8847 ret = -TARGET_EFAULT;
8848 }
8849 unlock_user(n, arg2, 0);
8850 unlock_user(v, arg3, arg4);
8851 }
8852 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008853 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008854 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008855 {
8856 void *p, *n;
8857 p = lock_user_string(arg1);
8858 n = lock_user_string(arg2);
8859 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008860 if (num == TARGET_NR_removexattr) {
8861 ret = get_errno(removexattr(p, n));
8862 } else {
8863 ret = get_errno(lremovexattr(p, n));
8864 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008865 } else {
8866 ret = -TARGET_EFAULT;
8867 }
8868 unlock_user(p, arg1, 0);
8869 unlock_user(n, arg2, 0);
8870 }
8871 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008872 case TARGET_NR_fremovexattr:
8873 {
8874 void *n;
8875 n = lock_user_string(arg2);
8876 if (n) {
8877 ret = get_errno(fremovexattr(arg1, n));
8878 } else {
8879 ret = -TARGET_EFAULT;
8880 }
8881 unlock_user(n, arg2, 0);
8882 }
8883 break;
bellardebc05482003-09-30 21:08:41 +00008884#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008885#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008886#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008887 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008888#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02008889 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00008890 ret = 0;
8891 break;
edgar_iglef967792009-01-07 14:19:38 +00008892#elif defined(TARGET_CRIS)
8893 if (arg1 & 0xff)
8894 ret = -TARGET_EINVAL;
8895 else {
8896 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8897 ret = 0;
8898 }
8899 break;
bellard8d18e892007-11-14 15:18:40 +00008900#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8901 ret = do_set_thread_area(cpu_env, arg1);
8902 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008903#elif defined(TARGET_M68K)
8904 {
Andreas Färber0429a972013-08-26 18:14:44 +02008905 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008906 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008907 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008908 break;
8909 }
ths6f5b89a2007-03-02 20:48:00 +00008910#else
8911 goto unimplemented_nowarn;
8912#endif
8913#endif
8914#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008915 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008916#if defined(TARGET_I386) && defined(TARGET_ABI32)
8917 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008918 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008919#elif defined(TARGET_M68K)
8920 {
Andreas Färber0429a972013-08-26 18:14:44 +02008921 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008922 ret = ts->tp_value;
8923 break;
8924 }
bellard8d18e892007-11-14 15:18:40 +00008925#else
bellard5cd43932003-03-29 16:54:36 +00008926 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008927#endif
bellard8d18e892007-11-14 15:18:40 +00008928#endif
bellard48dc41e2006-06-21 18:15:50 +00008929#ifdef TARGET_NR_getdomainname
8930 case TARGET_NR_getdomainname:
8931 goto unimplemented_nowarn;
8932#endif
ths6f5b89a2007-03-02 20:48:00 +00008933
thsb5906f92007-03-19 13:32:45 +00008934#ifdef TARGET_NR_clock_gettime
8935 case TARGET_NR_clock_gettime:
8936 {
8937 struct timespec ts;
8938 ret = get_errno(clock_gettime(arg1, &ts));
8939 if (!is_error(ret)) {
8940 host_to_target_timespec(arg2, &ts);
8941 }
8942 break;
8943 }
8944#endif
8945#ifdef TARGET_NR_clock_getres
8946 case TARGET_NR_clock_getres:
8947 {
8948 struct timespec ts;
8949 ret = get_errno(clock_getres(arg1, &ts));
8950 if (!is_error(ret)) {
8951 host_to_target_timespec(arg2, &ts);
8952 }
8953 break;
8954 }
8955#endif
pbrook63d76512008-05-29 13:43:29 +00008956#ifdef TARGET_NR_clock_nanosleep
8957 case TARGET_NR_clock_nanosleep:
8958 {
8959 struct timespec ts;
8960 target_to_host_timespec(&ts, arg3);
8961 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8962 if (arg4)
8963 host_to_target_timespec(arg4, &ts);
8964 break;
8965 }
8966#endif
thsb5906f92007-03-19 13:32:45 +00008967
ths6f5b89a2007-03-02 20:48:00 +00008968#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8969 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008970 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8971 break;
ths6f5b89a2007-03-02 20:48:00 +00008972#endif
8973
ths3ae43202007-09-16 21:39:48 +00008974#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008975 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008976 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008977 break;
8978#endif
8979
ths3ae43202007-09-16 21:39:48 +00008980#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008981 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008982 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8983 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008984 break;
8985#endif
8986
ths4f2b1fe2007-06-21 21:57:12 +00008987#ifdef TARGET_NR_set_robust_list
8988 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008989 case TARGET_NR_get_robust_list:
8990 /* The ABI for supporting robust futexes has userspace pass
8991 * the kernel a pointer to a linked list which is updated by
8992 * userspace after the syscall; the list is walked by the kernel
8993 * when the thread exits. Since the linked list in QEMU guest
8994 * memory isn't a valid linked list for the host and we have
8995 * no way to reliably intercept the thread-death event, we can't
8996 * support these. Silently return ENOSYS so that guest userspace
8997 * falls back to a non-robust futex implementation (which should
8998 * be OK except in the corner case of the guest crashing while
8999 * holding a mutex that is shared with another process via
9000 * shared memory).
9001 */
9002 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009003#endif
9004
Peter Maydell1acae9f2013-07-02 14:04:12 +01009005#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009006 case TARGET_NR_utimensat:
9007 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009008 struct timespec *tsp, ts[2];
9009 if (!arg3) {
9010 tsp = NULL;
9011 } else {
9012 target_to_host_timespec(ts, arg3);
9013 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9014 tsp = ts;
9015 }
ths9007f0e2007-09-25 17:50:37 +00009016 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009017 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009018 else {
bellard579a97f2007-11-11 14:26:47 +00009019 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009020 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009021 goto fail;
9022 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009023 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009024 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009025 }
9026 }
9027 break;
9028#endif
pbrookbd0c5662008-05-29 14:34:11 +00009029 case TARGET_NR_futex:
9030 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9031 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009032#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009033 case TARGET_NR_inotify_init:
9034 ret = get_errno(sys_inotify_init());
9035 break;
9036#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009037#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009038#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9039 case TARGET_NR_inotify_init1:
9040 ret = get_errno(sys_inotify_init1(arg1));
9041 break;
9042#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009043#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009044#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009045 case TARGET_NR_inotify_add_watch:
9046 p = lock_user_string(arg2);
9047 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9048 unlock_user(p, arg2, 0);
9049 break;
9050#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009051#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009052 case TARGET_NR_inotify_rm_watch:
9053 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9054 break;
9055#endif
ths9007f0e2007-09-25 17:50:37 +00009056
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009057#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009058 case TARGET_NR_mq_open:
9059 {
9060 struct mq_attr posix_mq_attr;
9061
9062 p = lock_user_string(arg1 - 1);
9063 if (arg4 != 0)
9064 copy_from_user_mq_attr (&posix_mq_attr, arg4);
9065 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
9066 unlock_user (p, arg1, 0);
9067 }
9068 break;
9069
9070 case TARGET_NR_mq_unlink:
9071 p = lock_user_string(arg1 - 1);
9072 ret = get_errno(mq_unlink(p));
9073 unlock_user (p, arg1, 0);
9074 break;
9075
9076 case TARGET_NR_mq_timedsend:
9077 {
9078 struct timespec ts;
9079
9080 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9081 if (arg5 != 0) {
9082 target_to_host_timespec(&ts, arg5);
9083 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9084 host_to_target_timespec(arg5, &ts);
9085 }
9086 else
9087 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9088 unlock_user (p, arg2, arg3);
9089 }
9090 break;
9091
9092 case TARGET_NR_mq_timedreceive:
9093 {
9094 struct timespec ts;
9095 unsigned int prio;
9096
9097 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9098 if (arg5 != 0) {
9099 target_to_host_timespec(&ts, arg5);
9100 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9101 host_to_target_timespec(arg5, &ts);
9102 }
9103 else
9104 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9105 unlock_user (p, arg2, arg3);
9106 if (arg4 != 0)
9107 put_user_u32(prio, arg4);
9108 }
9109 break;
9110
9111 /* Not implemented for now... */
9112/* case TARGET_NR_mq_notify: */
9113/* break; */
9114
9115 case TARGET_NR_mq_getsetattr:
9116 {
9117 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9118 ret = 0;
9119 if (arg3 != 0) {
9120 ret = mq_getattr(arg1, &posix_mq_attr_out);
9121 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9122 }
9123 if (arg2 != 0) {
9124 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9125 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9126 }
9127
9128 }
9129 break;
9130#endif
9131
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309132#ifdef CONFIG_SPLICE
9133#ifdef TARGET_NR_tee
9134 case TARGET_NR_tee:
9135 {
9136 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9137 }
9138 break;
9139#endif
9140#ifdef TARGET_NR_splice
9141 case TARGET_NR_splice:
9142 {
9143 loff_t loff_in, loff_out;
9144 loff_t *ploff_in = NULL, *ploff_out = NULL;
9145 if(arg2) {
9146 get_user_u64(loff_in, arg2);
9147 ploff_in = &loff_in;
9148 }
9149 if(arg4) {
9150 get_user_u64(loff_out, arg2);
9151 ploff_out = &loff_out;
9152 }
9153 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9154 }
9155 break;
9156#endif
9157#ifdef TARGET_NR_vmsplice
9158 case TARGET_NR_vmsplice:
9159 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009160 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9161 if (vec != NULL) {
9162 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9163 unlock_iovec(vec, arg2, arg3, 0);
9164 } else {
9165 ret = -host_to_target_errno(errno);
9166 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309167 }
9168 break;
9169#endif
9170#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009171#ifdef CONFIG_EVENTFD
9172#if defined(TARGET_NR_eventfd)
9173 case TARGET_NR_eventfd:
9174 ret = get_errno(eventfd(arg1, 0));
9175 break;
9176#endif
9177#if defined(TARGET_NR_eventfd2)
9178 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009179 {
9180 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9181 if (arg2 & TARGET_O_NONBLOCK) {
9182 host_flags |= O_NONBLOCK;
9183 }
9184 if (arg2 & TARGET_O_CLOEXEC) {
9185 host_flags |= O_CLOEXEC;
9186 }
9187 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009188 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009189 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009190#endif
9191#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009192#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9193 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009194#if TARGET_ABI_BITS == 32
9195 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9196 target_offset64(arg5, arg6)));
9197#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009198 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009199#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009200 break;
9201#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009202#if defined(CONFIG_SYNC_FILE_RANGE)
9203#if defined(TARGET_NR_sync_file_range)
9204 case TARGET_NR_sync_file_range:
9205#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009206#if defined(TARGET_MIPS)
9207 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9208 target_offset64(arg5, arg6), arg7));
9209#else
Peter Maydellc727f472011-01-06 11:05:10 +00009210 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9211 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009212#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009213#else
9214 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9215#endif
9216 break;
9217#endif
9218#if defined(TARGET_NR_sync_file_range2)
9219 case TARGET_NR_sync_file_range2:
9220 /* This is like sync_file_range but the arguments are reordered */
9221#if TARGET_ABI_BITS == 32
9222 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9223 target_offset64(arg5, arg6), arg2));
9224#else
9225 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9226#endif
9227 break;
9228#endif
9229#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009230#if defined(CONFIG_EPOLL)
9231#if defined(TARGET_NR_epoll_create)
9232 case TARGET_NR_epoll_create:
9233 ret = get_errno(epoll_create(arg1));
9234 break;
9235#endif
9236#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9237 case TARGET_NR_epoll_create1:
9238 ret = get_errno(epoll_create1(arg1));
9239 break;
9240#endif
9241#if defined(TARGET_NR_epoll_ctl)
9242 case TARGET_NR_epoll_ctl:
9243 {
9244 struct epoll_event ep;
9245 struct epoll_event *epp = 0;
9246 if (arg4) {
9247 struct target_epoll_event *target_ep;
9248 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9249 goto efault;
9250 }
9251 ep.events = tswap32(target_ep->events);
9252 /* The epoll_data_t union is just opaque data to the kernel,
9253 * so we transfer all 64 bits across and need not worry what
9254 * actual data type it is.
9255 */
9256 ep.data.u64 = tswap64(target_ep->data.u64);
9257 unlock_user_struct(target_ep, arg4, 0);
9258 epp = &ep;
9259 }
9260 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9261 break;
9262 }
9263#endif
9264
9265#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9266#define IMPLEMENT_EPOLL_PWAIT
9267#endif
9268#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9269#if defined(TARGET_NR_epoll_wait)
9270 case TARGET_NR_epoll_wait:
9271#endif
9272#if defined(IMPLEMENT_EPOLL_PWAIT)
9273 case TARGET_NR_epoll_pwait:
9274#endif
9275 {
9276 struct target_epoll_event *target_ep;
9277 struct epoll_event *ep;
9278 int epfd = arg1;
9279 int maxevents = arg3;
9280 int timeout = arg4;
9281
9282 target_ep = lock_user(VERIFY_WRITE, arg2,
9283 maxevents * sizeof(struct target_epoll_event), 1);
9284 if (!target_ep) {
9285 goto efault;
9286 }
9287
9288 ep = alloca(maxevents * sizeof(struct epoll_event));
9289
9290 switch (num) {
9291#if defined(IMPLEMENT_EPOLL_PWAIT)
9292 case TARGET_NR_epoll_pwait:
9293 {
9294 target_sigset_t *target_set;
9295 sigset_t _set, *set = &_set;
9296
9297 if (arg5) {
9298 target_set = lock_user(VERIFY_READ, arg5,
9299 sizeof(target_sigset_t), 1);
9300 if (!target_set) {
9301 unlock_user(target_ep, arg2, 0);
9302 goto efault;
9303 }
9304 target_to_host_sigset(set, target_set);
9305 unlock_user(target_set, arg5, 0);
9306 } else {
9307 set = NULL;
9308 }
9309
9310 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9311 break;
9312 }
9313#endif
9314#if defined(TARGET_NR_epoll_wait)
9315 case TARGET_NR_epoll_wait:
9316 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9317 break;
9318#endif
9319 default:
9320 ret = -TARGET_ENOSYS;
9321 }
9322 if (!is_error(ret)) {
9323 int i;
9324 for (i = 0; i < ret; i++) {
9325 target_ep[i].events = tswap32(ep[i].events);
9326 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9327 }
9328 }
9329 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9330 break;
9331 }
9332#endif
9333#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009334#ifdef TARGET_NR_prlimit64
9335 case TARGET_NR_prlimit64:
9336 {
9337 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9338 struct target_rlimit64 *target_rnew, *target_rold;
9339 struct host_rlimit64 rnew, rold, *rnewp = 0;
9340 if (arg3) {
9341 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9342 goto efault;
9343 }
9344 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9345 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9346 unlock_user_struct(target_rnew, arg3, 0);
9347 rnewp = &rnew;
9348 }
9349
9350 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9351 if (!is_error(ret) && arg4) {
9352 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9353 goto efault;
9354 }
9355 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9356 target_rold->rlim_max = tswap64(rold.rlim_max);
9357 unlock_user_struct(target_rold, arg4, 1);
9358 }
9359 break;
9360 }
9361#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009362#ifdef TARGET_NR_gethostname
9363 case TARGET_NR_gethostname:
9364 {
9365 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9366 if (name) {
9367 ret = get_errno(gethostname(name, arg2));
9368 unlock_user(name, arg1, arg2);
9369 } else {
9370 ret = -TARGET_EFAULT;
9371 }
9372 break;
9373 }
9374#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009375#ifdef TARGET_NR_atomic_cmpxchg_32
9376 case TARGET_NR_atomic_cmpxchg_32:
9377 {
9378 /* should use start_exclusive from main.c */
9379 abi_ulong mem_value;
9380 if (get_user_u32(mem_value, arg6)) {
9381 target_siginfo_t info;
9382 info.si_signo = SIGSEGV;
9383 info.si_errno = 0;
9384 info.si_code = TARGET_SEGV_MAPERR;
9385 info._sifields._sigfault._addr = arg6;
9386 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9387 ret = 0xdeadbeef;
9388
9389 }
9390 if (mem_value == arg2)
9391 put_user_u32(arg1, arg6);
9392 ret = mem_value;
9393 break;
9394 }
9395#endif
9396#ifdef TARGET_NR_atomic_barrier
9397 case TARGET_NR_atomic_barrier:
9398 {
9399 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009400 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009401 break;
9402 }
9403#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009404
9405#ifdef TARGET_NR_timer_create
9406 case TARGET_NR_timer_create:
9407 {
9408 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9409
9410 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9411 struct target_sigevent *ptarget_sevp;
9412 struct target_timer_t *ptarget_timer;
9413
9414 int clkid = arg1;
9415 int timer_index = next_free_host_timer();
9416
9417 if (timer_index < 0) {
9418 ret = -TARGET_EAGAIN;
9419 } else {
9420 timer_t *phtimer = g_posix_timers + timer_index;
9421
9422 if (arg2) {
9423 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9424 goto efault;
9425 }
9426
9427 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9428 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9429
9430 phost_sevp = &host_sevp;
9431 }
9432
9433 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9434 if (ret) {
9435 phtimer = NULL;
9436 } else {
9437 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9438 goto efault;
9439 }
9440 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9441 unlock_user_struct(ptarget_timer, arg3, 1);
9442 }
9443 }
9444 break;
9445 }
9446#endif
9447
9448#ifdef TARGET_NR_timer_settime
9449 case TARGET_NR_timer_settime:
9450 {
9451 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9452 * struct itimerspec * old_value */
9453 arg1 &= 0xffff;
9454 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9455 ret = -TARGET_EINVAL;
9456 } else {
9457 timer_t htimer = g_posix_timers[arg1];
9458 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9459
9460 target_to_host_itimerspec(&hspec_new, arg3);
9461 ret = get_errno(
9462 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9463 host_to_target_itimerspec(arg2, &hspec_old);
9464 }
9465 break;
9466 }
9467#endif
9468
9469#ifdef TARGET_NR_timer_gettime
9470 case TARGET_NR_timer_gettime:
9471 {
9472 /* args: timer_t timerid, struct itimerspec *curr_value */
9473 arg1 &= 0xffff;
9474 if (!arg2) {
9475 return -TARGET_EFAULT;
9476 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9477 ret = -TARGET_EINVAL;
9478 } else {
9479 timer_t htimer = g_posix_timers[arg1];
9480 struct itimerspec hspec;
9481 ret = get_errno(timer_gettime(htimer, &hspec));
9482
9483 if (host_to_target_itimerspec(arg2, &hspec)) {
9484 ret = -TARGET_EFAULT;
9485 }
9486 }
9487 break;
9488 }
9489#endif
9490
9491#ifdef TARGET_NR_timer_getoverrun
9492 case TARGET_NR_timer_getoverrun:
9493 {
9494 /* args: timer_t timerid */
9495 arg1 &= 0xffff;
9496 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9497 ret = -TARGET_EINVAL;
9498 } else {
9499 timer_t htimer = g_posix_timers[arg1];
9500 ret = get_errno(timer_getoverrun(htimer));
9501 }
9502 break;
9503 }
9504#endif
9505
9506#ifdef TARGET_NR_timer_delete
9507 case TARGET_NR_timer_delete:
9508 {
9509 /* args: timer_t timerid */
9510 arg1 &= 0xffff;
9511 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9512 ret = -TARGET_EINVAL;
9513 } else {
9514 timer_t htimer = g_posix_timers[arg1];
9515 ret = get_errno(timer_delete(htimer));
9516 g_posix_timers[arg1] = 0;
9517 }
9518 break;
9519 }
9520#endif
9521
bellard31e31b82003-02-18 22:55:36 +00009522 default:
9523 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009524 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009525#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 +00009526 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009527#endif
ths0da46a62007-10-20 20:23:07 +00009528 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009529 break;
9530 }
bellard579a97f2007-11-11 14:26:47 +00009531fail:
bellardc573ff62004-01-04 15:51:36 +00009532#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009533 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009534#endif
thsb92c47c2007-11-01 00:07:38 +00009535 if(do_strace)
9536 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009537 return ret;
bellard579a97f2007-11-11 14:26:47 +00009538efault:
9539 ret = -TARGET_EFAULT;
9540 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009541}