blob: a50229d0d72fc68966515fcf2bc308b833a3c032 [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{
Alexander Graf1a49ef22012-05-01 16:30:28 +01005095#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber0429a972013-08-26 18:14:44 +02005096 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5097 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005098#endif
5099 FILE *fp;
5100 char *line = NULL;
5101 size_t len = 0;
5102 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005103
Alexander Graf1a49ef22012-05-01 16:30:28 +01005104 fp = fopen("/proc/self/maps", "r");
5105 if (fp == NULL) {
5106 return -EACCES;
5107 }
5108
5109 while ((read = getline(&line, &len, fp)) != -1) {
5110 int fields, dev_maj, dev_min, inode;
5111 uint64_t min, max, offset;
5112 char flag_r, flag_w, flag_x, flag_p;
5113 char path[512] = "";
5114 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5115 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5116 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5117
5118 if ((fields < 10) || (fields > 11)) {
5119 continue;
5120 }
5121 if (!strncmp(path, "[stack]", 7)) {
5122 continue;
5123 }
5124 if (h2g_valid(min) && h2g_valid(max)) {
5125 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005126 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01005127 h2g(min), h2g(max), flag_r, flag_w,
5128 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005129 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005130 }
5131 }
5132
5133 free(line);
5134 fclose(fp);
5135
5136#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005137 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5138 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005139 (unsigned long long)(ts->info->start_stack +
5140 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005141 (unsigned long long)0);
5142#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005143
5144 return 0;
5145}
5146
Alexander Graf480b8e72011-11-02 20:23:25 +01005147static int open_self_stat(void *cpu_env, int fd)
5148{
Andreas Färber0429a972013-08-26 18:14:44 +02005149 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5150 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005151 abi_ulong start_stack = ts->info->start_stack;
5152 int i;
5153
5154 for (i = 0; i < 44; i++) {
5155 char buf[128];
5156 int len;
5157 uint64_t val = 0;
5158
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005159 if (i == 0) {
5160 /* pid */
5161 val = getpid();
5162 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5163 } else if (i == 1) {
5164 /* app name */
5165 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5166 } else if (i == 27) {
5167 /* stack bottom */
5168 val = start_stack;
5169 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5170 } else {
5171 /* for the rest, there is MasterCard */
5172 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005173 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005174
Alexander Graf480b8e72011-11-02 20:23:25 +01005175 len = strlen(buf);
5176 if (write(fd, buf, len) != len) {
5177 return -1;
5178 }
5179 }
5180
5181 return 0;
5182}
5183
Alexander Graf257450e2011-11-02 20:23:26 +01005184static int open_self_auxv(void *cpu_env, int fd)
5185{
Andreas Färber0429a972013-08-26 18:14:44 +02005186 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5187 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005188 abi_ulong auxv = ts->info->saved_auxv;
5189 abi_ulong len = ts->info->auxv_len;
5190 char *ptr;
5191
5192 /*
5193 * Auxiliary vector is stored in target process stack.
5194 * read in whole auxv vector and copy it to file
5195 */
5196 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5197 if (ptr != NULL) {
5198 while (len > 0) {
5199 ssize_t r;
5200 r = write(fd, ptr, len);
5201 if (r <= 0) {
5202 break;
5203 }
5204 len -= r;
5205 ptr += r;
5206 }
5207 lseek(fd, 0, SEEK_SET);
5208 unlock_user(ptr, auxv, len);
5209 }
5210
5211 return 0;
5212}
5213
Andreas Schwab463d8e72013-07-02 14:04:12 +01005214static int is_proc_myself(const char *filename, const char *entry)
5215{
5216 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5217 filename += strlen("/proc/");
5218 if (!strncmp(filename, "self/", strlen("self/"))) {
5219 filename += strlen("self/");
5220 } else if (*filename >= '1' && *filename <= '9') {
5221 char myself[80];
5222 snprintf(myself, sizeof(myself), "%d/", getpid());
5223 if (!strncmp(filename, myself, strlen(myself))) {
5224 filename += strlen(myself);
5225 } else {
5226 return 0;
5227 }
5228 } else {
5229 return 0;
5230 }
5231 if (!strcmp(filename, entry)) {
5232 return 1;
5233 }
5234 }
5235 return 0;
5236}
5237
Laurent Vivierde6b9932013-08-30 01:46:40 +02005238#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5239static int is_proc(const char *filename, const char *entry)
5240{
5241 return strcmp(filename, entry) == 0;
5242}
5243
5244static int open_net_route(void *cpu_env, int fd)
5245{
5246 FILE *fp;
5247 char *line = NULL;
5248 size_t len = 0;
5249 ssize_t read;
5250
5251 fp = fopen("/proc/net/route", "r");
5252 if (fp == NULL) {
5253 return -EACCES;
5254 }
5255
5256 /* read header */
5257
5258 read = getline(&line, &len, fp);
5259 dprintf(fd, "%s", line);
5260
5261 /* read routes */
5262
5263 while ((read = getline(&line, &len, fp)) != -1) {
5264 char iface[16];
5265 uint32_t dest, gw, mask;
5266 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5267 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5268 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5269 &mask, &mtu, &window, &irtt);
5270 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5271 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5272 metric, tswap32(mask), mtu, window, irtt);
5273 }
5274
5275 free(line);
5276 fclose(fp);
5277
5278 return 0;
5279}
5280#endif
5281
Alexander Graf3be14d02011-11-02 20:23:23 +01005282static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5283{
5284 struct fake_open {
5285 const char *filename;
5286 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005287 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005288 };
5289 const struct fake_open *fake_open;
5290 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005291 { "maps", open_self_maps, is_proc_myself },
5292 { "stat", open_self_stat, is_proc_myself },
5293 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005294 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005295#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5296 { "/proc/net/route", open_net_route, is_proc },
5297#endif
5298 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005299 };
5300
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005301 if (is_proc_myself(pathname, "exe")) {
5302 int execfd = qemu_getauxval(AT_EXECFD);
5303 return execfd ? execfd : get_errno(open(exec_path, flags, mode));
5304 }
5305
Alexander Graf3be14d02011-11-02 20:23:23 +01005306 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005307 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005308 break;
5309 }
5310 }
5311
5312 if (fake_open->filename) {
5313 const char *tmpdir;
5314 char filename[PATH_MAX];
5315 int fd, r;
5316
5317 /* create temporary file to map stat to */
5318 tmpdir = getenv("TMPDIR");
5319 if (!tmpdir)
5320 tmpdir = "/tmp";
5321 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5322 fd = mkstemp(filename);
5323 if (fd < 0) {
5324 return fd;
5325 }
5326 unlink(filename);
5327
5328 if ((r = fake_open->fill(cpu_env, fd))) {
5329 close(fd);
5330 return r;
5331 }
5332 lseek(fd, 0, SEEK_SET);
5333
5334 return fd;
5335 }
5336
5337 return get_errno(open(path(pathname), flags, mode));
5338}
5339
ths0da46a62007-10-20 20:23:07 +00005340/* do_syscall() should always have a single exit point at the end so
5341 that actions, such as logging of syscall results, can be performed.
5342 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005343abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5344 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005345 abi_long arg5, abi_long arg6, abi_long arg7,
5346 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005347{
Andreas Färber182735e2013-05-29 22:29:20 +02005348 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005349 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005350 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005351 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005352 void *p;
ths3b46e622007-09-17 08:09:54 +00005353
bellard72f03902003-02-18 23:33:18 +00005354#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005355 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005356#endif
thsb92c47c2007-11-01 00:07:38 +00005357 if(do_strace)
5358 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5359
bellard31e31b82003-02-18 22:55:36 +00005360 switch(num) {
5361 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005362 /* In old applications this may be used to implement _exit(2).
5363 However in threaded applictions it is used for thread termination,
5364 and _exit_group is used for application termination.
5365 Do thread termination if we have more then one thread. */
5366 /* FIXME: This probably breaks if a signal arrives. We should probably
5367 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005368 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005369 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005370
Andreas Färber9b056fc2013-06-24 23:53:10 +02005371 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005372 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005373 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005374 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005375 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005376 if (ts->child_tidptr) {
5377 put_user_u32(0, ts->child_tidptr);
5378 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5379 NULL, NULL, 0);
5380 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005381 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005382 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005383 g_free(ts);
5384 pthread_exit(NULL);
5385 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005386#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005387 _mcleanup();
5388#endif
bellarde9009672005-04-26 20:42:36 +00005389 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005390 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005391 ret = 0; /* avoid warning */
5392 break;
5393 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005394 if (arg3 == 0)
5395 ret = 0;
5396 else {
5397 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5398 goto efault;
5399 ret = get_errno(read(arg1, p, arg3));
5400 unlock_user(p, arg2, ret);
5401 }
bellard31e31b82003-02-18 22:55:36 +00005402 break;
5403 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005404 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5405 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005406 ret = get_errno(write(arg1, p, arg3));
5407 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005408 break;
5409 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005410 if (!(p = lock_user_string(arg1)))
5411 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005412 ret = get_errno(do_open(cpu_env, p,
5413 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5414 arg3));
pbrook53a59602006-03-25 19:31:22 +00005415 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005416 break;
ths82424832007-09-24 09:21:55 +00005417#if defined(TARGET_NR_openat) && defined(__NR_openat)
5418 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005419 if (!(p = lock_user_string(arg2)))
5420 goto efault;
5421 ret = get_errno(sys_openat(arg1,
5422 path(p),
5423 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5424 arg4));
5425 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005426 break;
5427#endif
bellard31e31b82003-02-18 22:55:36 +00005428 case TARGET_NR_close:
5429 ret = get_errno(close(arg1));
5430 break;
5431 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005432 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005433 break;
5434 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005435 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005436 break;
thse5febef2007-04-01 18:31:35 +00005437#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005438 case TARGET_NR_waitpid:
5439 {
pbrook53a59602006-03-25 19:31:22 +00005440 int status;
5441 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005442 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005443 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005444 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005445 }
5446 break;
thse5febef2007-04-01 18:31:35 +00005447#endif
pbrookf0cbb612008-05-30 18:20:05 +00005448#ifdef TARGET_NR_waitid
5449 case TARGET_NR_waitid:
5450 {
5451 siginfo_t info;
5452 info.si_pid = 0;
5453 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5454 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005455 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005456 goto efault;
5457 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005458 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005459 }
5460 }
5461 break;
5462#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005463#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005464 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005465 if (!(p = lock_user_string(arg1)))
5466 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005467 ret = get_errno(creat(p, arg2));
5468 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005469 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005470#endif
bellard31e31b82003-02-18 22:55:36 +00005471 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005472 {
5473 void * p2;
5474 p = lock_user_string(arg1);
5475 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005476 if (!p || !p2)
5477 ret = -TARGET_EFAULT;
5478 else
5479 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005480 unlock_user(p2, arg2, 0);
5481 unlock_user(p, arg1, 0);
5482 }
bellard31e31b82003-02-18 22:55:36 +00005483 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005484#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005485 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005486 {
5487 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005488 if (!arg2 || !arg4)
5489 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005490 p = lock_user_string(arg2);
5491 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005492 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005493 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005494 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005495 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005496 unlock_user(p, arg2, 0);
5497 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005498 }
5499 break;
5500#endif
bellard31e31b82003-02-18 22:55:36 +00005501 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005502 if (!(p = lock_user_string(arg1)))
5503 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005504 ret = get_errno(unlink(p));
5505 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005506 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005507#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005508 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005509 if (!(p = lock_user_string(arg2)))
5510 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005511 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005512 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005513 break;
balrogb7d35e62007-12-12 00:40:24 +00005514#endif
bellard31e31b82003-02-18 22:55:36 +00005515 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005516 {
5517 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005518 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005519 abi_ulong gp;
5520 abi_ulong guest_argp;
5521 abi_ulong guest_envp;
5522 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005523 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005524 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005525
bellardf7341ff2003-03-30 21:00:25 +00005526 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005527 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005528 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005529 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005530 goto efault;
ths03aa1972007-12-02 06:28:08 +00005531 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005532 break;
bellard7854b052003-03-29 17:22:23 +00005533 argc++;
bellard2f619692007-11-16 10:46:05 +00005534 }
bellardf7341ff2003-03-30 21:00:25 +00005535 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005536 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005537 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005538 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005539 goto efault;
ths03aa1972007-12-02 06:28:08 +00005540 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005541 break;
bellard7854b052003-03-29 17:22:23 +00005542 envc++;
bellard2f619692007-11-16 10:46:05 +00005543 }
bellard7854b052003-03-29 17:22:23 +00005544
bellardf7341ff2003-03-30 21:00:25 +00005545 argp = alloca((argc + 1) * sizeof(void *));
5546 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005547
pbrookda94d262008-05-30 18:24:00 +00005548 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005549 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005550 if (get_user_ual(addr, gp))
5551 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005552 if (!addr)
5553 break;
bellard2f619692007-11-16 10:46:05 +00005554 if (!(*q = lock_user_string(addr)))
5555 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005556 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005557 }
bellardf7341ff2003-03-30 21:00:25 +00005558 *q = NULL;
5559
pbrookda94d262008-05-30 18:24:00 +00005560 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005561 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005562 if (get_user_ual(addr, gp))
5563 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005564 if (!addr)
5565 break;
bellard2f619692007-11-16 10:46:05 +00005566 if (!(*q = lock_user_string(addr)))
5567 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005568 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005569 }
bellardf7341ff2003-03-30 21:00:25 +00005570 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005571
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005572 /* This case will not be caught by the host's execve() if its
5573 page size is bigger than the target's. */
5574 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5575 ret = -TARGET_E2BIG;
5576 goto execve_end;
5577 }
bellard2f619692007-11-16 10:46:05 +00005578 if (!(p = lock_user_string(arg1)))
5579 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005580 ret = get_errno(execve(p, argp, envp));
5581 unlock_user(p, arg1, 0);
5582
bellard2f619692007-11-16 10:46:05 +00005583 goto execve_end;
5584
5585 execve_efault:
5586 ret = -TARGET_EFAULT;
5587
5588 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005589 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005590 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005591 if (get_user_ual(addr, gp)
5592 || !addr)
5593 break;
pbrook53a59602006-03-25 19:31:22 +00005594 unlock_user(*q, addr, 0);
5595 }
5596 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005597 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005598 if (get_user_ual(addr, gp)
5599 || !addr)
5600 break;
pbrook53a59602006-03-25 19:31:22 +00005601 unlock_user(*q, addr, 0);
5602 }
bellard7854b052003-03-29 17:22:23 +00005603 }
bellard31e31b82003-02-18 22:55:36 +00005604 break;
5605 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005606 if (!(p = lock_user_string(arg1)))
5607 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005608 ret = get_errno(chdir(p));
5609 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005610 break;
bellarda315a142005-01-30 22:59:18 +00005611#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005612 case TARGET_NR_time:
5613 {
pbrook53a59602006-03-25 19:31:22 +00005614 time_t host_time;
5615 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005616 if (!is_error(ret)
5617 && arg1
5618 && put_user_sal(host_time, arg1))
5619 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005620 }
5621 break;
bellarda315a142005-01-30 22:59:18 +00005622#endif
bellard31e31b82003-02-18 22:55:36 +00005623 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005624 if (!(p = lock_user_string(arg1)))
5625 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005626 ret = get_errno(mknod(p, arg2, arg3));
5627 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005628 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005629#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005630 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005631 if (!(p = lock_user_string(arg2)))
5632 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005633 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005634 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005635 break;
5636#endif
bellard31e31b82003-02-18 22:55:36 +00005637 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005638 if (!(p = lock_user_string(arg1)))
5639 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005640 ret = get_errno(chmod(p, arg2));
5641 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005642 break;
bellardebc05482003-09-30 21:08:41 +00005643#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005644 case TARGET_NR_break:
5645 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005646#endif
5647#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005648 case TARGET_NR_oldstat:
5649 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005650#endif
bellard31e31b82003-02-18 22:55:36 +00005651 case TARGET_NR_lseek:
5652 ret = get_errno(lseek(arg1, arg2, arg3));
5653 break;
Richard Henderson92317332010-05-03 10:07:53 -07005654#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5655 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005656 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005657 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005658 ret = get_errno(getpid());
5659 break;
Richard Henderson92317332010-05-03 10:07:53 -07005660#endif
5661#ifdef TARGET_NR_getpid
5662 case TARGET_NR_getpid:
5663 ret = get_errno(getpid());
5664 break;
5665#endif
bellard31e31b82003-02-18 22:55:36 +00005666 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01005667 {
5668 /* need to look at the data field */
5669 void *p2, *p3;
5670
5671 if (arg1) {
5672 p = lock_user_string(arg1);
5673 if (!p) {
5674 goto efault;
5675 }
5676 } else {
5677 p = NULL;
5678 }
5679
5680 p2 = lock_user_string(arg2);
5681 if (!p2) {
5682 if (arg1) {
5683 unlock_user(p, arg1, 0);
5684 }
5685 goto efault;
5686 }
5687
5688 if (arg3) {
5689 p3 = lock_user_string(arg3);
5690 if (!p3) {
5691 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005692 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01005693 }
5694 unlock_user(p2, arg2, 0);
5695 goto efault;
5696 }
5697 } else {
5698 p3 = NULL;
5699 }
5700
5701 /* FIXME - arg5 should be locked, but it isn't clear how to
5702 * do that since it's not guaranteed to be a NULL-terminated
5703 * string.
5704 */
5705 if (!arg5) {
5706 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
5707 } else {
5708 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
5709 }
5710 ret = get_errno(ret);
5711
5712 if (arg1) {
5713 unlock_user(p, arg1, 0);
5714 }
5715 unlock_user(p2, arg2, 0);
5716 if (arg3) {
5717 unlock_user(p3, arg3, 0);
5718 }
5719 }
5720 break;
thse5febef2007-04-01 18:31:35 +00005721#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005722 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005723 if (!(p = lock_user_string(arg1)))
5724 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005725 ret = get_errno(umount(p));
5726 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005727 break;
thse5febef2007-04-01 18:31:35 +00005728#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005729#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005730 case TARGET_NR_stime:
5731 {
pbrook53a59602006-03-25 19:31:22 +00005732 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005733 if (get_user_sal(host_time, arg1))
5734 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005735 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005736 }
5737 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005738#endif
bellard31e31b82003-02-18 22:55:36 +00005739 case TARGET_NR_ptrace:
5740 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005741#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005742 case TARGET_NR_alarm:
5743 ret = alarm(arg1);
5744 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005745#endif
bellardebc05482003-09-30 21:08:41 +00005746#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005747 case TARGET_NR_oldfstat:
5748 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005749#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005750#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005751 case TARGET_NR_pause:
5752 ret = get_errno(pause());
5753 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005754#endif
thse5febef2007-04-01 18:31:35 +00005755#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005756 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005757 {
pbrook53a59602006-03-25 19:31:22 +00005758 struct utimbuf tbuf, *host_tbuf;
5759 struct target_utimbuf *target_tbuf;
5760 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005761 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5762 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005763 tbuf.actime = tswapal(target_tbuf->actime);
5764 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005765 unlock_user_struct(target_tbuf, arg2, 0);
5766 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005767 } else {
pbrook53a59602006-03-25 19:31:22 +00005768 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005769 }
bellard579a97f2007-11-11 14:26:47 +00005770 if (!(p = lock_user_string(arg1)))
5771 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005772 ret = get_errno(utime(p, host_tbuf));
5773 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005774 }
5775 break;
thse5febef2007-04-01 18:31:35 +00005776#endif
bellard978a66f2004-12-06 22:58:05 +00005777 case TARGET_NR_utimes:
5778 {
bellard978a66f2004-12-06 22:58:05 +00005779 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005780 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005781 if (copy_from_user_timeval(&tv[0], arg2)
5782 || copy_from_user_timeval(&tv[1],
5783 arg2 + sizeof(struct target_timeval)))
5784 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005785 tvp = tv;
5786 } else {
5787 tvp = NULL;
5788 }
bellard579a97f2007-11-11 14:26:47 +00005789 if (!(p = lock_user_string(arg1)))
5790 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005791 ret = get_errno(utimes(p, tvp));
5792 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005793 }
5794 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005795#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005796 case TARGET_NR_futimesat:
5797 {
5798 struct timeval *tvp, tv[2];
5799 if (arg3) {
5800 if (copy_from_user_timeval(&tv[0], arg3)
5801 || copy_from_user_timeval(&tv[1],
5802 arg3 + sizeof(struct target_timeval)))
5803 goto efault;
5804 tvp = tv;
5805 } else {
5806 tvp = NULL;
5807 }
5808 if (!(p = lock_user_string(arg2)))
5809 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005810 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005811 unlock_user(p, arg2, 0);
5812 }
5813 break;
5814#endif
bellardebc05482003-09-30 21:08:41 +00005815#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005816 case TARGET_NR_stty:
5817 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005818#endif
5819#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005820 case TARGET_NR_gtty:
5821 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005822#endif
bellard31e31b82003-02-18 22:55:36 +00005823 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005824 if (!(p = lock_user_string(arg1)))
5825 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005826 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005827 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005828 break;
ths92a34c12007-09-24 09:27:49 +00005829#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5830 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005831 if (!(p = lock_user_string(arg2)))
5832 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005833 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005834 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005835 break;
5836#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005837#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005838 case TARGET_NR_nice:
5839 ret = get_errno(nice(arg1));
5840 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005841#endif
bellardebc05482003-09-30 21:08:41 +00005842#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005843 case TARGET_NR_ftime:
5844 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005845#endif
bellard31e31b82003-02-18 22:55:36 +00005846 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005847 sync();
5848 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005849 break;
5850 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005851 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005852 break;
5853 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005854 {
5855 void *p2;
5856 p = lock_user_string(arg1);
5857 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005858 if (!p || !p2)
5859 ret = -TARGET_EFAULT;
5860 else
5861 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005862 unlock_user(p2, arg2, 0);
5863 unlock_user(p, arg1, 0);
5864 }
bellard31e31b82003-02-18 22:55:36 +00005865 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005866#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005867 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005868 {
bellard579a97f2007-11-11 14:26:47 +00005869 void *p2;
ths722183f2007-09-24 09:24:37 +00005870 p = lock_user_string(arg2);
5871 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005872 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005873 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005874 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005875 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005876 unlock_user(p2, arg4, 0);
5877 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005878 }
5879 break;
5880#endif
bellard31e31b82003-02-18 22:55:36 +00005881 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005882 if (!(p = lock_user_string(arg1)))
5883 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005884 ret = get_errno(mkdir(p, arg2));
5885 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005886 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005887#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005888 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005889 if (!(p = lock_user_string(arg2)))
5890 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005891 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005892 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005893 break;
5894#endif
bellard31e31b82003-02-18 22:55:36 +00005895 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005896 if (!(p = lock_user_string(arg1)))
5897 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005898 ret = get_errno(rmdir(p));
5899 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005900 break;
5901 case TARGET_NR_dup:
5902 ret = get_errno(dup(arg1));
5903 break;
5904 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005905 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005906 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005907#ifdef TARGET_NR_pipe2
5908 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005909 ret = do_pipe(cpu_env, arg1,
5910 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005911 break;
5912#endif
bellard31e31b82003-02-18 22:55:36 +00005913 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005914 {
pbrook53a59602006-03-25 19:31:22 +00005915 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005916 struct tms tms;
5917 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005918 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005919 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5920 if (!tmsp)
5921 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005922 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5923 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5924 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5925 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005926 }
bellardc596ed12003-07-13 17:32:31 +00005927 if (!is_error(ret))
5928 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005929 }
5930 break;
bellardebc05482003-09-30 21:08:41 +00005931#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005932 case TARGET_NR_prof:
5933 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005934#endif
thse5febef2007-04-01 18:31:35 +00005935#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005936 case TARGET_NR_signal:
5937 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005938#endif
bellard31e31b82003-02-18 22:55:36 +00005939 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005940 if (arg1 == 0) {
5941 ret = get_errno(acct(NULL));
5942 } else {
5943 if (!(p = lock_user_string(arg1)))
5944 goto efault;
5945 ret = get_errno(acct(path(p)));
5946 unlock_user(p, arg1, 0);
5947 }
pbrook24836682006-04-16 14:14:53 +00005948 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005949#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005950 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005951 if (!(p = lock_user_string(arg1)))
5952 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005953 ret = get_errno(umount2(p, arg2));
5954 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005955 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005956#endif
bellardebc05482003-09-30 21:08:41 +00005957#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005958 case TARGET_NR_lock:
5959 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005960#endif
bellard31e31b82003-02-18 22:55:36 +00005961 case TARGET_NR_ioctl:
5962 ret = do_ioctl(arg1, arg2, arg3);
5963 break;
5964 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005965 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005966 break;
bellardebc05482003-09-30 21:08:41 +00005967#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005968 case TARGET_NR_mpx:
5969 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005970#endif
bellard31e31b82003-02-18 22:55:36 +00005971 case TARGET_NR_setpgid:
5972 ret = get_errno(setpgid(arg1, arg2));
5973 break;
bellardebc05482003-09-30 21:08:41 +00005974#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005975 case TARGET_NR_ulimit:
5976 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005977#endif
5978#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005979 case TARGET_NR_oldolduname:
5980 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005981#endif
bellard31e31b82003-02-18 22:55:36 +00005982 case TARGET_NR_umask:
5983 ret = get_errno(umask(arg1));
5984 break;
5985 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00005986 if (!(p = lock_user_string(arg1)))
5987 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005988 ret = get_errno(chroot(p));
5989 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005990 break;
5991 case TARGET_NR_ustat:
5992 goto unimplemented;
5993 case TARGET_NR_dup2:
5994 ret = get_errno(dup2(arg1, arg2));
5995 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005996#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5997 case TARGET_NR_dup3:
5998 ret = get_errno(dup3(arg1, arg2, arg3));
5999 break;
6000#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006001#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006002 case TARGET_NR_getppid:
6003 ret = get_errno(getppid());
6004 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006005#endif
bellard31e31b82003-02-18 22:55:36 +00006006 case TARGET_NR_getpgrp:
6007 ret = get_errno(getpgrp());
6008 break;
6009 case TARGET_NR_setsid:
6010 ret = get_errno(setsid());
6011 break;
thse5febef2007-04-01 18:31:35 +00006012#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006013 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006014 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006015#if defined(TARGET_ALPHA)
6016 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006017 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006018 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006019 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6020 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006021 act._sa_handler = old_act->_sa_handler;
6022 target_siginitset(&act.sa_mask, old_act->sa_mask);
6023 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006024 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006025 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006026 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006027 }
6028 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006029 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006030 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6031 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006032 old_act->_sa_handler = oact._sa_handler;
6033 old_act->sa_mask = oact.sa_mask.sig[0];
6034 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006035 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006036 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006037#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006038 struct target_sigaction act, oact, *pact, *old_act;
6039
6040 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006041 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6042 goto efault;
bellard106ec872006-06-27 21:08:10 +00006043 act._sa_handler = old_act->_sa_handler;
6044 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6045 act.sa_flags = old_act->sa_flags;
6046 unlock_user_struct(old_act, arg2, 0);
6047 pact = &act;
6048 } else {
6049 pact = NULL;
6050 }
6051
6052 ret = get_errno(do_sigaction(arg1, pact, &oact));
6053
6054 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006055 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6056 goto efault;
bellard106ec872006-06-27 21:08:10 +00006057 old_act->_sa_handler = oact._sa_handler;
6058 old_act->sa_flags = oact.sa_flags;
6059 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6060 old_act->sa_mask.sig[1] = 0;
6061 old_act->sa_mask.sig[2] = 0;
6062 old_act->sa_mask.sig[3] = 0;
6063 unlock_user_struct(old_act, arg3, 1);
6064 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006065#else
6066 struct target_old_sigaction *old_act;
6067 struct target_sigaction act, oact, *pact;
6068 if (arg2) {
6069 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6070 goto efault;
6071 act._sa_handler = old_act->_sa_handler;
6072 target_siginitset(&act.sa_mask, old_act->sa_mask);
6073 act.sa_flags = old_act->sa_flags;
6074 act.sa_restorer = old_act->sa_restorer;
6075 unlock_user_struct(old_act, arg2, 0);
6076 pact = &act;
6077 } else {
6078 pact = NULL;
6079 }
6080 ret = get_errno(do_sigaction(arg1, pact, &oact));
6081 if (!is_error(ret) && arg3) {
6082 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6083 goto efault;
6084 old_act->_sa_handler = oact._sa_handler;
6085 old_act->sa_mask = oact.sa_mask.sig[0];
6086 old_act->sa_flags = oact.sa_flags;
6087 old_act->sa_restorer = oact.sa_restorer;
6088 unlock_user_struct(old_act, arg3, 1);
6089 }
ths388bb212007-05-13 13:58:00 +00006090#endif
bellard31e31b82003-02-18 22:55:36 +00006091 }
6092 break;
thse5febef2007-04-01 18:31:35 +00006093#endif
bellard66fb9762003-03-23 01:06:05 +00006094 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006095 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006096#if defined(TARGET_ALPHA)
6097 struct target_sigaction act, oact, *pact = 0;
6098 struct target_rt_sigaction *rt_act;
6099 /* ??? arg4 == sizeof(sigset_t). */
6100 if (arg2) {
6101 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6102 goto efault;
6103 act._sa_handler = rt_act->_sa_handler;
6104 act.sa_mask = rt_act->sa_mask;
6105 act.sa_flags = rt_act->sa_flags;
6106 act.sa_restorer = arg5;
6107 unlock_user_struct(rt_act, arg2, 0);
6108 pact = &act;
6109 }
6110 ret = get_errno(do_sigaction(arg1, pact, &oact));
6111 if (!is_error(ret) && arg3) {
6112 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6113 goto efault;
6114 rt_act->_sa_handler = oact._sa_handler;
6115 rt_act->sa_mask = oact.sa_mask;
6116 rt_act->sa_flags = oact.sa_flags;
6117 unlock_user_struct(rt_act, arg3, 1);
6118 }
6119#else
pbrook53a59602006-03-25 19:31:22 +00006120 struct target_sigaction *act;
6121 struct target_sigaction *oact;
6122
bellard579a97f2007-11-11 14:26:47 +00006123 if (arg2) {
6124 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6125 goto efault;
6126 } else
pbrook53a59602006-03-25 19:31:22 +00006127 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006128 if (arg3) {
6129 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6130 ret = -TARGET_EFAULT;
6131 goto rt_sigaction_fail;
6132 }
6133 } else
pbrook53a59602006-03-25 19:31:22 +00006134 oact = NULL;
6135 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006136 rt_sigaction_fail:
6137 if (act)
pbrook53a59602006-03-25 19:31:22 +00006138 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006139 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006140 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006141#endif
pbrook53a59602006-03-25 19:31:22 +00006142 }
bellard66fb9762003-03-23 01:06:05 +00006143 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006144#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006145 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006146 {
6147 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006148 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006149 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006150 host_to_target_old_sigset(&target_set, &cur_set);
6151 ret = target_set;
6152 }
6153 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006154#endif
6155#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006156 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006157 {
6158 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006159 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006160 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006161 target_to_host_old_sigset(&set, &target_set);
6162 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006163 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006164 host_to_target_old_sigset(&target_set, &oset);
6165 ret = target_set;
6166 }
6167 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006168#endif
thse5febef2007-04-01 18:31:35 +00006169#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006170 case TARGET_NR_sigprocmask:
6171 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006172#if defined(TARGET_ALPHA)
6173 sigset_t set, oldset;
6174 abi_ulong mask;
6175 int how;
6176
6177 switch (arg1) {
6178 case TARGET_SIG_BLOCK:
6179 how = SIG_BLOCK;
6180 break;
6181 case TARGET_SIG_UNBLOCK:
6182 how = SIG_UNBLOCK;
6183 break;
6184 case TARGET_SIG_SETMASK:
6185 how = SIG_SETMASK;
6186 break;
6187 default:
6188 ret = -TARGET_EINVAL;
6189 goto fail;
6190 }
6191 mask = arg2;
6192 target_to_host_old_sigset(&set, &mask);
6193
Alex Barcelo1c275922014-03-14 14:36:55 +00006194 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006195 if (!is_error(ret)) {
6196 host_to_target_old_sigset(&mask, &oldset);
6197 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006198 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006199 }
6200#else
bellard66fb9762003-03-23 01:06:05 +00006201 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006202 int how;
ths3b46e622007-09-17 08:09:54 +00006203
pbrook53a59602006-03-25 19:31:22 +00006204 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006205 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006206 case TARGET_SIG_BLOCK:
6207 how = SIG_BLOCK;
6208 break;
6209 case TARGET_SIG_UNBLOCK:
6210 how = SIG_UNBLOCK;
6211 break;
6212 case TARGET_SIG_SETMASK:
6213 how = SIG_SETMASK;
6214 break;
6215 default:
ths0da46a62007-10-20 20:23:07 +00006216 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006217 goto fail;
6218 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006219 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006220 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006221 target_to_host_old_sigset(&set, p);
6222 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006223 set_ptr = &set;
6224 } else {
6225 how = 0;
6226 set_ptr = NULL;
6227 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006228 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006229 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006230 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006231 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006232 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006233 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006234 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006235#endif
bellard66fb9762003-03-23 01:06:05 +00006236 }
6237 break;
thse5febef2007-04-01 18:31:35 +00006238#endif
bellard66fb9762003-03-23 01:06:05 +00006239 case TARGET_NR_rt_sigprocmask:
6240 {
6241 int how = arg1;
6242 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006243
pbrook53a59602006-03-25 19:31:22 +00006244 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006245 switch(how) {
6246 case TARGET_SIG_BLOCK:
6247 how = SIG_BLOCK;
6248 break;
6249 case TARGET_SIG_UNBLOCK:
6250 how = SIG_UNBLOCK;
6251 break;
6252 case TARGET_SIG_SETMASK:
6253 how = SIG_SETMASK;
6254 break;
6255 default:
ths0da46a62007-10-20 20:23:07 +00006256 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006257 goto fail;
6258 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006259 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006260 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006261 target_to_host_sigset(&set, p);
6262 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006263 set_ptr = &set;
6264 } else {
6265 how = 0;
6266 set_ptr = NULL;
6267 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006268 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006269 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006270 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006271 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006272 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006273 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006274 }
6275 }
6276 break;
thse5febef2007-04-01 18:31:35 +00006277#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006278 case TARGET_NR_sigpending:
6279 {
6280 sigset_t set;
6281 ret = get_errno(sigpending(&set));
6282 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006283 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006284 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006285 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006286 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006287 }
6288 }
6289 break;
thse5febef2007-04-01 18:31:35 +00006290#endif
bellard66fb9762003-03-23 01:06:05 +00006291 case TARGET_NR_rt_sigpending:
6292 {
6293 sigset_t set;
6294 ret = get_errno(sigpending(&set));
6295 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006296 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006297 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006298 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006299 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006300 }
6301 }
6302 break;
thse5febef2007-04-01 18:31:35 +00006303#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006304 case TARGET_NR_sigsuspend:
6305 {
6306 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006307#if defined(TARGET_ALPHA)
6308 abi_ulong mask = arg1;
6309 target_to_host_old_sigset(&set, &mask);
6310#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006311 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006312 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006313 target_to_host_old_sigset(&set, p);
6314 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006315#endif
bellard66fb9762003-03-23 01:06:05 +00006316 ret = get_errno(sigsuspend(&set));
6317 }
6318 break;
thse5febef2007-04-01 18:31:35 +00006319#endif
bellard66fb9762003-03-23 01:06:05 +00006320 case TARGET_NR_rt_sigsuspend:
6321 {
6322 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006323 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006324 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006325 target_to_host_sigset(&set, p);
6326 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006327 ret = get_errno(sigsuspend(&set));
6328 }
6329 break;
6330 case TARGET_NR_rt_sigtimedwait:
6331 {
bellard66fb9762003-03-23 01:06:05 +00006332 sigset_t set;
6333 struct timespec uts, *puts;
6334 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006335
Anthony Liguoric227f092009-10-01 16:12:16 -05006336 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006337 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006338 target_to_host_sigset(&set, p);
6339 unlock_user(p, arg1, 0);
6340 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006341 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006342 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006343 } else {
6344 puts = NULL;
6345 }
6346 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006347 if (!is_error(ret)) {
6348 if (arg2) {
6349 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6350 0);
6351 if (!p) {
6352 goto efault;
6353 }
6354 host_to_target_siginfo(p, &uinfo);
6355 unlock_user(p, arg2, sizeof(target_siginfo_t));
6356 }
6357 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006358 }
6359 }
6360 break;
6361 case TARGET_NR_rt_sigqueueinfo:
6362 {
6363 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006364 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006365 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006366 target_to_host_siginfo(&uinfo, p);
6367 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006368 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6369 }
6370 break;
thse5febef2007-04-01 18:31:35 +00006371#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006372 case TARGET_NR_sigreturn:
6373 /* NOTE: ret is eax, so not transcoding must be done */
6374 ret = do_sigreturn(cpu_env);
6375 break;
thse5febef2007-04-01 18:31:35 +00006376#endif
bellard66fb9762003-03-23 01:06:05 +00006377 case TARGET_NR_rt_sigreturn:
6378 /* NOTE: ret is eax, so not transcoding must be done */
6379 ret = do_rt_sigreturn(cpu_env);
6380 break;
bellard31e31b82003-02-18 22:55:36 +00006381 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006382 if (!(p = lock_user_string(arg1)))
6383 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006384 ret = get_errno(sethostname(p, arg2));
6385 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006386 break;
6387 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006388 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006389 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006390 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006391 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006392 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6393 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006394 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6395 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006396 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006397 ret = get_errno(setrlimit(resource, &rlim));
6398 }
6399 break;
bellard31e31b82003-02-18 22:55:36 +00006400 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006401 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006402 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006403 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006404 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006405
bellard9de5e442003-03-23 16:49:39 +00006406 ret = get_errno(getrlimit(resource, &rlim));
6407 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006408 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6409 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006410 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6411 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006412 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006413 }
6414 }
6415 break;
bellard31e31b82003-02-18 22:55:36 +00006416 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006417 {
6418 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006419 ret = get_errno(getrusage(arg1, &rusage));
6420 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006421 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006422 }
6423 }
6424 break;
bellard31e31b82003-02-18 22:55:36 +00006425 case TARGET_NR_gettimeofday:
6426 {
bellard31e31b82003-02-18 22:55:36 +00006427 struct timeval tv;
6428 ret = get_errno(gettimeofday(&tv, NULL));
6429 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006430 if (copy_to_user_timeval(arg1, &tv))
6431 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006432 }
6433 }
6434 break;
6435 case TARGET_NR_settimeofday:
6436 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006437 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006438 struct timezone tz, *ptz = NULL;
6439
Paul Burtonb67d8032014-06-22 11:25:41 +01006440 if (arg1) {
6441 if (copy_from_user_timeval(&tv, arg1)) {
6442 goto efault;
6443 }
6444 ptv = &tv;
6445 }
Paul Burtonef4467e2014-06-22 11:25:40 +01006446
6447 if (arg2) {
6448 if (copy_from_user_timezone(&tz, arg2)) {
6449 goto efault;
6450 }
6451 ptz = &tz;
6452 }
6453
Paul Burtonb67d8032014-06-22 11:25:41 +01006454 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00006455 }
6456 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006457#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006458 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006459#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6460 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6461#else
bellardf2674e32003-07-09 12:26:09 +00006462 {
pbrook53a59602006-03-25 19:31:22 +00006463 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006464 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006465 long nsel;
6466
bellard579a97f2007-11-11 14:26:47 +00006467 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6468 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006469 nsel = tswapal(sel->n);
6470 inp = tswapal(sel->inp);
6471 outp = tswapal(sel->outp);
6472 exp = tswapal(sel->exp);
6473 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006474 unlock_user_struct(sel, arg1, 0);
6475 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006476 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006477#endif
bellardf2674e32003-07-09 12:26:09 +00006478 break;
bellard048f6b42005-11-26 18:47:20 +00006479#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006480#ifdef TARGET_NR_pselect6
6481 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006482 {
6483 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6484 fd_set rfds, wfds, efds;
6485 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6486 struct timespec ts, *ts_ptr;
6487
6488 /*
6489 * The 6th arg is actually two args smashed together,
6490 * so we cannot use the C library.
6491 */
6492 sigset_t set;
6493 struct {
6494 sigset_t *set;
6495 size_t size;
6496 } sig, *sig_ptr;
6497
6498 abi_ulong arg_sigset, arg_sigsize, *arg7;
6499 target_sigset_t *target_sigset;
6500
6501 n = arg1;
6502 rfd_addr = arg2;
6503 wfd_addr = arg3;
6504 efd_addr = arg4;
6505 ts_addr = arg5;
6506
6507 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6508 if (ret) {
6509 goto fail;
6510 }
6511 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6512 if (ret) {
6513 goto fail;
6514 }
6515 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6516 if (ret) {
6517 goto fail;
6518 }
6519
6520 /*
6521 * This takes a timespec, and not a timeval, so we cannot
6522 * use the do_select() helper ...
6523 */
6524 if (ts_addr) {
6525 if (target_to_host_timespec(&ts, ts_addr)) {
6526 goto efault;
6527 }
6528 ts_ptr = &ts;
6529 } else {
6530 ts_ptr = NULL;
6531 }
6532
6533 /* Extract the two packed args for the sigset */
6534 if (arg6) {
6535 sig_ptr = &sig;
6536 sig.size = _NSIG / 8;
6537
6538 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6539 if (!arg7) {
6540 goto efault;
6541 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006542 arg_sigset = tswapal(arg7[0]);
6543 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006544 unlock_user(arg7, arg6, 0);
6545
6546 if (arg_sigset) {
6547 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006548 if (arg_sigsize != sizeof(*target_sigset)) {
6549 /* Like the kernel, we enforce correct size sigsets */
6550 ret = -TARGET_EINVAL;
6551 goto fail;
6552 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006553 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6554 sizeof(*target_sigset), 1);
6555 if (!target_sigset) {
6556 goto efault;
6557 }
6558 target_to_host_sigset(&set, target_sigset);
6559 unlock_user(target_sigset, arg_sigset, 0);
6560 } else {
6561 sig.set = NULL;
6562 }
6563 } else {
6564 sig_ptr = NULL;
6565 }
6566
6567 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6568 ts_ptr, sig_ptr));
6569
6570 if (!is_error(ret)) {
6571 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6572 goto efault;
6573 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6574 goto efault;
6575 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6576 goto efault;
6577
6578 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6579 goto efault;
6580 }
6581 }
6582 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006583#endif
bellard31e31b82003-02-18 22:55:36 +00006584 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006585 {
6586 void *p2;
6587 p = lock_user_string(arg1);
6588 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006589 if (!p || !p2)
6590 ret = -TARGET_EFAULT;
6591 else
6592 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006593 unlock_user(p2, arg2, 0);
6594 unlock_user(p, arg1, 0);
6595 }
bellard31e31b82003-02-18 22:55:36 +00006596 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006597#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006598 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006599 {
bellard579a97f2007-11-11 14:26:47 +00006600 void *p2;
thsf0b62432007-09-24 09:25:40 +00006601 p = lock_user_string(arg1);
6602 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006603 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006604 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006605 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006606 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006607 unlock_user(p2, arg3, 0);
6608 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006609 }
6610 break;
6611#endif
bellardebc05482003-09-30 21:08:41 +00006612#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006613 case TARGET_NR_oldlstat:
6614 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006615#endif
bellard31e31b82003-02-18 22:55:36 +00006616 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006617 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006618 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006619 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006620 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006621 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006622 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006623 } else if (is_proc_myself((const char *)p, "exe")) {
6624 char real[PATH_MAX], *temp;
6625 temp = realpath(exec_path, real);
6626 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6627 snprintf((char *)p2, arg3, "%s", real);
6628 } else {
6629 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006630 }
pbrook53a59602006-03-25 19:31:22 +00006631 unlock_user(p2, arg2, ret);
6632 unlock_user(p, arg1, 0);
6633 }
bellard31e31b82003-02-18 22:55:36 +00006634 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006635#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006636 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006637 {
bellard579a97f2007-11-11 14:26:47 +00006638 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006639 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006640 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006641 if (!p || !p2) {
6642 ret = -TARGET_EFAULT;
6643 } else if (is_proc_myself((const char *)p, "exe")) {
6644 char real[PATH_MAX], *temp;
6645 temp = realpath(exec_path, real);
6646 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6647 snprintf((char *)p2, arg4, "%s", real);
6648 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006649 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006650 }
bellard579a97f2007-11-11 14:26:47 +00006651 unlock_user(p2, arg3, ret);
6652 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006653 }
6654 break;
6655#endif
thse5febef2007-04-01 18:31:35 +00006656#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006657 case TARGET_NR_uselib:
6658 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006659#endif
6660#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006661 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006662 if (!(p = lock_user_string(arg1)))
6663 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006664 ret = get_errno(swapon(p, arg2));
6665 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006666 break;
thse5febef2007-04-01 18:31:35 +00006667#endif
bellard31e31b82003-02-18 22:55:36 +00006668 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006669 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6670 /* arg4 must be ignored in all other cases */
6671 p = lock_user_string(arg4);
6672 if (!p) {
6673 goto efault;
6674 }
6675 ret = get_errno(reboot(arg1, arg2, arg3, p));
6676 unlock_user(p, arg4, 0);
6677 } else {
6678 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6679 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006680 break;
thse5febef2007-04-01 18:31:35 +00006681#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006682 case TARGET_NR_readdir:
6683 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006684#endif
6685#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006686 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006687#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6688 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006689 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6690 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006691 {
blueswir1992f48a2007-10-14 16:27:31 +00006692 abi_ulong *v;
6693 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006694 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6695 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006696 v1 = tswapal(v[0]);
6697 v2 = tswapal(v[1]);
6698 v3 = tswapal(v[2]);
6699 v4 = tswapal(v[3]);
6700 v5 = tswapal(v[4]);
6701 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006702 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006703 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006704 target_to_host_bitmask(v4, mmap_flags_tbl),
6705 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006706 }
bellard31e31b82003-02-18 22:55:36 +00006707#else
ths5fafdf22007-09-16 21:08:06 +00006708 ret = get_errno(target_mmap(arg1, arg2, arg3,
6709 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006710 arg5,
6711 arg6));
bellard31e31b82003-02-18 22:55:36 +00006712#endif
bellard6fb883e2003-07-09 17:12:39 +00006713 break;
thse5febef2007-04-01 18:31:35 +00006714#endif
bellarda315a142005-01-30 22:59:18 +00006715#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006716 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006717#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006718#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006719#endif
ths5fafdf22007-09-16 21:08:06 +00006720 ret = get_errno(target_mmap(arg1, arg2, arg3,
6721 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006722 arg5,
bellardc573ff62004-01-04 15:51:36 +00006723 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006724 break;
bellarda315a142005-01-30 22:59:18 +00006725#endif
bellard31e31b82003-02-18 22:55:36 +00006726 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006727 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006728 break;
bellard9de5e442003-03-23 16:49:39 +00006729 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006730 {
Andreas Färber0429a972013-08-26 18:14:44 +02006731 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006732 /* Special hack to detect libc making the stack executable. */
6733 if ((arg3 & PROT_GROWSDOWN)
6734 && arg1 >= ts->info->stack_limit
6735 && arg1 <= ts->info->start_stack) {
6736 arg3 &= ~PROT_GROWSDOWN;
6737 arg2 = arg2 + arg1 - ts->info->stack_limit;
6738 arg1 = ts->info->stack_limit;
6739 }
6740 }
bellard54936002003-05-13 00:25:15 +00006741 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006742 break;
thse5febef2007-04-01 18:31:35 +00006743#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006744 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006745 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006746 break;
thse5febef2007-04-01 18:31:35 +00006747#endif
pbrook53a59602006-03-25 19:31:22 +00006748 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006749#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006750 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006751 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006752 break;
thse5febef2007-04-01 18:31:35 +00006753#endif
6754#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006755 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006756 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006757 break;
thse5febef2007-04-01 18:31:35 +00006758#endif
6759#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006760 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006761 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006762 break;
thse5febef2007-04-01 18:31:35 +00006763#endif
6764#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006765 case TARGET_NR_mlockall:
6766 ret = get_errno(mlockall(arg1));
6767 break;
thse5febef2007-04-01 18:31:35 +00006768#endif
6769#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006770 case TARGET_NR_munlockall:
6771 ret = get_errno(munlockall());
6772 break;
thse5febef2007-04-01 18:31:35 +00006773#endif
bellard31e31b82003-02-18 22:55:36 +00006774 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006775 if (!(p = lock_user_string(arg1)))
6776 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006777 ret = get_errno(truncate(p, arg2));
6778 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006779 break;
6780 case TARGET_NR_ftruncate:
6781 ret = get_errno(ftruncate(arg1, arg2));
6782 break;
6783 case TARGET_NR_fchmod:
6784 ret = get_errno(fchmod(arg1, arg2));
6785 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006786#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006787 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006788 if (!(p = lock_user_string(arg2)))
6789 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006790 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006791 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006792 break;
6793#endif
bellard31e31b82003-02-18 22:55:36 +00006794 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006795 /* Note that negative values are valid for getpriority, so we must
6796 differentiate based on errno settings. */
6797 errno = 0;
6798 ret = getpriority(arg1, arg2);
6799 if (ret == -1 && errno != 0) {
6800 ret = -host_to_target_errno(errno);
6801 break;
6802 }
6803#ifdef TARGET_ALPHA
6804 /* Return value is the unbiased priority. Signal no error. */
6805 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6806#else
6807 /* Return value is a biased priority to avoid negative numbers. */
6808 ret = 20 - ret;
6809#endif
bellard31e31b82003-02-18 22:55:36 +00006810 break;
6811 case TARGET_NR_setpriority:
6812 ret = get_errno(setpriority(arg1, arg2, arg3));
6813 break;
bellardebc05482003-09-30 21:08:41 +00006814#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006815 case TARGET_NR_profil:
6816 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006817#endif
bellard31e31b82003-02-18 22:55:36 +00006818 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006819 if (!(p = lock_user_string(arg1)))
6820 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006821 ret = get_errno(statfs(path(p), &stfs));
6822 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006823 convert_statfs:
6824 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006825 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006826
bellard579a97f2007-11-11 14:26:47 +00006827 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6828 goto efault;
6829 __put_user(stfs.f_type, &target_stfs->f_type);
6830 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6831 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6832 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6833 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6834 __put_user(stfs.f_files, &target_stfs->f_files);
6835 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6836 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6837 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6838 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006839 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6840 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006841 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006842 }
6843 break;
6844 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006845 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006846 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006847#ifdef TARGET_NR_statfs64
6848 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006849 if (!(p = lock_user_string(arg1)))
6850 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006851 ret = get_errno(statfs(path(p), &stfs));
6852 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006853 convert_statfs64:
6854 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006855 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006856
bellard579a97f2007-11-11 14:26:47 +00006857 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6858 goto efault;
6859 __put_user(stfs.f_type, &target_stfs->f_type);
6860 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6861 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6862 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6863 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6864 __put_user(stfs.f_files, &target_stfs->f_files);
6865 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6866 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6867 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6868 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006869 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6870 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006871 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006872 }
6873 break;
6874 case TARGET_NR_fstatfs64:
6875 ret = get_errno(fstatfs(arg1, &stfs));
6876 goto convert_statfs64;
6877#endif
bellardebc05482003-09-30 21:08:41 +00006878#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006879 case TARGET_NR_ioperm:
6880 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006881#endif
thse5febef2007-04-01 18:31:35 +00006882#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006883 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006884 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006885 break;
thse5febef2007-04-01 18:31:35 +00006886#endif
bellard3532fa72006-06-24 15:06:03 +00006887#ifdef TARGET_NR_accept
6888 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006889 ret = do_accept4(arg1, arg2, arg3, 0);
6890 break;
6891#endif
6892#ifdef TARGET_NR_accept4
6893 case TARGET_NR_accept4:
6894#ifdef CONFIG_ACCEPT4
6895 ret = do_accept4(arg1, arg2, arg3, arg4);
6896#else
6897 goto unimplemented;
6898#endif
bellard3532fa72006-06-24 15:06:03 +00006899 break;
6900#endif
6901#ifdef TARGET_NR_bind
6902 case TARGET_NR_bind:
6903 ret = do_bind(arg1, arg2, arg3);
6904 break;
6905#endif
6906#ifdef TARGET_NR_connect
6907 case TARGET_NR_connect:
6908 ret = do_connect(arg1, arg2, arg3);
6909 break;
6910#endif
6911#ifdef TARGET_NR_getpeername
6912 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006913 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006914 break;
6915#endif
6916#ifdef TARGET_NR_getsockname
6917 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006918 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006919 break;
6920#endif
6921#ifdef TARGET_NR_getsockopt
6922 case TARGET_NR_getsockopt:
6923 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6924 break;
6925#endif
6926#ifdef TARGET_NR_listen
6927 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006928 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006929 break;
6930#endif
6931#ifdef TARGET_NR_recv
6932 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006933 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006934 break;
6935#endif
6936#ifdef TARGET_NR_recvfrom
6937 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006938 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006939 break;
6940#endif
6941#ifdef TARGET_NR_recvmsg
6942 case TARGET_NR_recvmsg:
6943 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6944 break;
6945#endif
6946#ifdef TARGET_NR_send
6947 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006948 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006949 break;
6950#endif
6951#ifdef TARGET_NR_sendmsg
6952 case TARGET_NR_sendmsg:
6953 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6954 break;
6955#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006956#ifdef TARGET_NR_sendmmsg
6957 case TARGET_NR_sendmmsg:
6958 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6959 break;
6960 case TARGET_NR_recvmmsg:
6961 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6962 break;
6963#endif
bellard3532fa72006-06-24 15:06:03 +00006964#ifdef TARGET_NR_sendto
6965 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006966 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006967 break;
6968#endif
6969#ifdef TARGET_NR_shutdown
6970 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006971 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006972 break;
6973#endif
6974#ifdef TARGET_NR_socket
6975 case TARGET_NR_socket:
6976 ret = do_socket(arg1, arg2, arg3);
6977 break;
6978#endif
6979#ifdef TARGET_NR_socketpair
6980 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006981 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006982 break;
6983#endif
6984#ifdef TARGET_NR_setsockopt
6985 case TARGET_NR_setsockopt:
6986 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6987 break;
6988#endif
ths7494b0f2007-02-11 18:26:53 +00006989
bellard31e31b82003-02-18 22:55:36 +00006990 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006991 if (!(p = lock_user_string(arg2)))
6992 goto efault;
thse5574482007-02-11 20:03:13 +00006993 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6994 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006995 break;
6996
bellard31e31b82003-02-18 22:55:36 +00006997 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006998 {
bellard66fb9762003-03-23 01:06:05 +00006999 struct itimerval value, ovalue, *pvalue;
7000
pbrook53a59602006-03-25 19:31:22 +00007001 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007002 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007003 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7004 || copy_from_user_timeval(&pvalue->it_value,
7005 arg2 + sizeof(struct target_timeval)))
7006 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007007 } else {
7008 pvalue = NULL;
7009 }
7010 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007011 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007012 if (copy_to_user_timeval(arg3,
7013 &ovalue.it_interval)
7014 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7015 &ovalue.it_value))
7016 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007017 }
7018 }
7019 break;
bellard31e31b82003-02-18 22:55:36 +00007020 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007021 {
bellard66fb9762003-03-23 01:06:05 +00007022 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007023
bellard66fb9762003-03-23 01:06:05 +00007024 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007025 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007026 if (copy_to_user_timeval(arg2,
7027 &value.it_interval)
7028 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7029 &value.it_value))
7030 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007031 }
7032 }
7033 break;
bellard31e31b82003-02-18 22:55:36 +00007034 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007035 if (!(p = lock_user_string(arg1)))
7036 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007037 ret = get_errno(stat(path(p), &st));
7038 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007039 goto do_stat;
7040 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007041 if (!(p = lock_user_string(arg1)))
7042 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007043 ret = get_errno(lstat(path(p), &st));
7044 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007045 goto do_stat;
7046 case TARGET_NR_fstat:
7047 {
7048 ret = get_errno(fstat(arg1, &st));
7049 do_stat:
7050 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007051 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007052
bellard579a97f2007-11-11 14:26:47 +00007053 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7054 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007055 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007056 __put_user(st.st_dev, &target_st->st_dev);
7057 __put_user(st.st_ino, &target_st->st_ino);
7058 __put_user(st.st_mode, &target_st->st_mode);
7059 __put_user(st.st_uid, &target_st->st_uid);
7060 __put_user(st.st_gid, &target_st->st_gid);
7061 __put_user(st.st_nlink, &target_st->st_nlink);
7062 __put_user(st.st_rdev, &target_st->st_rdev);
7063 __put_user(st.st_size, &target_st->st_size);
7064 __put_user(st.st_blksize, &target_st->st_blksize);
7065 __put_user(st.st_blocks, &target_st->st_blocks);
7066 __put_user(st.st_atime, &target_st->target_st_atime);
7067 __put_user(st.st_mtime, &target_st->target_st_mtime);
7068 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007069 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007070 }
7071 }
7072 break;
bellardebc05482003-09-30 21:08:41 +00007073#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007074 case TARGET_NR_olduname:
7075 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007076#endif
7077#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007078 case TARGET_NR_iopl:
7079 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007080#endif
bellard31e31b82003-02-18 22:55:36 +00007081 case TARGET_NR_vhangup:
7082 ret = get_errno(vhangup());
7083 break;
bellardebc05482003-09-30 21:08:41 +00007084#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007085 case TARGET_NR_idle:
7086 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007087#endif
bellard42ad6ae2005-01-03 22:48:11 +00007088#ifdef TARGET_NR_syscall
7089 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007090 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7091 arg6, arg7, arg8, 0);
7092 break;
bellard42ad6ae2005-01-03 22:48:11 +00007093#endif
bellard31e31b82003-02-18 22:55:36 +00007094 case TARGET_NR_wait4:
7095 {
7096 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007097 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007098 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007099 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007100 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007101 if (target_rusage)
7102 rusage_ptr = &rusage;
7103 else
7104 rusage_ptr = NULL;
7105 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7106 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007107 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007108 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007109 if (put_user_s32(status, status_ptr))
7110 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007111 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007112 if (target_rusage) {
7113 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7114 if (rusage_err) {
7115 ret = rusage_err;
7116 }
7117 }
bellard31e31b82003-02-18 22:55:36 +00007118 }
7119 }
7120 break;
thse5febef2007-04-01 18:31:35 +00007121#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007122 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007123 if (!(p = lock_user_string(arg1)))
7124 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007125 ret = get_errno(swapoff(p));
7126 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007127 break;
thse5febef2007-04-01 18:31:35 +00007128#endif
bellard31e31b82003-02-18 22:55:36 +00007129 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007130 {
pbrook53a59602006-03-25 19:31:22 +00007131 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007132 struct sysinfo value;
7133 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007134 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007135 {
bellard579a97f2007-11-11 14:26:47 +00007136 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7137 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007138 __put_user(value.uptime, &target_value->uptime);
7139 __put_user(value.loads[0], &target_value->loads[0]);
7140 __put_user(value.loads[1], &target_value->loads[1]);
7141 __put_user(value.loads[2], &target_value->loads[2]);
7142 __put_user(value.totalram, &target_value->totalram);
7143 __put_user(value.freeram, &target_value->freeram);
7144 __put_user(value.sharedram, &target_value->sharedram);
7145 __put_user(value.bufferram, &target_value->bufferram);
7146 __put_user(value.totalswap, &target_value->totalswap);
7147 __put_user(value.freeswap, &target_value->freeswap);
7148 __put_user(value.procs, &target_value->procs);
7149 __put_user(value.totalhigh, &target_value->totalhigh);
7150 __put_user(value.freehigh, &target_value->freehigh);
7151 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007152 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007153 }
7154 }
7155 break;
thse5febef2007-04-01 18:31:35 +00007156#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007157 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007158 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7159 break;
thse5febef2007-04-01 18:31:35 +00007160#endif
aurel32e5289082009-04-18 16:16:12 +00007161#ifdef TARGET_NR_semget
7162 case TARGET_NR_semget:
7163 ret = get_errno(semget(arg1, arg2, arg3));
7164 break;
7165#endif
7166#ifdef TARGET_NR_semop
7167 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007168 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007169 break;
7170#endif
7171#ifdef TARGET_NR_semctl
7172 case TARGET_NR_semctl:
7173 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7174 break;
7175#endif
aurel32eeb438c2008-10-13 21:08:55 +00007176#ifdef TARGET_NR_msgctl
7177 case TARGET_NR_msgctl:
7178 ret = do_msgctl(arg1, arg2, arg3);
7179 break;
7180#endif
7181#ifdef TARGET_NR_msgget
7182 case TARGET_NR_msgget:
7183 ret = get_errno(msgget(arg1, arg2));
7184 break;
7185#endif
7186#ifdef TARGET_NR_msgrcv
7187 case TARGET_NR_msgrcv:
7188 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7189 break;
7190#endif
7191#ifdef TARGET_NR_msgsnd
7192 case TARGET_NR_msgsnd:
7193 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7194 break;
7195#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007196#ifdef TARGET_NR_shmget
7197 case TARGET_NR_shmget:
7198 ret = get_errno(shmget(arg1, arg2, arg3));
7199 break;
7200#endif
7201#ifdef TARGET_NR_shmctl
7202 case TARGET_NR_shmctl:
7203 ret = do_shmctl(arg1, arg2, arg3);
7204 break;
7205#endif
7206#ifdef TARGET_NR_shmat
7207 case TARGET_NR_shmat:
7208 ret = do_shmat(arg1, arg2, arg3);
7209 break;
7210#endif
7211#ifdef TARGET_NR_shmdt
7212 case TARGET_NR_shmdt:
7213 ret = do_shmdt(arg1);
7214 break;
7215#endif
bellard31e31b82003-02-18 22:55:36 +00007216 case TARGET_NR_fsync:
7217 ret = get_errno(fsync(arg1));
7218 break;
bellard31e31b82003-02-18 22:55:36 +00007219 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007220 /* Linux manages to have three different orderings for its
7221 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7222 * match the kernel's CONFIG_CLONE_* settings.
7223 * Microblaze is further special in that it uses a sixth
7224 * implicit argument to clone for the TLS pointer.
7225 */
7226#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007227 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007228#elif defined(TARGET_CLONE_BACKWARDS)
7229 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7230#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007231 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007232#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007233 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007234#endif
bellard1b6b0292003-03-22 17:31:38 +00007235 break;
bellardec86b0f2003-04-11 00:15:04 +00007236#ifdef __NR_exit_group
7237 /* new thread calls */
7238 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007239#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007240 _mcleanup();
7241#endif
bellarde9009672005-04-26 20:42:36 +00007242 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007243 ret = get_errno(exit_group(arg1));
7244 break;
7245#endif
bellard31e31b82003-02-18 22:55:36 +00007246 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007247 if (!(p = lock_user_string(arg1)))
7248 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007249 ret = get_errno(setdomainname(p, arg2));
7250 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007251 break;
7252 case TARGET_NR_uname:
7253 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007254 {
7255 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007256
bellard579a97f2007-11-11 14:26:47 +00007257 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7258 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007259 ret = get_errno(sys_uname(buf));
7260 if (!is_error(ret)) {
7261 /* Overrite the native machine name with whatever is being
7262 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007263 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007264 /* Allow the user to override the reported release. */
7265 if (qemu_uname_release && *qemu_uname_release)
7266 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007267 }
pbrook53a59602006-03-25 19:31:22 +00007268 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007269 }
bellard31e31b82003-02-18 22:55:36 +00007270 break;
bellard6dbad632003-03-16 18:05:05 +00007271#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007272 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007273 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007274 break;
j_mayer84409dd2007-04-06 08:56:50 +00007275#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007276 case TARGET_NR_vm86old:
7277 goto unimplemented;
7278 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007279 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007280 break;
7281#endif
j_mayer84409dd2007-04-06 08:56:50 +00007282#endif
bellard31e31b82003-02-18 22:55:36 +00007283 case TARGET_NR_adjtimex:
7284 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007285#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007286 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007287#endif
bellard31e31b82003-02-18 22:55:36 +00007288 case TARGET_NR_init_module:
7289 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007290#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007291 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007292#endif
bellard31e31b82003-02-18 22:55:36 +00007293 goto unimplemented;
7294 case TARGET_NR_quotactl:
7295 goto unimplemented;
7296 case TARGET_NR_getpgid:
7297 ret = get_errno(getpgid(arg1));
7298 break;
7299 case TARGET_NR_fchdir:
7300 ret = get_errno(fchdir(arg1));
7301 break;
j_mayer84409dd2007-04-06 08:56:50 +00007302#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007303 case TARGET_NR_bdflush:
7304 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007305#endif
thse5febef2007-04-01 18:31:35 +00007306#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007307 case TARGET_NR_sysfs:
7308 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007309#endif
bellard31e31b82003-02-18 22:55:36 +00007310 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007311 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007312 break;
thse5febef2007-04-01 18:31:35 +00007313#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007314 case TARGET_NR_afs_syscall:
7315 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007316#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007317#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007318 case TARGET_NR__llseek:
7319 {
7320 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007321#if !defined(__NR_llseek)
7322 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7323 if (res == -1) {
7324 ret = get_errno(res);
7325 } else {
7326 ret = 0;
7327 }
7328#else
bellard31e31b82003-02-18 22:55:36 +00007329 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007330#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007331 if ((ret == 0) && put_user_s64(res, arg4)) {
7332 goto efault;
7333 }
bellard31e31b82003-02-18 22:55:36 +00007334 }
7335 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007336#endif
bellard31e31b82003-02-18 22:55:36 +00007337 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007338#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007339#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007340 {
pbrook53a59602006-03-25 19:31:22 +00007341 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007342 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007343 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007344
7345 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007346 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007347 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007348 goto fail;
7349 }
ths3b46e622007-09-17 08:09:54 +00007350
bellard4add45b2003-06-05 01:52:59 +00007351 ret = get_errno(sys_getdents(arg1, dirp, count));
7352 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007353 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007354 struct target_dirent *tde;
7355 int len = ret;
7356 int reclen, treclen;
7357 int count1, tnamelen;
7358
7359 count1 = 0;
7360 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007361 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7362 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007363 tde = target_dirp;
7364 while (len > 0) {
7365 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007366 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7367 assert(tnamelen >= 0);
7368 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7369 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007370 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007371 tde->d_ino = tswapal(de->d_ino);
7372 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007373 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007374 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007375 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007376 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007377 count1 += treclen;
7378 }
7379 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007380 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007381 }
7382 free(dirp);
7383 }
7384#else
bellard31e31b82003-02-18 22:55:36 +00007385 {
aurel326556a832008-10-13 21:08:17 +00007386 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007387 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007388
bellard579a97f2007-11-11 14:26:47 +00007389 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7390 goto efault;
bellard72f03902003-02-18 23:33:18 +00007391 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007392 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007393 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007394 int len = ret;
7395 int reclen;
7396 de = dirp;
7397 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007398 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007399 if (reclen > len)
7400 break;
bellard8083a3e2003-03-24 23:12:16 +00007401 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007402 tswapls(&de->d_ino);
7403 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007404 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007405 len -= reclen;
7406 }
7407 }
pbrook53a59602006-03-25 19:31:22 +00007408 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007409 }
bellard4add45b2003-06-05 01:52:59 +00007410#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007411#else
7412 /* Implement getdents in terms of getdents64 */
7413 {
7414 struct linux_dirent64 *dirp;
7415 abi_long count = arg3;
7416
7417 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7418 if (!dirp) {
7419 goto efault;
7420 }
7421 ret = get_errno(sys_getdents64(arg1, dirp, count));
7422 if (!is_error(ret)) {
7423 /* Convert the dirent64 structs to target dirent. We do this
7424 * in-place, since we can guarantee that a target_dirent is no
7425 * larger than a dirent64; however this means we have to be
7426 * careful to read everything before writing in the new format.
7427 */
7428 struct linux_dirent64 *de;
7429 struct target_dirent *tde;
7430 int len = ret;
7431 int tlen = 0;
7432
7433 de = dirp;
7434 tde = (struct target_dirent *)dirp;
7435 while (len > 0) {
7436 int namelen, treclen;
7437 int reclen = de->d_reclen;
7438 uint64_t ino = de->d_ino;
7439 int64_t off = de->d_off;
7440 uint8_t type = de->d_type;
7441
7442 namelen = strlen(de->d_name);
7443 treclen = offsetof(struct target_dirent, d_name)
7444 + namelen + 2;
7445 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7446
7447 memmove(tde->d_name, de->d_name, namelen + 1);
7448 tde->d_ino = tswapal(ino);
7449 tde->d_off = tswapal(off);
7450 tde->d_reclen = tswap16(treclen);
7451 /* The target_dirent type is in what was formerly a padding
7452 * byte at the end of the structure:
7453 */
7454 *(((char *)tde) + treclen - 1) = type;
7455
7456 de = (struct linux_dirent64 *)((char *)de + reclen);
7457 tde = (struct target_dirent *)((char *)tde + treclen);
7458 len -= reclen;
7459 tlen += treclen;
7460 }
7461 ret = tlen;
7462 }
7463 unlock_user(dirp, arg2, ret);
7464 }
7465#endif
bellard31e31b82003-02-18 22:55:36 +00007466 break;
ths3ae43202007-09-16 21:39:48 +00007467#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007468 case TARGET_NR_getdents64:
7469 {
aurel326556a832008-10-13 21:08:17 +00007470 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007471 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007472 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7473 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007474 ret = get_errno(sys_getdents64(arg1, dirp, count));
7475 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007476 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007477 int len = ret;
7478 int reclen;
7479 de = dirp;
7480 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007481 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007482 if (reclen > len)
7483 break;
bellard8083a3e2003-03-24 23:12:16 +00007484 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007485 tswap64s((uint64_t *)&de->d_ino);
7486 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007487 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007488 len -= reclen;
7489 }
7490 }
pbrook53a59602006-03-25 19:31:22 +00007491 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007492 }
7493 break;
bellarda541f292004-04-12 20:39:29 +00007494#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007495#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007496 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007497 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007498 break;
thse5febef2007-04-01 18:31:35 +00007499#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007500#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7501# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007502 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007503# endif
7504# ifdef TARGET_NR_ppoll
7505 case TARGET_NR_ppoll:
7506# endif
bellard9de5e442003-03-23 16:49:39 +00007507 {
pbrook53a59602006-03-25 19:31:22 +00007508 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007509 unsigned int nfds = arg2;
7510 int timeout = arg3;
7511 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007512 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007513
bellard579a97f2007-11-11 14:26:47 +00007514 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7515 if (!target_pfd)
7516 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007517
bellard9de5e442003-03-23 16:49:39 +00007518 pfd = alloca(sizeof(struct pollfd) * nfds);
7519 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007520 pfd[i].fd = tswap32(target_pfd[i].fd);
7521 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007522 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007523
7524# ifdef TARGET_NR_ppoll
7525 if (num == TARGET_NR_ppoll) {
7526 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7527 target_sigset_t *target_set;
7528 sigset_t _set, *set = &_set;
7529
7530 if (arg3) {
7531 if (target_to_host_timespec(timeout_ts, arg3)) {
7532 unlock_user(target_pfd, arg1, 0);
7533 goto efault;
7534 }
7535 } else {
7536 timeout_ts = NULL;
7537 }
7538
7539 if (arg4) {
7540 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7541 if (!target_set) {
7542 unlock_user(target_pfd, arg1, 0);
7543 goto efault;
7544 }
7545 target_to_host_sigset(set, target_set);
7546 } else {
7547 set = NULL;
7548 }
7549
7550 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7551
7552 if (!is_error(ret) && arg3) {
7553 host_to_target_timespec(arg3, timeout_ts);
7554 }
7555 if (arg4) {
7556 unlock_user(target_set, arg4, 0);
7557 }
7558 } else
7559# endif
7560 ret = get_errno(poll(pfd, nfds, timeout));
7561
bellard9de5e442003-03-23 16:49:39 +00007562 if (!is_error(ret)) {
7563 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007564 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007565 }
7566 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007567 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007568 }
7569 break;
thse5febef2007-04-01 18:31:35 +00007570#endif
bellard31e31b82003-02-18 22:55:36 +00007571 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007572 /* NOTE: the flock constant seems to be the same for every
7573 Linux platform */
7574 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007575 break;
7576 case TARGET_NR_readv:
7577 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007578 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7579 if (vec != NULL) {
7580 ret = get_errno(readv(arg1, vec, arg3));
7581 unlock_iovec(vec, arg2, arg3, 1);
7582 } else {
7583 ret = -host_to_target_errno(errno);
7584 }
bellard31e31b82003-02-18 22:55:36 +00007585 }
7586 break;
7587 case TARGET_NR_writev:
7588 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007589 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7590 if (vec != NULL) {
7591 ret = get_errno(writev(arg1, vec, arg3));
7592 unlock_iovec(vec, arg2, arg3, 0);
7593 } else {
7594 ret = -host_to_target_errno(errno);
7595 }
bellard31e31b82003-02-18 22:55:36 +00007596 }
7597 break;
7598 case TARGET_NR_getsid:
7599 ret = get_errno(getsid(arg1));
7600 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007601#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007602 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007603 ret = get_errno(fdatasync(arg1));
7604 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007605#endif
bellard31e31b82003-02-18 22:55:36 +00007606 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007607 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007608 return value. */
ths0da46a62007-10-20 20:23:07 +00007609 ret = -TARGET_ENOTDIR;
7610 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007611 case TARGET_NR_sched_getaffinity:
7612 {
7613 unsigned int mask_size;
7614 unsigned long *mask;
7615
7616 /*
7617 * sched_getaffinity needs multiples of ulong, so need to take
7618 * care of mismatches between target ulong and host ulong sizes.
7619 */
7620 if (arg2 & (sizeof(abi_ulong) - 1)) {
7621 ret = -TARGET_EINVAL;
7622 break;
7623 }
7624 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7625
7626 mask = alloca(mask_size);
7627 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7628
7629 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007630 if (ret > arg2) {
7631 /* More data returned than the caller's buffer will fit.
7632 * This only happens if sizeof(abi_long) < sizeof(long)
7633 * and the caller passed us a buffer holding an odd number
7634 * of abi_longs. If the host kernel is actually using the
7635 * extra 4 bytes then fail EINVAL; otherwise we can just
7636 * ignore them and only copy the interesting part.
7637 */
7638 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7639 if (numcpus > arg2 * 8) {
7640 ret = -TARGET_EINVAL;
7641 break;
7642 }
7643 ret = arg2;
7644 }
7645
Mike McCormackcd18f052011-04-18 14:43:36 +09007646 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007647 goto efault;
7648 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007649 }
7650 }
7651 break;
7652 case TARGET_NR_sched_setaffinity:
7653 {
7654 unsigned int mask_size;
7655 unsigned long *mask;
7656
7657 /*
7658 * sched_setaffinity needs multiples of ulong, so need to take
7659 * care of mismatches between target ulong and host ulong sizes.
7660 */
7661 if (arg2 & (sizeof(abi_ulong) - 1)) {
7662 ret = -TARGET_EINVAL;
7663 break;
7664 }
7665 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7666
7667 mask = alloca(mask_size);
7668 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7669 goto efault;
7670 }
7671 memcpy(mask, p, arg2);
7672 unlock_user_struct(p, arg2, 0);
7673
7674 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7675 }
7676 break;
bellard31e31b82003-02-18 22:55:36 +00007677 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007678 {
pbrook53a59602006-03-25 19:31:22 +00007679 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007680 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007681
bellard579a97f2007-11-11 14:26:47 +00007682 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7683 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007684 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007685 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007686 ret = get_errno(sched_setparam(arg1, &schp));
7687 }
7688 break;
bellard31e31b82003-02-18 22:55:36 +00007689 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007690 {
pbrook53a59602006-03-25 19:31:22 +00007691 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007692 struct sched_param schp;
7693 ret = get_errno(sched_getparam(arg1, &schp));
7694 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007695 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7696 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007697 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007698 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007699 }
7700 }
7701 break;
bellard31e31b82003-02-18 22:55:36 +00007702 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007703 {
pbrook53a59602006-03-25 19:31:22 +00007704 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007705 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007706 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7707 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007708 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007709 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007710 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7711 }
7712 break;
bellard31e31b82003-02-18 22:55:36 +00007713 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007714 ret = get_errno(sched_getscheduler(arg1));
7715 break;
bellard31e31b82003-02-18 22:55:36 +00007716 case TARGET_NR_sched_yield:
7717 ret = get_errno(sched_yield());
7718 break;
7719 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007720 ret = get_errno(sched_get_priority_max(arg1));
7721 break;
bellard31e31b82003-02-18 22:55:36 +00007722 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007723 ret = get_errno(sched_get_priority_min(arg1));
7724 break;
bellard31e31b82003-02-18 22:55:36 +00007725 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007726 {
bellard5cd43932003-03-29 16:54:36 +00007727 struct timespec ts;
7728 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7729 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007730 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007731 }
7732 }
7733 break;
bellard31e31b82003-02-18 22:55:36 +00007734 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007735 {
bellard1b6b0292003-03-22 17:31:38 +00007736 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007737 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007738 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007739 if (is_error(ret) && arg2) {
7740 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007741 }
7742 }
7743 break;
thse5febef2007-04-01 18:31:35 +00007744#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007745 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007746 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007747#endif
7748#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007749 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007750 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007751#endif
bellard31e31b82003-02-18 22:55:36 +00007752 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007753 switch (arg1) {
7754 case PR_GET_PDEATHSIG:
7755 {
7756 int deathsig;
7757 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7758 if (!is_error(ret) && arg2
7759 && put_user_ual(deathsig, arg2)) {
7760 goto efault;
thse5574482007-02-11 20:03:13 +00007761 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007762 break;
7763 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007764#ifdef PR_GET_NAME
7765 case PR_GET_NAME:
7766 {
7767 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7768 if (!name) {
7769 goto efault;
7770 }
7771 ret = get_errno(prctl(arg1, (unsigned long)name,
7772 arg3, arg4, arg5));
7773 unlock_user(name, arg2, 16);
7774 break;
7775 }
7776 case PR_SET_NAME:
7777 {
7778 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7779 if (!name) {
7780 goto efault;
7781 }
7782 ret = get_errno(prctl(arg1, (unsigned long)name,
7783 arg3, arg4, arg5));
7784 unlock_user(name, arg2, 0);
7785 break;
7786 }
7787#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007788 default:
7789 /* Most prctl options have no pointer arguments */
7790 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7791 break;
7792 }
ths39b9aae2007-02-11 18:36:44 +00007793 break;
bellardd2fd1af2007-11-14 18:08:56 +00007794#ifdef TARGET_NR_arch_prctl
7795 case TARGET_NR_arch_prctl:
7796#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7797 ret = do_arch_prctl(cpu_env, arg1, arg2);
7798 break;
7799#else
7800 goto unimplemented;
7801#endif
7802#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007803#ifdef TARGET_NR_pread64
7804 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007805 if (regpairs_aligned(cpu_env)) {
7806 arg4 = arg5;
7807 arg5 = arg6;
7808 }
aurel32f2c7ba12008-03-28 22:32:06 +00007809 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7810 goto efault;
7811 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7812 unlock_user(p, arg2, ret);
7813 break;
7814 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007815 if (regpairs_aligned(cpu_env)) {
7816 arg4 = arg5;
7817 arg5 = arg6;
7818 }
aurel32f2c7ba12008-03-28 22:32:06 +00007819 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7820 goto efault;
7821 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7822 unlock_user(p, arg2, 0);
7823 break;
7824#endif
bellard31e31b82003-02-18 22:55:36 +00007825 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007826 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7827 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007828 ret = get_errno(sys_getcwd1(p, arg2));
7829 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007830 break;
7831 case TARGET_NR_capget:
7832 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007833 {
7834 struct target_user_cap_header *target_header;
7835 struct target_user_cap_data *target_data = NULL;
7836 struct __user_cap_header_struct header;
7837 struct __user_cap_data_struct data[2];
7838 struct __user_cap_data_struct *dataptr = NULL;
7839 int i, target_datalen;
7840 int data_items = 1;
7841
7842 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7843 goto efault;
7844 }
7845 header.version = tswap32(target_header->version);
7846 header.pid = tswap32(target_header->pid);
7847
Peter Maydellec864872014-03-19 16:07:30 +00007848 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007849 /* Version 2 and up takes pointer to two user_data structs */
7850 data_items = 2;
7851 }
7852
7853 target_datalen = sizeof(*target_data) * data_items;
7854
7855 if (arg2) {
7856 if (num == TARGET_NR_capget) {
7857 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7858 } else {
7859 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7860 }
7861 if (!target_data) {
7862 unlock_user_struct(target_header, arg1, 0);
7863 goto efault;
7864 }
7865
7866 if (num == TARGET_NR_capset) {
7867 for (i = 0; i < data_items; i++) {
7868 data[i].effective = tswap32(target_data[i].effective);
7869 data[i].permitted = tswap32(target_data[i].permitted);
7870 data[i].inheritable = tswap32(target_data[i].inheritable);
7871 }
7872 }
7873
7874 dataptr = data;
7875 }
7876
7877 if (num == TARGET_NR_capget) {
7878 ret = get_errno(capget(&header, dataptr));
7879 } else {
7880 ret = get_errno(capset(&header, dataptr));
7881 }
7882
7883 /* The kernel always updates version for both capget and capset */
7884 target_header->version = tswap32(header.version);
7885 unlock_user_struct(target_header, arg1, 1);
7886
7887 if (arg2) {
7888 if (num == TARGET_NR_capget) {
7889 for (i = 0; i < data_items; i++) {
7890 target_data[i].effective = tswap32(data[i].effective);
7891 target_data[i].permitted = tswap32(data[i].permitted);
7892 target_data[i].inheritable = tswap32(data[i].inheritable);
7893 }
7894 unlock_user(target_data, arg2, target_datalen);
7895 } else {
7896 unlock_user(target_data, arg2, 0);
7897 }
7898 }
7899 break;
7900 }
bellard31e31b82003-02-18 22:55:36 +00007901 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007902#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007903 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007904 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007905 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007906 break;
7907#else
bellard5cd43932003-03-29 16:54:36 +00007908 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007909#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007910
7911#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007912 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007913 {
7914 off_t *offp = NULL;
7915 off_t off;
7916 if (arg3) {
7917 ret = get_user_sal(off, arg3);
7918 if (is_error(ret)) {
7919 break;
7920 }
7921 offp = &off;
7922 }
7923 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7924 if (!is_error(ret) && arg3) {
7925 abi_long ret2 = put_user_sal(off, arg3);
7926 if (is_error(ret2)) {
7927 ret = ret2;
7928 }
7929 }
7930 break;
7931 }
7932#ifdef TARGET_NR_sendfile64
7933 case TARGET_NR_sendfile64:
7934 {
7935 off_t *offp = NULL;
7936 off_t off;
7937 if (arg3) {
7938 ret = get_user_s64(off, arg3);
7939 if (is_error(ret)) {
7940 break;
7941 }
7942 offp = &off;
7943 }
7944 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7945 if (!is_error(ret) && arg3) {
7946 abi_long ret2 = put_user_s64(off, arg3);
7947 if (is_error(ret2)) {
7948 ret = ret2;
7949 }
7950 }
7951 break;
7952 }
7953#endif
7954#else
7955 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007956#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007957 case TARGET_NR_sendfile64:
7958#endif
bellard5cd43932003-03-29 16:54:36 +00007959 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007960#endif
7961
bellardebc05482003-09-30 21:08:41 +00007962#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007963 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007964 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007965#endif
7966#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007967 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007968 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007969#endif
bellard048f6b42005-11-26 18:47:20 +00007970#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007971 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007972 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7973 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007974 break;
bellard048f6b42005-11-26 18:47:20 +00007975#endif
bellardebc05482003-09-30 21:08:41 +00007976#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007977 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007978 {
7979 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007980 int resource = target_to_host_resource(arg1);
7981 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007982 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007983 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007984 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7985 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007986 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7987 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007988 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007989 }
7990 break;
7991 }
bellardebc05482003-09-30 21:08:41 +00007992#endif
bellarda315a142005-01-30 22:59:18 +00007993#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007994 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007995 if (!(p = lock_user_string(arg1)))
7996 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007997 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7998 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007999 break;
bellarda315a142005-01-30 22:59:18 +00008000#endif
8001#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008002 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008003 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008004 break;
bellarda315a142005-01-30 22:59:18 +00008005#endif
8006#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008007 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008008 if (!(p = lock_user_string(arg1)))
8009 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008010 ret = get_errno(stat(path(p), &st));
8011 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008012 if (!is_error(ret))
8013 ret = host_to_target_stat64(cpu_env, arg2, &st);
8014 break;
bellarda315a142005-01-30 22:59:18 +00008015#endif
8016#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008017 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008018 if (!(p = lock_user_string(arg1)))
8019 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008020 ret = get_errno(lstat(path(p), &st));
8021 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008022 if (!is_error(ret))
8023 ret = host_to_target_stat64(cpu_env, arg2, &st);
8024 break;
bellarda315a142005-01-30 22:59:18 +00008025#endif
8026#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008027 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008028 ret = get_errno(fstat(arg1, &st));
8029 if (!is_error(ret))
8030 ret = host_to_target_stat64(cpu_env, arg2, &st);
8031 break;
bellardec86b0f2003-04-11 00:15:04 +00008032#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008033#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008034#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008035 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008036#endif
8037#ifdef TARGET_NR_newfstatat
8038 case TARGET_NR_newfstatat:
8039#endif
balrog6a24a772008-09-20 02:23:36 +00008040 if (!(p = lock_user_string(arg2)))
8041 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008042 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008043 if (!is_error(ret))
8044 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008045 break;
bellarda315a142005-01-30 22:59:18 +00008046#endif
bellard67867302003-11-23 17:05:30 +00008047 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008048 if (!(p = lock_user_string(arg1)))
8049 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008050 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8051 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008052 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008053#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008054 case TARGET_NR_getuid:
8055 ret = get_errno(high2lowuid(getuid()));
8056 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008057#endif
8058#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008059 case TARGET_NR_getgid:
8060 ret = get_errno(high2lowgid(getgid()));
8061 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008062#endif
8063#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008064 case TARGET_NR_geteuid:
8065 ret = get_errno(high2lowuid(geteuid()));
8066 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008067#endif
8068#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008069 case TARGET_NR_getegid:
8070 ret = get_errno(high2lowgid(getegid()));
8071 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008072#endif
bellard67867302003-11-23 17:05:30 +00008073 case TARGET_NR_setreuid:
8074 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8075 break;
8076 case TARGET_NR_setregid:
8077 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8078 break;
8079 case TARGET_NR_getgroups:
8080 {
8081 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008082 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008083 gid_t *grouplist;
8084 int i;
8085
8086 grouplist = alloca(gidsetsize * sizeof(gid_t));
8087 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008088 if (gidsetsize == 0)
8089 break;
bellard67867302003-11-23 17:05:30 +00008090 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008091 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008092 if (!target_grouplist)
8093 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008094 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008095 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008096 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008097 }
8098 }
8099 break;
8100 case TARGET_NR_setgroups:
8101 {
8102 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008103 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008104 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008105 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008106 if (gidsetsize) {
8107 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008108 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008109 if (!target_grouplist) {
8110 ret = -TARGET_EFAULT;
8111 goto fail;
8112 }
8113 for (i = 0; i < gidsetsize; i++) {
8114 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8115 }
8116 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008117 }
bellard67867302003-11-23 17:05:30 +00008118 ret = get_errno(setgroups(gidsetsize, grouplist));
8119 }
8120 break;
8121 case TARGET_NR_fchown:
8122 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8123 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008124#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008125 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008126 if (!(p = lock_user_string(arg2)))
8127 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008128 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8129 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008130 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008131 break;
8132#endif
bellard67867302003-11-23 17:05:30 +00008133#ifdef TARGET_NR_setresuid
8134 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008135 ret = get_errno(setresuid(low2highuid(arg1),
8136 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008137 low2highuid(arg3)));
8138 break;
8139#endif
8140#ifdef TARGET_NR_getresuid
8141 case TARGET_NR_getresuid:
8142 {
pbrook53a59602006-03-25 19:31:22 +00008143 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008144 ret = get_errno(getresuid(&ruid, &euid, &suid));
8145 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008146 if (put_user_id(high2lowuid(ruid), arg1)
8147 || put_user_id(high2lowuid(euid), arg2)
8148 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008149 goto efault;
bellard67867302003-11-23 17:05:30 +00008150 }
8151 }
8152 break;
8153#endif
8154#ifdef TARGET_NR_getresgid
8155 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008156 ret = get_errno(setresgid(low2highgid(arg1),
8157 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008158 low2highgid(arg3)));
8159 break;
8160#endif
8161#ifdef TARGET_NR_getresgid
8162 case TARGET_NR_getresgid:
8163 {
pbrook53a59602006-03-25 19:31:22 +00008164 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008165 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8166 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008167 if (put_user_id(high2lowgid(rgid), arg1)
8168 || put_user_id(high2lowgid(egid), arg2)
8169 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008170 goto efault;
bellard67867302003-11-23 17:05:30 +00008171 }
8172 }
8173 break;
8174#endif
8175 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008176 if (!(p = lock_user_string(arg1)))
8177 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008178 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8179 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008180 break;
8181 case TARGET_NR_setuid:
8182 ret = get_errno(setuid(low2highuid(arg1)));
8183 break;
8184 case TARGET_NR_setgid:
8185 ret = get_errno(setgid(low2highgid(arg1)));
8186 break;
8187 case TARGET_NR_setfsuid:
8188 ret = get_errno(setfsuid(arg1));
8189 break;
8190 case TARGET_NR_setfsgid:
8191 ret = get_errno(setfsgid(arg1));
8192 break;
bellard67867302003-11-23 17:05:30 +00008193
bellarda315a142005-01-30 22:59:18 +00008194#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008195 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008196 if (!(p = lock_user_string(arg1)))
8197 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008198 ret = get_errno(lchown(p, arg2, arg3));
8199 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008200 break;
bellarda315a142005-01-30 22:59:18 +00008201#endif
8202#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008203 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008204 ret = get_errno(getuid());
8205 break;
bellarda315a142005-01-30 22:59:18 +00008206#endif
aurel3264b4d282008-11-14 17:20:15 +00008207
8208#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8209 /* Alpha specific */
8210 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008211 {
8212 uid_t euid;
8213 euid=geteuid();
8214 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8215 }
aurel3264b4d282008-11-14 17:20:15 +00008216 ret = get_errno(getuid());
8217 break;
8218#endif
8219#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8220 /* Alpha specific */
8221 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008222 {
8223 uid_t egid;
8224 egid=getegid();
8225 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8226 }
aurel3264b4d282008-11-14 17:20:15 +00008227 ret = get_errno(getgid());
8228 break;
8229#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008230#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8231 /* Alpha specific */
8232 case TARGET_NR_osf_getsysinfo:
8233 ret = -TARGET_EOPNOTSUPP;
8234 switch (arg1) {
8235 case TARGET_GSI_IEEE_FP_CONTROL:
8236 {
8237 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8238
8239 /* Copied from linux ieee_fpcr_to_swcr. */
8240 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8241 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8242 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8243 | SWCR_TRAP_ENABLE_DZE
8244 | SWCR_TRAP_ENABLE_OVF);
8245 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8246 | SWCR_TRAP_ENABLE_INE);
8247 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8248 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8249
8250 if (put_user_u64 (swcr, arg2))
8251 goto efault;
8252 ret = 0;
8253 }
8254 break;
8255
8256 /* case GSI_IEEE_STATE_AT_SIGNAL:
8257 -- Not implemented in linux kernel.
8258 case GSI_UACPROC:
8259 -- Retrieves current unaligned access state; not much used.
8260 case GSI_PROC_TYPE:
8261 -- Retrieves implver information; surely not used.
8262 case GSI_GET_HWRPB:
8263 -- Grabs a copy of the HWRPB; surely not used.
8264 */
8265 }
8266 break;
8267#endif
8268#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8269 /* Alpha specific */
8270 case TARGET_NR_osf_setsysinfo:
8271 ret = -TARGET_EOPNOTSUPP;
8272 switch (arg1) {
8273 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008274 {
8275 uint64_t swcr, fpcr, orig_fpcr;
8276
Richard Henderson6e06d512012-06-01 09:08:21 -07008277 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008278 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008279 }
8280 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008281 fpcr = orig_fpcr & FPCR_DYN_MASK;
8282
8283 /* Copied from linux ieee_swcr_to_fpcr. */
8284 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8285 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8286 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8287 | SWCR_TRAP_ENABLE_DZE
8288 | SWCR_TRAP_ENABLE_OVF)) << 48;
8289 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8290 | SWCR_TRAP_ENABLE_INE)) << 57;
8291 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8292 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8293
Richard Henderson6e06d512012-06-01 09:08:21 -07008294 cpu_alpha_store_fpcr(cpu_env, fpcr);
8295 ret = 0;
8296 }
8297 break;
8298
8299 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8300 {
8301 uint64_t exc, fpcr, orig_fpcr;
8302 int si_code;
8303
8304 if (get_user_u64(exc, arg2)) {
8305 goto efault;
8306 }
8307
8308 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8309
8310 /* We only add to the exception status here. */
8311 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8312
8313 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008314 ret = 0;
8315
Richard Henderson6e06d512012-06-01 09:08:21 -07008316 /* Old exceptions are not signaled. */
8317 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008318
Richard Henderson6e06d512012-06-01 09:08:21 -07008319 /* If any exceptions set by this call,
8320 and are unmasked, send a signal. */
8321 si_code = 0;
8322 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8323 si_code = TARGET_FPE_FLTRES;
8324 }
8325 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8326 si_code = TARGET_FPE_FLTUND;
8327 }
8328 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8329 si_code = TARGET_FPE_FLTOVF;
8330 }
8331 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8332 si_code = TARGET_FPE_FLTDIV;
8333 }
8334 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8335 si_code = TARGET_FPE_FLTINV;
8336 }
8337 if (si_code != 0) {
8338 target_siginfo_t info;
8339 info.si_signo = SIGFPE;
8340 info.si_errno = 0;
8341 info.si_code = si_code;
8342 info._sifields._sigfault._addr
8343 = ((CPUArchState *)cpu_env)->pc;
8344 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008345 }
8346 }
8347 break;
8348
8349 /* case SSI_NVPAIRS:
8350 -- Used with SSIN_UACPROC to enable unaligned accesses.
8351 case SSI_IEEE_STATE_AT_SIGNAL:
8352 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8353 -- Not implemented in linux kernel
8354 */
8355 }
8356 break;
8357#endif
8358#ifdef TARGET_NR_osf_sigprocmask
8359 /* Alpha specific. */
8360 case TARGET_NR_osf_sigprocmask:
8361 {
8362 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008363 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008364 sigset_t set, oldset;
8365
8366 switch(arg1) {
8367 case TARGET_SIG_BLOCK:
8368 how = SIG_BLOCK;
8369 break;
8370 case TARGET_SIG_UNBLOCK:
8371 how = SIG_UNBLOCK;
8372 break;
8373 case TARGET_SIG_SETMASK:
8374 how = SIG_SETMASK;
8375 break;
8376 default:
8377 ret = -TARGET_EINVAL;
8378 goto fail;
8379 }
8380 mask = arg2;
8381 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008382 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008383 host_to_target_old_sigset(&mask, &oldset);
8384 ret = mask;
8385 }
8386 break;
8387#endif
aurel3264b4d282008-11-14 17:20:15 +00008388
bellarda315a142005-01-30 22:59:18 +00008389#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008390 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008391 ret = get_errno(getgid());
8392 break;
bellarda315a142005-01-30 22:59:18 +00008393#endif
8394#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008395 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008396 ret = get_errno(geteuid());
8397 break;
bellarda315a142005-01-30 22:59:18 +00008398#endif
8399#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008400 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008401 ret = get_errno(getegid());
8402 break;
bellarda315a142005-01-30 22:59:18 +00008403#endif
8404#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008405 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008406 ret = get_errno(setreuid(arg1, arg2));
8407 break;
bellarda315a142005-01-30 22:59:18 +00008408#endif
8409#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008410 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008411 ret = get_errno(setregid(arg1, arg2));
8412 break;
bellarda315a142005-01-30 22:59:18 +00008413#endif
8414#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008415 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008416 {
8417 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008418 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008419 gid_t *grouplist;
8420 int i;
8421
8422 grouplist = alloca(gidsetsize * sizeof(gid_t));
8423 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008424 if (gidsetsize == 0)
8425 break;
bellard99c475a2005-01-31 20:45:13 +00008426 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008427 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8428 if (!target_grouplist) {
8429 ret = -TARGET_EFAULT;
8430 goto fail;
8431 }
balroga2155fc2008-09-20 02:12:08 +00008432 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008433 target_grouplist[i] = tswap32(grouplist[i]);
8434 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008435 }
8436 }
8437 break;
bellarda315a142005-01-30 22:59:18 +00008438#endif
8439#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008440 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008441 {
8442 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008443 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008444 gid_t *grouplist;
8445 int i;
ths3b46e622007-09-17 08:09:54 +00008446
bellard99c475a2005-01-31 20:45:13 +00008447 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008448 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8449 if (!target_grouplist) {
8450 ret = -TARGET_EFAULT;
8451 goto fail;
8452 }
bellard99c475a2005-01-31 20:45:13 +00008453 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008454 grouplist[i] = tswap32(target_grouplist[i]);
8455 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008456 ret = get_errno(setgroups(gidsetsize, grouplist));
8457 }
8458 break;
bellarda315a142005-01-30 22:59:18 +00008459#endif
8460#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008461 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008462 ret = get_errno(fchown(arg1, arg2, arg3));
8463 break;
bellarda315a142005-01-30 22:59:18 +00008464#endif
8465#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008466 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008467 ret = get_errno(setresuid(arg1, arg2, arg3));
8468 break;
bellarda315a142005-01-30 22:59:18 +00008469#endif
8470#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008471 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008472 {
pbrook53a59602006-03-25 19:31:22 +00008473 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008474 ret = get_errno(getresuid(&ruid, &euid, &suid));
8475 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008476 if (put_user_u32(ruid, arg1)
8477 || put_user_u32(euid, arg2)
8478 || put_user_u32(suid, arg3))
8479 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008480 }
8481 }
8482 break;
bellarda315a142005-01-30 22:59:18 +00008483#endif
8484#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008485 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008486 ret = get_errno(setresgid(arg1, arg2, arg3));
8487 break;
bellarda315a142005-01-30 22:59:18 +00008488#endif
8489#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008490 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008491 {
pbrook53a59602006-03-25 19:31:22 +00008492 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008493 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8494 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008495 if (put_user_u32(rgid, arg1)
8496 || put_user_u32(egid, arg2)
8497 || put_user_u32(sgid, arg3))
8498 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008499 }
8500 }
8501 break;
bellarda315a142005-01-30 22:59:18 +00008502#endif
8503#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008504 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008505 if (!(p = lock_user_string(arg1)))
8506 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008507 ret = get_errno(chown(p, arg2, arg3));
8508 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008509 break;
bellarda315a142005-01-30 22:59:18 +00008510#endif
8511#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008512 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008513 ret = get_errno(setuid(arg1));
8514 break;
bellarda315a142005-01-30 22:59:18 +00008515#endif
8516#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008517 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008518 ret = get_errno(setgid(arg1));
8519 break;
bellarda315a142005-01-30 22:59:18 +00008520#endif
8521#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008522 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008523 ret = get_errno(setfsuid(arg1));
8524 break;
bellarda315a142005-01-30 22:59:18 +00008525#endif
8526#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008527 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008528 ret = get_errno(setfsgid(arg1));
8529 break;
bellarda315a142005-01-30 22:59:18 +00008530#endif
bellard67867302003-11-23 17:05:30 +00008531
bellard31e31b82003-02-18 22:55:36 +00008532 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008533 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008534#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008535 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008536 {
8537 void *a;
8538 ret = -TARGET_EFAULT;
8539 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8540 goto efault;
8541 if (!(p = lock_user_string(arg3)))
8542 goto mincore_fail;
8543 ret = get_errno(mincore(a, arg2, p));
8544 unlock_user(p, arg3, ret);
8545 mincore_fail:
8546 unlock_user(a, arg1, 0);
8547 }
8548 break;
bellardffa65c32004-01-04 23:57:22 +00008549#endif
aurel32408321b2008-10-01 21:46:32 +00008550#ifdef TARGET_NR_arm_fadvise64_64
8551 case TARGET_NR_arm_fadvise64_64:
8552 {
8553 /*
8554 * arm_fadvise64_64 looks like fadvise64_64 but
8555 * with different argument order
8556 */
8557 abi_long temp;
8558 temp = arg3;
8559 arg3 = arg4;
8560 arg4 = temp;
8561 }
8562#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008563#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008564#ifdef TARGET_NR_fadvise64_64
8565 case TARGET_NR_fadvise64_64:
8566#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008567#ifdef TARGET_NR_fadvise64
8568 case TARGET_NR_fadvise64:
8569#endif
8570#ifdef TARGET_S390X
8571 switch (arg4) {
8572 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8573 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8574 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8575 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8576 default: break;
8577 }
8578#endif
8579 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008580 break;
8581#endif
bellardffa65c32004-01-04 23:57:22 +00008582#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008583 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008584 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008585 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008586 This will break MADV_DONTNEED.
8587 This is a hint, so ignoring and returning success is ok. */
8588 ret = get_errno(0);
8589 break;
bellardffa65c32004-01-04 23:57:22 +00008590#endif
blueswir1992f48a2007-10-14 16:27:31 +00008591#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008592 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008593 {
thsb1e341e2007-03-20 21:50:52 +00008594 int cmd;
bellard77e46722003-04-29 20:39:06 +00008595 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008596 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008597#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008598 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008599#endif
bellard77e46722003-04-29 20:39:06 +00008600
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008601 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008602 if (cmd == -TARGET_EINVAL) {
8603 ret = cmd;
8604 break;
8605 }
thsb1e341e2007-03-20 21:50:52 +00008606
bellard60cd49d2003-03-16 22:53:56 +00008607 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008608 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008609#ifdef TARGET_ARM
8610 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008611 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8612 goto efault;
ths58134272007-03-31 18:59:32 +00008613 fl.l_type = tswap16(target_efl->l_type);
8614 fl.l_whence = tswap16(target_efl->l_whence);
8615 fl.l_start = tswap64(target_efl->l_start);
8616 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008617 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008618 unlock_user_struct(target_efl, arg3, 0);
8619 } else
8620#endif
8621 {
bellard9ee1fa22007-11-11 15:11:19 +00008622 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8623 goto efault;
ths58134272007-03-31 18:59:32 +00008624 fl.l_type = tswap16(target_fl->l_type);
8625 fl.l_whence = tswap16(target_fl->l_whence);
8626 fl.l_start = tswap64(target_fl->l_start);
8627 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008628 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008629 unlock_user_struct(target_fl, arg3, 0);
8630 }
thsb1e341e2007-03-20 21:50:52 +00008631 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008632 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008633#ifdef TARGET_ARM
8634 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008635 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8636 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008637 target_efl->l_type = tswap16(fl.l_type);
8638 target_efl->l_whence = tswap16(fl.l_whence);
8639 target_efl->l_start = tswap64(fl.l_start);
8640 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008641 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008642 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008643 } else
8644#endif
8645 {
bellard9ee1fa22007-11-11 15:11:19 +00008646 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8647 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008648 target_fl->l_type = tswap16(fl.l_type);
8649 target_fl->l_whence = tswap16(fl.l_whence);
8650 target_fl->l_start = tswap64(fl.l_start);
8651 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008652 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008653 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008654 }
bellard77e46722003-04-29 20:39:06 +00008655 }
8656 break;
8657
thsb1e341e2007-03-20 21:50:52 +00008658 case TARGET_F_SETLK64:
8659 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008660#ifdef TARGET_ARM
8661 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008662 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8663 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008664 fl.l_type = tswap16(target_efl->l_type);
8665 fl.l_whence = tswap16(target_efl->l_whence);
8666 fl.l_start = tswap64(target_efl->l_start);
8667 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008668 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008669 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008670 } else
8671#endif
8672 {
bellard9ee1fa22007-11-11 15:11:19 +00008673 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8674 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008675 fl.l_type = tswap16(target_fl->l_type);
8676 fl.l_whence = tswap16(target_fl->l_whence);
8677 fl.l_start = tswap64(target_fl->l_start);
8678 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008679 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008680 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008681 }
thsb1e341e2007-03-20 21:50:52 +00008682 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008683 break;
bellard60cd49d2003-03-16 22:53:56 +00008684 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008685 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008686 break;
8687 }
bellard77e46722003-04-29 20:39:06 +00008688 break;
8689 }
bellard60cd49d2003-03-16 22:53:56 +00008690#endif
ths7d600c82006-12-08 01:32:58 +00008691#ifdef TARGET_NR_cacheflush
8692 case TARGET_NR_cacheflush:
8693 /* self-modifying code is handled automatically, so nothing needed */
8694 ret = 0;
8695 break;
8696#endif
bellardebc05482003-09-30 21:08:41 +00008697#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008698 case TARGET_NR_security:
8699 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008700#endif
bellardc573ff62004-01-04 15:51:36 +00008701#ifdef TARGET_NR_getpagesize
8702 case TARGET_NR_getpagesize:
8703 ret = TARGET_PAGE_SIZE;
8704 break;
8705#endif
bellard31e31b82003-02-18 22:55:36 +00008706 case TARGET_NR_gettid:
8707 ret = get_errno(gettid());
8708 break;
thse5febef2007-04-01 18:31:35 +00008709#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008710 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008711#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008712 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008713 arg2 = arg3;
8714 arg3 = arg4;
8715 arg4 = arg5;
8716 }
aurel322054ac92008-10-13 21:08:07 +00008717 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8718#else
8719 ret = get_errno(readahead(arg1, arg2, arg3));
8720#endif
8721 break;
thse5febef2007-04-01 18:31:35 +00008722#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008723#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008724#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008725 case TARGET_NR_listxattr:
8726 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008727 {
8728 void *p, *b = 0;
8729 if (arg2) {
8730 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8731 if (!b) {
8732 ret = -TARGET_EFAULT;
8733 break;
8734 }
8735 }
8736 p = lock_user_string(arg1);
8737 if (p) {
8738 if (num == TARGET_NR_listxattr) {
8739 ret = get_errno(listxattr(p, b, arg3));
8740 } else {
8741 ret = get_errno(llistxattr(p, b, arg3));
8742 }
8743 } else {
8744 ret = -TARGET_EFAULT;
8745 }
8746 unlock_user(p, arg1, 0);
8747 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008748 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008749 }
8750 case TARGET_NR_flistxattr:
8751 {
8752 void *b = 0;
8753 if (arg2) {
8754 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8755 if (!b) {
8756 ret = -TARGET_EFAULT;
8757 break;
8758 }
8759 }
8760 ret = get_errno(flistxattr(arg1, b, arg3));
8761 unlock_user(b, arg2, arg3);
8762 break;
8763 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008764 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008765 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008766 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008767 void *p, *n, *v = 0;
8768 if (arg3) {
8769 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8770 if (!v) {
8771 ret = -TARGET_EFAULT;
8772 break;
8773 }
8774 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008775 p = lock_user_string(arg1);
8776 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008777 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008778 if (num == TARGET_NR_setxattr) {
8779 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8780 } else {
8781 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8782 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008783 } else {
8784 ret = -TARGET_EFAULT;
8785 }
8786 unlock_user(p, arg1, 0);
8787 unlock_user(n, arg2, 0);
8788 unlock_user(v, arg3, 0);
8789 }
8790 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008791 case TARGET_NR_fsetxattr:
8792 {
8793 void *n, *v = 0;
8794 if (arg3) {
8795 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8796 if (!v) {
8797 ret = -TARGET_EFAULT;
8798 break;
8799 }
8800 }
8801 n = lock_user_string(arg2);
8802 if (n) {
8803 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8804 } else {
8805 ret = -TARGET_EFAULT;
8806 }
8807 unlock_user(n, arg2, 0);
8808 unlock_user(v, arg3, 0);
8809 }
8810 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008811 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008812 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008813 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008814 void *p, *n, *v = 0;
8815 if (arg3) {
8816 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8817 if (!v) {
8818 ret = -TARGET_EFAULT;
8819 break;
8820 }
8821 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008822 p = lock_user_string(arg1);
8823 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008824 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008825 if (num == TARGET_NR_getxattr) {
8826 ret = get_errno(getxattr(p, n, v, arg4));
8827 } else {
8828 ret = get_errno(lgetxattr(p, n, v, arg4));
8829 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008830 } else {
8831 ret = -TARGET_EFAULT;
8832 }
8833 unlock_user(p, arg1, 0);
8834 unlock_user(n, arg2, 0);
8835 unlock_user(v, arg3, arg4);
8836 }
8837 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008838 case TARGET_NR_fgetxattr:
8839 {
8840 void *n, *v = 0;
8841 if (arg3) {
8842 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8843 if (!v) {
8844 ret = -TARGET_EFAULT;
8845 break;
8846 }
8847 }
8848 n = lock_user_string(arg2);
8849 if (n) {
8850 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8851 } else {
8852 ret = -TARGET_EFAULT;
8853 }
8854 unlock_user(n, arg2, 0);
8855 unlock_user(v, arg3, arg4);
8856 }
8857 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008858 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008859 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008860 {
8861 void *p, *n;
8862 p = lock_user_string(arg1);
8863 n = lock_user_string(arg2);
8864 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008865 if (num == TARGET_NR_removexattr) {
8866 ret = get_errno(removexattr(p, n));
8867 } else {
8868 ret = get_errno(lremovexattr(p, n));
8869 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008870 } else {
8871 ret = -TARGET_EFAULT;
8872 }
8873 unlock_user(p, arg1, 0);
8874 unlock_user(n, arg2, 0);
8875 }
8876 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008877 case TARGET_NR_fremovexattr:
8878 {
8879 void *n;
8880 n = lock_user_string(arg2);
8881 if (n) {
8882 ret = get_errno(fremovexattr(arg1, n));
8883 } else {
8884 ret = -TARGET_EFAULT;
8885 }
8886 unlock_user(n, arg2, 0);
8887 }
8888 break;
bellardebc05482003-09-30 21:08:41 +00008889#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008890#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008891#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008892 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008893#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02008894 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00008895 ret = 0;
8896 break;
edgar_iglef967792009-01-07 14:19:38 +00008897#elif defined(TARGET_CRIS)
8898 if (arg1 & 0xff)
8899 ret = -TARGET_EINVAL;
8900 else {
8901 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8902 ret = 0;
8903 }
8904 break;
bellard8d18e892007-11-14 15:18:40 +00008905#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8906 ret = do_set_thread_area(cpu_env, arg1);
8907 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008908#elif defined(TARGET_M68K)
8909 {
Andreas Färber0429a972013-08-26 18:14:44 +02008910 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008911 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008912 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008913 break;
8914 }
ths6f5b89a2007-03-02 20:48:00 +00008915#else
8916 goto unimplemented_nowarn;
8917#endif
8918#endif
8919#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008920 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008921#if defined(TARGET_I386) && defined(TARGET_ABI32)
8922 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008923 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008924#elif defined(TARGET_M68K)
8925 {
Andreas Färber0429a972013-08-26 18:14:44 +02008926 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008927 ret = ts->tp_value;
8928 break;
8929 }
bellard8d18e892007-11-14 15:18:40 +00008930#else
bellard5cd43932003-03-29 16:54:36 +00008931 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008932#endif
bellard8d18e892007-11-14 15:18:40 +00008933#endif
bellard48dc41e2006-06-21 18:15:50 +00008934#ifdef TARGET_NR_getdomainname
8935 case TARGET_NR_getdomainname:
8936 goto unimplemented_nowarn;
8937#endif
ths6f5b89a2007-03-02 20:48:00 +00008938
thsb5906f92007-03-19 13:32:45 +00008939#ifdef TARGET_NR_clock_gettime
8940 case TARGET_NR_clock_gettime:
8941 {
8942 struct timespec ts;
8943 ret = get_errno(clock_gettime(arg1, &ts));
8944 if (!is_error(ret)) {
8945 host_to_target_timespec(arg2, &ts);
8946 }
8947 break;
8948 }
8949#endif
8950#ifdef TARGET_NR_clock_getres
8951 case TARGET_NR_clock_getres:
8952 {
8953 struct timespec ts;
8954 ret = get_errno(clock_getres(arg1, &ts));
8955 if (!is_error(ret)) {
8956 host_to_target_timespec(arg2, &ts);
8957 }
8958 break;
8959 }
8960#endif
pbrook63d76512008-05-29 13:43:29 +00008961#ifdef TARGET_NR_clock_nanosleep
8962 case TARGET_NR_clock_nanosleep:
8963 {
8964 struct timespec ts;
8965 target_to_host_timespec(&ts, arg3);
8966 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8967 if (arg4)
8968 host_to_target_timespec(arg4, &ts);
8969 break;
8970 }
8971#endif
thsb5906f92007-03-19 13:32:45 +00008972
ths6f5b89a2007-03-02 20:48:00 +00008973#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8974 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008975 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8976 break;
ths6f5b89a2007-03-02 20:48:00 +00008977#endif
8978
ths3ae43202007-09-16 21:39:48 +00008979#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008980 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008981 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008982 break;
8983#endif
8984
ths3ae43202007-09-16 21:39:48 +00008985#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008986 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008987 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8988 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008989 break;
8990#endif
8991
ths4f2b1fe2007-06-21 21:57:12 +00008992#ifdef TARGET_NR_set_robust_list
8993 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008994 case TARGET_NR_get_robust_list:
8995 /* The ABI for supporting robust futexes has userspace pass
8996 * the kernel a pointer to a linked list which is updated by
8997 * userspace after the syscall; the list is walked by the kernel
8998 * when the thread exits. Since the linked list in QEMU guest
8999 * memory isn't a valid linked list for the host and we have
9000 * no way to reliably intercept the thread-death event, we can't
9001 * support these. Silently return ENOSYS so that guest userspace
9002 * falls back to a non-robust futex implementation (which should
9003 * be OK except in the corner case of the guest crashing while
9004 * holding a mutex that is shared with another process via
9005 * shared memory).
9006 */
9007 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009008#endif
9009
Peter Maydell1acae9f2013-07-02 14:04:12 +01009010#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009011 case TARGET_NR_utimensat:
9012 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009013 struct timespec *tsp, ts[2];
9014 if (!arg3) {
9015 tsp = NULL;
9016 } else {
9017 target_to_host_timespec(ts, arg3);
9018 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9019 tsp = ts;
9020 }
ths9007f0e2007-09-25 17:50:37 +00009021 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009022 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009023 else {
bellard579a97f2007-11-11 14:26:47 +00009024 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009025 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009026 goto fail;
9027 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009028 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009029 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009030 }
9031 }
9032 break;
9033#endif
pbrookbd0c5662008-05-29 14:34:11 +00009034 case TARGET_NR_futex:
9035 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9036 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009037#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009038 case TARGET_NR_inotify_init:
9039 ret = get_errno(sys_inotify_init());
9040 break;
9041#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009042#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009043#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9044 case TARGET_NR_inotify_init1:
9045 ret = get_errno(sys_inotify_init1(arg1));
9046 break;
9047#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009048#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009049#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009050 case TARGET_NR_inotify_add_watch:
9051 p = lock_user_string(arg2);
9052 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9053 unlock_user(p, arg2, 0);
9054 break;
9055#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009056#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009057 case TARGET_NR_inotify_rm_watch:
9058 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9059 break;
9060#endif
ths9007f0e2007-09-25 17:50:37 +00009061
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009062#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009063 case TARGET_NR_mq_open:
9064 {
9065 struct mq_attr posix_mq_attr;
9066
9067 p = lock_user_string(arg1 - 1);
9068 if (arg4 != 0)
9069 copy_from_user_mq_attr (&posix_mq_attr, arg4);
9070 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
9071 unlock_user (p, arg1, 0);
9072 }
9073 break;
9074
9075 case TARGET_NR_mq_unlink:
9076 p = lock_user_string(arg1 - 1);
9077 ret = get_errno(mq_unlink(p));
9078 unlock_user (p, arg1, 0);
9079 break;
9080
9081 case TARGET_NR_mq_timedsend:
9082 {
9083 struct timespec ts;
9084
9085 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9086 if (arg5 != 0) {
9087 target_to_host_timespec(&ts, arg5);
9088 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9089 host_to_target_timespec(arg5, &ts);
9090 }
9091 else
9092 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9093 unlock_user (p, arg2, arg3);
9094 }
9095 break;
9096
9097 case TARGET_NR_mq_timedreceive:
9098 {
9099 struct timespec ts;
9100 unsigned int prio;
9101
9102 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9103 if (arg5 != 0) {
9104 target_to_host_timespec(&ts, arg5);
9105 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9106 host_to_target_timespec(arg5, &ts);
9107 }
9108 else
9109 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9110 unlock_user (p, arg2, arg3);
9111 if (arg4 != 0)
9112 put_user_u32(prio, arg4);
9113 }
9114 break;
9115
9116 /* Not implemented for now... */
9117/* case TARGET_NR_mq_notify: */
9118/* break; */
9119
9120 case TARGET_NR_mq_getsetattr:
9121 {
9122 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9123 ret = 0;
9124 if (arg3 != 0) {
9125 ret = mq_getattr(arg1, &posix_mq_attr_out);
9126 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9127 }
9128 if (arg2 != 0) {
9129 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9130 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9131 }
9132
9133 }
9134 break;
9135#endif
9136
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309137#ifdef CONFIG_SPLICE
9138#ifdef TARGET_NR_tee
9139 case TARGET_NR_tee:
9140 {
9141 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9142 }
9143 break;
9144#endif
9145#ifdef TARGET_NR_splice
9146 case TARGET_NR_splice:
9147 {
9148 loff_t loff_in, loff_out;
9149 loff_t *ploff_in = NULL, *ploff_out = NULL;
9150 if(arg2) {
9151 get_user_u64(loff_in, arg2);
9152 ploff_in = &loff_in;
9153 }
9154 if(arg4) {
9155 get_user_u64(loff_out, arg2);
9156 ploff_out = &loff_out;
9157 }
9158 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9159 }
9160 break;
9161#endif
9162#ifdef TARGET_NR_vmsplice
9163 case TARGET_NR_vmsplice:
9164 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009165 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9166 if (vec != NULL) {
9167 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9168 unlock_iovec(vec, arg2, arg3, 0);
9169 } else {
9170 ret = -host_to_target_errno(errno);
9171 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309172 }
9173 break;
9174#endif
9175#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009176#ifdef CONFIG_EVENTFD
9177#if defined(TARGET_NR_eventfd)
9178 case TARGET_NR_eventfd:
9179 ret = get_errno(eventfd(arg1, 0));
9180 break;
9181#endif
9182#if defined(TARGET_NR_eventfd2)
9183 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009184 {
9185 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9186 if (arg2 & TARGET_O_NONBLOCK) {
9187 host_flags |= O_NONBLOCK;
9188 }
9189 if (arg2 & TARGET_O_CLOEXEC) {
9190 host_flags |= O_CLOEXEC;
9191 }
9192 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009193 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009194 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009195#endif
9196#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009197#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9198 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009199#if TARGET_ABI_BITS == 32
9200 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9201 target_offset64(arg5, arg6)));
9202#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009203 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009204#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009205 break;
9206#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009207#if defined(CONFIG_SYNC_FILE_RANGE)
9208#if defined(TARGET_NR_sync_file_range)
9209 case TARGET_NR_sync_file_range:
9210#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009211#if defined(TARGET_MIPS)
9212 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9213 target_offset64(arg5, arg6), arg7));
9214#else
Peter Maydellc727f472011-01-06 11:05:10 +00009215 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9216 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009217#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009218#else
9219 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9220#endif
9221 break;
9222#endif
9223#if defined(TARGET_NR_sync_file_range2)
9224 case TARGET_NR_sync_file_range2:
9225 /* This is like sync_file_range but the arguments are reordered */
9226#if TARGET_ABI_BITS == 32
9227 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9228 target_offset64(arg5, arg6), arg2));
9229#else
9230 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9231#endif
9232 break;
9233#endif
9234#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009235#if defined(CONFIG_EPOLL)
9236#if defined(TARGET_NR_epoll_create)
9237 case TARGET_NR_epoll_create:
9238 ret = get_errno(epoll_create(arg1));
9239 break;
9240#endif
9241#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9242 case TARGET_NR_epoll_create1:
9243 ret = get_errno(epoll_create1(arg1));
9244 break;
9245#endif
9246#if defined(TARGET_NR_epoll_ctl)
9247 case TARGET_NR_epoll_ctl:
9248 {
9249 struct epoll_event ep;
9250 struct epoll_event *epp = 0;
9251 if (arg4) {
9252 struct target_epoll_event *target_ep;
9253 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9254 goto efault;
9255 }
9256 ep.events = tswap32(target_ep->events);
9257 /* The epoll_data_t union is just opaque data to the kernel,
9258 * so we transfer all 64 bits across and need not worry what
9259 * actual data type it is.
9260 */
9261 ep.data.u64 = tswap64(target_ep->data.u64);
9262 unlock_user_struct(target_ep, arg4, 0);
9263 epp = &ep;
9264 }
9265 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9266 break;
9267 }
9268#endif
9269
9270#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9271#define IMPLEMENT_EPOLL_PWAIT
9272#endif
9273#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9274#if defined(TARGET_NR_epoll_wait)
9275 case TARGET_NR_epoll_wait:
9276#endif
9277#if defined(IMPLEMENT_EPOLL_PWAIT)
9278 case TARGET_NR_epoll_pwait:
9279#endif
9280 {
9281 struct target_epoll_event *target_ep;
9282 struct epoll_event *ep;
9283 int epfd = arg1;
9284 int maxevents = arg3;
9285 int timeout = arg4;
9286
9287 target_ep = lock_user(VERIFY_WRITE, arg2,
9288 maxevents * sizeof(struct target_epoll_event), 1);
9289 if (!target_ep) {
9290 goto efault;
9291 }
9292
9293 ep = alloca(maxevents * sizeof(struct epoll_event));
9294
9295 switch (num) {
9296#if defined(IMPLEMENT_EPOLL_PWAIT)
9297 case TARGET_NR_epoll_pwait:
9298 {
9299 target_sigset_t *target_set;
9300 sigset_t _set, *set = &_set;
9301
9302 if (arg5) {
9303 target_set = lock_user(VERIFY_READ, arg5,
9304 sizeof(target_sigset_t), 1);
9305 if (!target_set) {
9306 unlock_user(target_ep, arg2, 0);
9307 goto efault;
9308 }
9309 target_to_host_sigset(set, target_set);
9310 unlock_user(target_set, arg5, 0);
9311 } else {
9312 set = NULL;
9313 }
9314
9315 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9316 break;
9317 }
9318#endif
9319#if defined(TARGET_NR_epoll_wait)
9320 case TARGET_NR_epoll_wait:
9321 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9322 break;
9323#endif
9324 default:
9325 ret = -TARGET_ENOSYS;
9326 }
9327 if (!is_error(ret)) {
9328 int i;
9329 for (i = 0; i < ret; i++) {
9330 target_ep[i].events = tswap32(ep[i].events);
9331 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9332 }
9333 }
9334 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9335 break;
9336 }
9337#endif
9338#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009339#ifdef TARGET_NR_prlimit64
9340 case TARGET_NR_prlimit64:
9341 {
9342 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9343 struct target_rlimit64 *target_rnew, *target_rold;
9344 struct host_rlimit64 rnew, rold, *rnewp = 0;
9345 if (arg3) {
9346 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9347 goto efault;
9348 }
9349 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9350 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9351 unlock_user_struct(target_rnew, arg3, 0);
9352 rnewp = &rnew;
9353 }
9354
9355 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9356 if (!is_error(ret) && arg4) {
9357 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9358 goto efault;
9359 }
9360 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9361 target_rold->rlim_max = tswap64(rold.rlim_max);
9362 unlock_user_struct(target_rold, arg4, 1);
9363 }
9364 break;
9365 }
9366#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009367#ifdef TARGET_NR_gethostname
9368 case TARGET_NR_gethostname:
9369 {
9370 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9371 if (name) {
9372 ret = get_errno(gethostname(name, arg2));
9373 unlock_user(name, arg1, arg2);
9374 } else {
9375 ret = -TARGET_EFAULT;
9376 }
9377 break;
9378 }
9379#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009380#ifdef TARGET_NR_atomic_cmpxchg_32
9381 case TARGET_NR_atomic_cmpxchg_32:
9382 {
9383 /* should use start_exclusive from main.c */
9384 abi_ulong mem_value;
9385 if (get_user_u32(mem_value, arg6)) {
9386 target_siginfo_t info;
9387 info.si_signo = SIGSEGV;
9388 info.si_errno = 0;
9389 info.si_code = TARGET_SEGV_MAPERR;
9390 info._sifields._sigfault._addr = arg6;
9391 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9392 ret = 0xdeadbeef;
9393
9394 }
9395 if (mem_value == arg2)
9396 put_user_u32(arg1, arg6);
9397 ret = mem_value;
9398 break;
9399 }
9400#endif
9401#ifdef TARGET_NR_atomic_barrier
9402 case TARGET_NR_atomic_barrier:
9403 {
9404 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009405 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009406 break;
9407 }
9408#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009409
9410#ifdef TARGET_NR_timer_create
9411 case TARGET_NR_timer_create:
9412 {
9413 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9414
9415 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9416 struct target_sigevent *ptarget_sevp;
9417 struct target_timer_t *ptarget_timer;
9418
9419 int clkid = arg1;
9420 int timer_index = next_free_host_timer();
9421
9422 if (timer_index < 0) {
9423 ret = -TARGET_EAGAIN;
9424 } else {
9425 timer_t *phtimer = g_posix_timers + timer_index;
9426
9427 if (arg2) {
9428 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9429 goto efault;
9430 }
9431
9432 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9433 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9434
9435 phost_sevp = &host_sevp;
9436 }
9437
9438 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9439 if (ret) {
9440 phtimer = NULL;
9441 } else {
9442 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9443 goto efault;
9444 }
9445 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9446 unlock_user_struct(ptarget_timer, arg3, 1);
9447 }
9448 }
9449 break;
9450 }
9451#endif
9452
9453#ifdef TARGET_NR_timer_settime
9454 case TARGET_NR_timer_settime:
9455 {
9456 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9457 * struct itimerspec * old_value */
9458 arg1 &= 0xffff;
9459 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9460 ret = -TARGET_EINVAL;
9461 } else {
9462 timer_t htimer = g_posix_timers[arg1];
9463 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9464
9465 target_to_host_itimerspec(&hspec_new, arg3);
9466 ret = get_errno(
9467 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9468 host_to_target_itimerspec(arg2, &hspec_old);
9469 }
9470 break;
9471 }
9472#endif
9473
9474#ifdef TARGET_NR_timer_gettime
9475 case TARGET_NR_timer_gettime:
9476 {
9477 /* args: timer_t timerid, struct itimerspec *curr_value */
9478 arg1 &= 0xffff;
9479 if (!arg2) {
9480 return -TARGET_EFAULT;
9481 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9482 ret = -TARGET_EINVAL;
9483 } else {
9484 timer_t htimer = g_posix_timers[arg1];
9485 struct itimerspec hspec;
9486 ret = get_errno(timer_gettime(htimer, &hspec));
9487
9488 if (host_to_target_itimerspec(arg2, &hspec)) {
9489 ret = -TARGET_EFAULT;
9490 }
9491 }
9492 break;
9493 }
9494#endif
9495
9496#ifdef TARGET_NR_timer_getoverrun
9497 case TARGET_NR_timer_getoverrun:
9498 {
9499 /* args: timer_t timerid */
9500 arg1 &= 0xffff;
9501 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9502 ret = -TARGET_EINVAL;
9503 } else {
9504 timer_t htimer = g_posix_timers[arg1];
9505 ret = get_errno(timer_getoverrun(htimer));
9506 }
9507 break;
9508 }
9509#endif
9510
9511#ifdef TARGET_NR_timer_delete
9512 case TARGET_NR_timer_delete:
9513 {
9514 /* args: timer_t timerid */
9515 arg1 &= 0xffff;
9516 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9517 ret = -TARGET_EINVAL;
9518 } else {
9519 timer_t htimer = g_posix_timers[arg1];
9520 ret = get_errno(timer_delete(htimer));
9521 g_posix_timers[arg1] = 0;
9522 }
9523 break;
9524 }
9525#endif
9526
bellard31e31b82003-02-18 22:55:36 +00009527 default:
9528 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009529 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009530#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 +00009531 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009532#endif
ths0da46a62007-10-20 20:23:07 +00009533 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009534 break;
9535 }
bellard579a97f2007-11-11 14:26:47 +00009536fail:
bellardc573ff62004-01-04 15:51:36 +00009537#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009538 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009539#endif
thsb92c47c2007-11-01 00:07:38 +00009540 if(do_strace)
9541 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009542 return ret;
bellard579a97f2007-11-11 14:26:47 +00009543efault:
9544 ret = -TARGET_EFAULT;
9545 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009546}