blob: 44853d090a225d68e76681ffb986c9898c4a181a [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>
Riku Voipio51834342014-06-22 11:25:42 +010061#include <sys/timerfd.h>
bellardebc05482003-09-30 21:08:41 +000062#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000063#include <sys/sysinfo.h>
bellard72f03902003-02-18 23:33:18 +000064//#include <sys/user.h>
bellard8853f862004-02-22 14:57:26 +000065#include <netinet/ip.h>
bellard7854b052003-03-29 17:22:23 +000066#include <netinet/tcp.h>
Laurent Vivier86fcd942011-03-30 01:35:23 +020067#include <linux/wireless.h>
Jing Huang920394d2012-07-24 13:59:23 +000068#include <linux/icmp.h>
Stefan Weil5a61cb62011-09-08 17:55:32 +020069#include "qemu-common.h"
Juan Quintela9788c9c2009-07-27 16:13:02 +020070#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +000071#include <sys/gmon.h>
72#endif
Riku Voipioc2882b92009-08-12 15:08:24 +030073#ifdef CONFIG_EVENTFD
74#include <sys/eventfd.h>
75#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +000076#ifdef CONFIG_EPOLL
77#include <sys/epoll.h>
78#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -070079#ifdef CONFIG_ATTR
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010080#include "qemu/xattr.h"
An-Cheng Huanga790ae32011-08-09 12:34:06 -070081#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +000082#ifdef CONFIG_SENDFILE
83#include <sys/sendfile.h>
84#endif
bellard31e31b82003-02-18 22:55:36 +000085
86#define termios host_termios
87#define winsize host_winsize
88#define termio host_termio
bellard04369ff2003-03-20 22:33:23 +000089#define sgttyb host_sgttyb /* same as target */
90#define tchars host_tchars /* same as target */
91#define ltchars host_ltchars /* same as target */
bellard31e31b82003-02-18 22:55:36 +000092
93#include <linux/termios.h>
94#include <linux/unistd.h>
bellard31e31b82003-02-18 22:55:36 +000095#include <linux/cdrom.h>
96#include <linux/hdreg.h>
97#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000098#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +000099#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300100#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000101#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000102#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000103#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200104#include <linux/fb.h>
105#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100106#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000107#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100108#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200109#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100110#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000111#include "linux_loop.h"
Riku Voipio18cb0082014-02-19 12:59:58 +0200112#include "uname.h"
bellard31e31b82003-02-18 22:55:36 +0000113
bellard3ef693a2003-03-23 20:17:16 +0000114#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000115
pbrookd865bab2008-06-07 22:12:17 +0000116#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
117 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000118
bellard72f03902003-02-18 23:33:18 +0000119//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000120
bellard1a9353d2003-03-16 20:28:50 +0000121//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000122#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
123#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000124
bellard70a194b2003-08-11 22:20:16 +0000125
bellard70a194b2003-08-11 22:20:16 +0000126#undef _syscall0
127#undef _syscall1
128#undef _syscall2
129#undef _syscall3
130#undef _syscall4
131#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000132#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000133
bellard83fcb512006-06-14 13:37:16 +0000134#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000135static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000136{ \
137 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000138}
139
bellard83fcb512006-06-14 13:37:16 +0000140#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000141static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000142{ \
143 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000144}
145
bellard83fcb512006-06-14 13:37:16 +0000146#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000147static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000148{ \
149 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000150}
151
bellard83fcb512006-06-14 13:37:16 +0000152#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000153static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000154{ \
155 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000156}
157
bellard83fcb512006-06-14 13:37:16 +0000158#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000159static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000160{ \
161 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000162}
163
bellard83fcb512006-06-14 13:37:16 +0000164#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
165 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000166static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000167{ \
168 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000169}
bellard83fcb512006-06-14 13:37:16 +0000170
171
172#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
173 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000174static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
175 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000176{ \
177 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
178}
179
bellard70a194b2003-08-11 22:20:16 +0000180
bellard31e31b82003-02-18 22:55:36 +0000181#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000182#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000183#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000184#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000185#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000186#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000187#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000188#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000189#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000190#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000191#define __NR_sys_inotify_init __NR_inotify_init
192#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
193#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000194
Alexander Graf42a39fb2011-04-15 17:32:45 +0200195#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
196 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000197#define __NR__llseek __NR_lseek
198#endif
199
James Hogana29e5ba2014-03-25 21:51:08 +0000200/* Newer kernel ports have llseek() instead of _llseek() */
201#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
202#define TARGET_NR__llseek TARGET_NR_llseek
203#endif
204
bellard72f03902003-02-18 23:33:18 +0000205#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000206_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000207#else
ths0da46a62007-10-20 20:23:07 +0000208/* This is a replacement for the host gettid() and must return a host
209 errno. */
bellard72f03902003-02-18 23:33:18 +0000210static int gettid(void) {
211 return -ENOSYS;
212}
213#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100214#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000215_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100216#endif
217#if !defined(__NR_getdents) || \
218 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000219_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
220#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700221#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000222_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
223 loff_t *, res, uint, wh);
224#endif
225_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
226_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
227#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
228_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
229#endif
230#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
231_syscall2(int,sys_tkill,int,tid,int,sig)
232#endif
233#ifdef __NR_exit_group
234_syscall1(int,exit_group,int,error_code)
235#endif
236#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
237_syscall1(int,set_tid_address,int *,tidptr)
238#endif
aurel323b3f24a2009-04-15 16:12:13 +0000239#if defined(TARGET_NR_futex) && defined(__NR_futex)
240_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
241 const struct timespec *,timeout,int *,uaddr2,int,val3)
242#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500243#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
244_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
245 unsigned long *, user_mask_ptr);
246#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
247_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
248 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200249_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
250 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000251_syscall2(int, capget, struct __user_cap_header_struct *, header,
252 struct __user_cap_data_struct *, data);
253_syscall2(int, capset, struct __user_cap_header_struct *, header,
254 struct __user_cap_data_struct *, data);
aurel323b3f24a2009-04-15 16:12:13 +0000255
256static bitmask_transtbl fcntl_flags_tbl[] = {
257 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
258 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
259 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
260 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
261 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
262 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
263 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
264 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700265 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000266 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
267 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
268 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
269 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000270#if defined(O_DIRECT)
271 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
272#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700273#if defined(O_NOATIME)
274 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
275#endif
276#if defined(O_CLOEXEC)
277 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
278#endif
279#if defined(O_PATH)
280 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
281#endif
282 /* Don't terminate the list prematurely on 64-bit host+guest. */
283#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
284 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
285#endif
aurel323b3f24a2009-04-15 16:12:13 +0000286 { 0, 0, 0, 0 }
287};
288
aurel323b3f24a2009-04-15 16:12:13 +0000289static int sys_getcwd1(char *buf, size_t size)
290{
291 if (getcwd(buf, size) == NULL) {
292 /* getcwd() sets errno */
293 return (-1);
294 }
aurel32aaf4ad32009-04-16 14:17:14 +0000295 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000296}
297
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}
Riku Voipioebc996f2009-04-21 15:01:51 +0300309
Peter Maydell1acae9f2013-07-02 14:04:12 +0100310#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300311#ifdef CONFIG_UTIMENSAT
312static int sys_utimensat(int dirfd, const char *pathname,
313 const struct timespec times[2], int flags)
314{
315 if (pathname == NULL)
316 return futimens(dirfd, times);
317 else
318 return utimensat(dirfd, pathname, times, flags);
319}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100320#elif defined(__NR_utimensat)
321#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000322_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
323 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100324#else
325static int sys_utimensat(int dirfd, const char *pathname,
326 const struct timespec times[2], int flags)
327{
328 errno = ENOSYS;
329 return -1;
330}
ths9007f0e2007-09-25 17:50:37 +0000331#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100332#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000333
334#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000335#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000336
aurel3239b59762008-10-01 21:46:50 +0000337#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000338static int sys_inotify_init(void)
339{
340 return (inotify_init());
341}
aurel3239b59762008-10-01 21:46:50 +0000342#endif
343#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000344static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
345{
346 return (inotify_add_watch(fd, pathname, mask));
347}
aurel3239b59762008-10-01 21:46:50 +0000348#endif
349#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000350static int sys_inotify_rm_watch(int fd, int32_t wd)
351{
aurel328690e422009-04-17 13:50:32 +0000352 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000353}
aurel3239b59762008-10-01 21:46:50 +0000354#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000355#ifdef CONFIG_INOTIFY1
356#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
357static int sys_inotify_init1(int flags)
358{
359 return (inotify_init1(flags));
360}
361#endif
362#endif
aurel323b3f24a2009-04-15 16:12:13 +0000363#else
364/* Userspace can usually survive runtime without inotify */
365#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000366#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000367#undef TARGET_NR_inotify_add_watch
368#undef TARGET_NR_inotify_rm_watch
369#endif /* CONFIG_INOTIFY */
370
Mike Frysingerd8035d42011-02-07 01:05:51 -0500371#if defined(TARGET_NR_ppoll)
372#ifndef __NR_ppoll
373# define __NR_ppoll -1
374#endif
375#define __NR_sys_ppoll __NR_ppoll
376_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200377 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500378 size_t, sigsetsize)
379#endif
bellard66fb9762003-03-23 01:06:05 +0000380
Mike Frysinger055e0902011-06-03 17:01:49 -0400381#if defined(TARGET_NR_pselect6)
382#ifndef __NR_pselect6
383# define __NR_pselect6 -1
384#endif
385#define __NR_sys_pselect6 __NR_pselect6
386_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
387 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
388#endif
389
Peter Maydell163a05a2011-06-27 17:44:52 +0100390#if defined(TARGET_NR_prlimit64)
391#ifndef __NR_prlimit64
392# define __NR_prlimit64 -1
393#endif
394#define __NR_sys_prlimit64 __NR_prlimit64
395/* The glibc rlimit structure may not be that used by the underlying syscall */
396struct host_rlimit64 {
397 uint64_t rlim_cur;
398 uint64_t rlim_max;
399};
400_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
401 const struct host_rlimit64 *, new_limit,
402 struct host_rlimit64 *, old_limit)
403#endif
404
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100405
406#if defined(TARGET_NR_timer_create)
407/* Maxiumum of 32 active POSIX timers allowed at any one time. */
408static timer_t g_posix_timers[32] = { 0, } ;
409
410static inline int next_free_host_timer(void)
411{
412 int k ;
413 /* FIXME: Does finding the next free slot require a lock? */
414 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
415 if (g_posix_timers[k] == 0) {
416 g_posix_timers[k] = (timer_t) 1;
417 return k;
418 }
419 }
420 return -1;
421}
422#endif
423
Riku Voipio48e515d2011-07-12 15:40:51 +0300424/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000425#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300426static inline int regpairs_aligned(void *cpu_env) {
427 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
428}
429#elif defined(TARGET_MIPS)
430static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000431#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
432/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
433 * of registers which translates to the same as ARM/MIPS, because we start with
434 * r3 as arg1 */
435static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300436#else
437static inline int regpairs_aligned(void *cpu_env) { return 0; }
438#endif
439
thsb92c47c2007-11-01 00:07:38 +0000440#define ERRNO_TABLE_SIZE 1200
441
442/* target_to_host_errno_table[] is initialized from
443 * host_to_target_errno_table[] in syscall_init(). */
444static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
445};
446
ths637947f2007-06-01 12:09:19 +0000447/*
thsfe8f0962007-07-12 10:59:21 +0000448 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000449 * minus the errnos that are not actually generic to all archs.
450 */
thsb92c47c2007-11-01 00:07:38 +0000451static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000452 [EIDRM] = TARGET_EIDRM,
453 [ECHRNG] = TARGET_ECHRNG,
454 [EL2NSYNC] = TARGET_EL2NSYNC,
455 [EL3HLT] = TARGET_EL3HLT,
456 [EL3RST] = TARGET_EL3RST,
457 [ELNRNG] = TARGET_ELNRNG,
458 [EUNATCH] = TARGET_EUNATCH,
459 [ENOCSI] = TARGET_ENOCSI,
460 [EL2HLT] = TARGET_EL2HLT,
461 [EDEADLK] = TARGET_EDEADLK,
462 [ENOLCK] = TARGET_ENOLCK,
463 [EBADE] = TARGET_EBADE,
464 [EBADR] = TARGET_EBADR,
465 [EXFULL] = TARGET_EXFULL,
466 [ENOANO] = TARGET_ENOANO,
467 [EBADRQC] = TARGET_EBADRQC,
468 [EBADSLT] = TARGET_EBADSLT,
469 [EBFONT] = TARGET_EBFONT,
470 [ENOSTR] = TARGET_ENOSTR,
471 [ENODATA] = TARGET_ENODATA,
472 [ETIME] = TARGET_ETIME,
473 [ENOSR] = TARGET_ENOSR,
474 [ENONET] = TARGET_ENONET,
475 [ENOPKG] = TARGET_ENOPKG,
476 [EREMOTE] = TARGET_EREMOTE,
477 [ENOLINK] = TARGET_ENOLINK,
478 [EADV] = TARGET_EADV,
479 [ESRMNT] = TARGET_ESRMNT,
480 [ECOMM] = TARGET_ECOMM,
481 [EPROTO] = TARGET_EPROTO,
482 [EDOTDOT] = TARGET_EDOTDOT,
483 [EMULTIHOP] = TARGET_EMULTIHOP,
484 [EBADMSG] = TARGET_EBADMSG,
485 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
486 [EOVERFLOW] = TARGET_EOVERFLOW,
487 [ENOTUNIQ] = TARGET_ENOTUNIQ,
488 [EBADFD] = TARGET_EBADFD,
489 [EREMCHG] = TARGET_EREMCHG,
490 [ELIBACC] = TARGET_ELIBACC,
491 [ELIBBAD] = TARGET_ELIBBAD,
492 [ELIBSCN] = TARGET_ELIBSCN,
493 [ELIBMAX] = TARGET_ELIBMAX,
494 [ELIBEXEC] = TARGET_ELIBEXEC,
495 [EILSEQ] = TARGET_EILSEQ,
496 [ENOSYS] = TARGET_ENOSYS,
497 [ELOOP] = TARGET_ELOOP,
498 [ERESTART] = TARGET_ERESTART,
499 [ESTRPIPE] = TARGET_ESTRPIPE,
500 [ENOTEMPTY] = TARGET_ENOTEMPTY,
501 [EUSERS] = TARGET_EUSERS,
502 [ENOTSOCK] = TARGET_ENOTSOCK,
503 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
504 [EMSGSIZE] = TARGET_EMSGSIZE,
505 [EPROTOTYPE] = TARGET_EPROTOTYPE,
506 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
507 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
508 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
509 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
510 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
511 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
512 [EADDRINUSE] = TARGET_EADDRINUSE,
513 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
514 [ENETDOWN] = TARGET_ENETDOWN,
515 [ENETUNREACH] = TARGET_ENETUNREACH,
516 [ENETRESET] = TARGET_ENETRESET,
517 [ECONNABORTED] = TARGET_ECONNABORTED,
518 [ECONNRESET] = TARGET_ECONNRESET,
519 [ENOBUFS] = TARGET_ENOBUFS,
520 [EISCONN] = TARGET_EISCONN,
521 [ENOTCONN] = TARGET_ENOTCONN,
522 [EUCLEAN] = TARGET_EUCLEAN,
523 [ENOTNAM] = TARGET_ENOTNAM,
524 [ENAVAIL] = TARGET_ENAVAIL,
525 [EISNAM] = TARGET_EISNAM,
526 [EREMOTEIO] = TARGET_EREMOTEIO,
527 [ESHUTDOWN] = TARGET_ESHUTDOWN,
528 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
529 [ETIMEDOUT] = TARGET_ETIMEDOUT,
530 [ECONNREFUSED] = TARGET_ECONNREFUSED,
531 [EHOSTDOWN] = TARGET_EHOSTDOWN,
532 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
533 [EALREADY] = TARGET_EALREADY,
534 [EINPROGRESS] = TARGET_EINPROGRESS,
535 [ESTALE] = TARGET_ESTALE,
536 [ECANCELED] = TARGET_ECANCELED,
537 [ENOMEDIUM] = TARGET_ENOMEDIUM,
538 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000539#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000540 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000541#endif
542#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000543 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000544#endif
545#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000546 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000547#endif
548#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000549 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000550#endif
551#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000552 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000553#endif
554#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000555 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000556#endif
thsb92c47c2007-11-01 00:07:38 +0000557};
ths637947f2007-06-01 12:09:19 +0000558
559static inline int host_to_target_errno(int err)
560{
561 if(host_to_target_errno_table[err])
562 return host_to_target_errno_table[err];
563 return err;
564}
565
thsb92c47c2007-11-01 00:07:38 +0000566static inline int target_to_host_errno(int err)
567{
568 if (target_to_host_errno_table[err])
569 return target_to_host_errno_table[err];
570 return err;
571}
572
blueswir1992f48a2007-10-14 16:27:31 +0000573static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000574{
575 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000576 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000577 else
578 return ret;
579}
580
blueswir1992f48a2007-10-14 16:27:31 +0000581static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000582{
blueswir1992f48a2007-10-14 16:27:31 +0000583 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000584}
585
thsb92c47c2007-11-01 00:07:38 +0000586char *target_strerror(int err)
587{
Alexander Graf962b2892011-11-21 12:04:07 +0100588 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
589 return NULL;
590 }
thsb92c47c2007-11-01 00:07:38 +0000591 return strerror(target_to_host_errno(err));
592}
593
Paul Burton8289d112014-06-22 11:25:33 +0100594static inline int host_to_target_sock_type(int host_type)
595{
596 int target_type;
597
598 switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
599 case SOCK_DGRAM:
600 target_type = TARGET_SOCK_DGRAM;
601 break;
602 case SOCK_STREAM:
603 target_type = TARGET_SOCK_STREAM;
604 break;
605 default:
606 target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
607 break;
608 }
609
610#if defined(SOCK_CLOEXEC)
611 if (host_type & SOCK_CLOEXEC) {
612 target_type |= TARGET_SOCK_CLOEXEC;
613 }
614#endif
615
616#if defined(SOCK_NONBLOCK)
617 if (host_type & SOCK_NONBLOCK) {
618 target_type |= TARGET_SOCK_NONBLOCK;
619 }
620#endif
621
622 return target_type;
623}
624
blueswir1992f48a2007-10-14 16:27:31 +0000625static abi_ulong target_brk;
626static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000627static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000628
blueswir1992f48a2007-10-14 16:27:31 +0000629void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000630{
blueswir14c1de732007-07-07 20:45:44 +0000631 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000632 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000633}
634
vincent4d1de872011-06-14 21:56:33 +0000635//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
636#define DEBUGF_BRK(message, args...)
637
ths0da46a62007-10-20 20:23:07 +0000638/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000639abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000640{
blueswir1992f48a2007-10-14 16:27:31 +0000641 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000642 int new_alloc_size;
643
Paul Brook3a0c6c42012-02-09 19:04:27 +0000644 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000645
vincent4d1de872011-06-14 21:56:33 +0000646 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000647 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000648 return target_brk;
649 }
650 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000651 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
652 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000653 return target_brk;
654 }
bellard31e31b82003-02-18 22:55:36 +0000655
vincent4d1de872011-06-14 21:56:33 +0000656 /* If the new brk is less than the highest page reserved to the
657 * target heap allocation, set it and we're almost done... */
658 if (new_brk <= brk_page) {
659 /* Heap contents are initialized to zero, as for anonymous
660 * mapped pages. */
661 if (new_brk > target_brk) {
662 memset(g2h(target_brk), 0, new_brk - target_brk);
663 }
bellard31e31b82003-02-18 22:55:36 +0000664 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000665 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000666 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000667 }
668
Peter Maydell00faf082011-04-18 16:34:24 +0100669 /* We need to allocate more memory after the brk... Note that
670 * we don't use MAP_FIXED because that will map over the top of
671 * any existing mapping (like the one with the host libc or qemu
672 * itself); instead we treat "mapped but at wrong address" as
673 * a failure and unmap again.
674 */
vincent4d1de872011-06-14 21:56:33 +0000675 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000676 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000677 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100678 MAP_ANON|MAP_PRIVATE, 0, 0));
679
680 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200681 /* Heap contents are initialized to zero, as for anonymous
682 * mapped pages. Technically the new pages are already
683 * initialized to zero since they *are* anonymous mapped
684 * pages, however we have to take care with the contents that
685 * come from the remaining part of the previous page: it may
686 * contains garbage data due to a previous heap usage (grown
687 * then shrunken). */
688 memset(g2h(target_brk), 0, brk_page - target_brk);
689
Peter Maydell00faf082011-04-18 16:34:24 +0100690 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000691 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000692 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
693 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100694 return target_brk;
695 } else if (mapped_addr != -1) {
696 /* Mapped but at wrong address, meaning there wasn't actually
697 * enough space for this brk.
698 */
699 target_munmap(mapped_addr, new_alloc_size);
700 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000701 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000702 }
703 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000704 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100705 }
balrog7ab240a2008-04-26 12:17:34 +0000706
Richard Henderson7dd46c02010-05-03 10:07:49 -0700707#if defined(TARGET_ALPHA)
708 /* We (partially) emulate OSF/1 on Alpha, which requires we
709 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100710 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700711#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100712 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000713 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000714}
715
ths26edcf42007-12-09 02:25:24 +0000716static inline abi_long copy_from_user_fdset(fd_set *fds,
717 abi_ulong target_fds_addr,
718 int n)
bellard31e31b82003-02-18 22:55:36 +0000719{
ths26edcf42007-12-09 02:25:24 +0000720 int i, nw, j, k;
721 abi_ulong b, *target_fds;
722
723 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
724 if (!(target_fds = lock_user(VERIFY_READ,
725 target_fds_addr,
726 sizeof(abi_ulong) * nw,
727 1)))
728 return -TARGET_EFAULT;
729
730 FD_ZERO(fds);
731 k = 0;
732 for (i = 0; i < nw; i++) {
733 /* grab the abi_ulong */
734 __get_user(b, &target_fds[i]);
735 for (j = 0; j < TARGET_ABI_BITS; j++) {
736 /* check the bit inside the abi_ulong */
737 if ((b >> j) & 1)
738 FD_SET(k, fds);
739 k++;
bellard31e31b82003-02-18 22:55:36 +0000740 }
bellard31e31b82003-02-18 22:55:36 +0000741 }
ths26edcf42007-12-09 02:25:24 +0000742
743 unlock_user(target_fds, target_fds_addr, 0);
744
745 return 0;
bellard31e31b82003-02-18 22:55:36 +0000746}
747
Mike Frysinger055e0902011-06-03 17:01:49 -0400748static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
749 abi_ulong target_fds_addr,
750 int n)
751{
752 if (target_fds_addr) {
753 if (copy_from_user_fdset(fds, target_fds_addr, n))
754 return -TARGET_EFAULT;
755 *fds_ptr = fds;
756 } else {
757 *fds_ptr = NULL;
758 }
759 return 0;
760}
761
ths26edcf42007-12-09 02:25:24 +0000762static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
763 const fd_set *fds,
764 int n)
bellard31e31b82003-02-18 22:55:36 +0000765{
bellard31e31b82003-02-18 22:55:36 +0000766 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000767 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000768 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000769
ths26edcf42007-12-09 02:25:24 +0000770 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
771 if (!(target_fds = lock_user(VERIFY_WRITE,
772 target_fds_addr,
773 sizeof(abi_ulong) * nw,
774 0)))
775 return -TARGET_EFAULT;
776
777 k = 0;
778 for (i = 0; i < nw; i++) {
779 v = 0;
780 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000781 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000782 k++;
bellard31e31b82003-02-18 22:55:36 +0000783 }
ths26edcf42007-12-09 02:25:24 +0000784 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000785 }
ths26edcf42007-12-09 02:25:24 +0000786
787 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
788
789 return 0;
bellard31e31b82003-02-18 22:55:36 +0000790}
791
bellardc596ed12003-07-13 17:32:31 +0000792#if defined(__alpha__)
793#define HOST_HZ 1024
794#else
795#define HOST_HZ 100
796#endif
797
blueswir1992f48a2007-10-14 16:27:31 +0000798static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000799{
800#if HOST_HZ == TARGET_HZ
801 return ticks;
802#else
803 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
804#endif
805}
806
bellard579a97f2007-11-11 14:26:47 +0000807static inline abi_long host_to_target_rusage(abi_ulong target_addr,
808 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000809{
pbrook53a59602006-03-25 19:31:22 +0000810 struct target_rusage *target_rusage;
811
bellard579a97f2007-11-11 14:26:47 +0000812 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
813 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200814 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
815 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
816 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
817 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
818 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
819 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
820 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
821 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
822 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
823 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
824 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
825 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
826 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
827 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
828 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
829 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
830 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
831 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000832 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000833
834 return 0;
bellardb4091862003-05-16 15:39:34 +0000835}
836
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200837static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900838{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200839 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300840 rlim_t result;
841
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200842 target_rlim_swap = tswapal(target_rlim);
843 if (target_rlim_swap == TARGET_RLIM_INFINITY)
844 return RLIM_INFINITY;
845
846 result = target_rlim_swap;
847 if (target_rlim_swap != (rlim_t)result)
848 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300849
850 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900851}
852
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200853static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900854{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200855 abi_ulong target_rlim_swap;
856 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300857
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200858 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300859 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900860 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300861 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200862 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300863
864 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900865}
866
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300867static inline int target_to_host_resource(int code)
868{
869 switch (code) {
870 case TARGET_RLIMIT_AS:
871 return RLIMIT_AS;
872 case TARGET_RLIMIT_CORE:
873 return RLIMIT_CORE;
874 case TARGET_RLIMIT_CPU:
875 return RLIMIT_CPU;
876 case TARGET_RLIMIT_DATA:
877 return RLIMIT_DATA;
878 case TARGET_RLIMIT_FSIZE:
879 return RLIMIT_FSIZE;
880 case TARGET_RLIMIT_LOCKS:
881 return RLIMIT_LOCKS;
882 case TARGET_RLIMIT_MEMLOCK:
883 return RLIMIT_MEMLOCK;
884 case TARGET_RLIMIT_MSGQUEUE:
885 return RLIMIT_MSGQUEUE;
886 case TARGET_RLIMIT_NICE:
887 return RLIMIT_NICE;
888 case TARGET_RLIMIT_NOFILE:
889 return RLIMIT_NOFILE;
890 case TARGET_RLIMIT_NPROC:
891 return RLIMIT_NPROC;
892 case TARGET_RLIMIT_RSS:
893 return RLIMIT_RSS;
894 case TARGET_RLIMIT_RTPRIO:
895 return RLIMIT_RTPRIO;
896 case TARGET_RLIMIT_SIGPENDING:
897 return RLIMIT_SIGPENDING;
898 case TARGET_RLIMIT_STACK:
899 return RLIMIT_STACK;
900 default:
901 return code;
902 }
903}
904
ths788f5ec2007-12-09 02:37:05 +0000905static inline abi_long copy_from_user_timeval(struct timeval *tv,
906 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000907{
pbrook53a59602006-03-25 19:31:22 +0000908 struct target_timeval *target_tv;
909
ths788f5ec2007-12-09 02:37:05 +0000910 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000911 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000912
913 __get_user(tv->tv_sec, &target_tv->tv_sec);
914 __get_user(tv->tv_usec, &target_tv->tv_usec);
915
916 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000917
918 return 0;
bellard31e31b82003-02-18 22:55:36 +0000919}
920
ths788f5ec2007-12-09 02:37:05 +0000921static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
922 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000923{
pbrook53a59602006-03-25 19:31:22 +0000924 struct target_timeval *target_tv;
925
ths788f5ec2007-12-09 02:37:05 +0000926 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000927 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000928
929 __put_user(tv->tv_sec, &target_tv->tv_sec);
930 __put_user(tv->tv_usec, &target_tv->tv_usec);
931
932 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000933
934 return 0;
bellard31e31b82003-02-18 22:55:36 +0000935}
936
Paul Burtonef4467e2014-06-22 11:25:40 +0100937static inline abi_long copy_from_user_timezone(struct timezone *tz,
938 abi_ulong target_tz_addr)
939{
940 struct target_timezone *target_tz;
941
942 if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
943 return -TARGET_EFAULT;
944 }
945
946 __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
947 __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
948
949 unlock_user_struct(target_tz, target_tz_addr, 0);
950
951 return 0;
952}
953
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700954#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
955#include <mqueue.h>
956
aurel3224e10032009-04-15 16:11:43 +0000957static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
958 abi_ulong target_mq_attr_addr)
959{
960 struct target_mq_attr *target_mq_attr;
961
962 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
963 target_mq_attr_addr, 1))
964 return -TARGET_EFAULT;
965
966 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
967 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
968 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
969 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
970
971 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
972
973 return 0;
974}
975
976static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
977 const struct mq_attr *attr)
978{
979 struct target_mq_attr *target_mq_attr;
980
981 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
982 target_mq_attr_addr, 0))
983 return -TARGET_EFAULT;
984
985 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
986 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
987 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
988 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
989
990 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
991
992 return 0;
993}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700994#endif
bellard31e31b82003-02-18 22:55:36 +0000995
Mike Frysinger055e0902011-06-03 17:01:49 -0400996#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000997/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000998static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000999 abi_ulong rfd_addr, abi_ulong wfd_addr,
1000 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +00001001{
1002 fd_set rfds, wfds, efds;
1003 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
1004 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00001005 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00001006
Mike Frysinger055e0902011-06-03 17:01:49 -04001007 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
1008 if (ret) {
1009 return ret;
pbrook53a59602006-03-25 19:31:22 +00001010 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001011 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1012 if (ret) {
1013 return ret;
pbrook53a59602006-03-25 19:31:22 +00001014 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001015 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1016 if (ret) {
1017 return ret;
pbrook53a59602006-03-25 19:31:22 +00001018 }
ths3b46e622007-09-17 08:09:54 +00001019
ths26edcf42007-12-09 02:25:24 +00001020 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001021 if (copy_from_user_timeval(&tv, target_tv_addr))
1022 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001023 tv_ptr = &tv;
1024 } else {
1025 tv_ptr = NULL;
1026 }
ths26edcf42007-12-09 02:25:24 +00001027
bellard31e31b82003-02-18 22:55:36 +00001028 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001029
ths26edcf42007-12-09 02:25:24 +00001030 if (!is_error(ret)) {
1031 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1032 return -TARGET_EFAULT;
1033 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1034 return -TARGET_EFAULT;
1035 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1036 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001037
ths788f5ec2007-12-09 02:37:05 +00001038 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1039 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001040 }
bellard579a97f2007-11-11 14:26:47 +00001041
bellard31e31b82003-02-18 22:55:36 +00001042 return ret;
1043}
Mike Frysinger055e0902011-06-03 17:01:49 -04001044#endif
bellard31e31b82003-02-18 22:55:36 +00001045
Riku Voipio099d6b02009-05-05 12:10:04 +03001046static abi_long do_pipe2(int host_pipe[], int flags)
1047{
1048#ifdef CONFIG_PIPE2
1049 return pipe2(host_pipe, flags);
1050#else
1051 return -ENOSYS;
1052#endif
1053}
1054
Richard Hendersonfb41a662010-05-03 10:07:52 -07001055static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1056 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001057{
1058 int host_pipe[2];
1059 abi_long ret;
1060 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1061
1062 if (is_error(ret))
1063 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001064
1065 /* Several targets have special calling conventions for the original
1066 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1067 if (!is_pipe2) {
1068#if defined(TARGET_ALPHA)
1069 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1070 return host_pipe[0];
1071#elif defined(TARGET_MIPS)
1072 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1073 return host_pipe[0];
1074#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001075 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001076 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001077#elif defined(TARGET_SPARC)
1078 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1079 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001080#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001081 }
1082
Riku Voipio099d6b02009-05-05 12:10:04 +03001083 if (put_user_s32(host_pipe[0], pipedes)
1084 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1085 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001086 return get_errno(ret);
1087}
1088
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001089static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1090 abi_ulong target_addr,
1091 socklen_t len)
1092{
1093 struct target_ip_mreqn *target_smreqn;
1094
1095 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1096 if (!target_smreqn)
1097 return -TARGET_EFAULT;
1098 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1099 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1100 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001101 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001102 unlock_user(target_smreqn, target_addr, 0);
1103
1104 return 0;
1105}
1106
bellard579a97f2007-11-11 14:26:47 +00001107static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1108 abi_ulong target_addr,
1109 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001110{
aurel32607175e2009-04-15 16:11:59 +00001111 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1112 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001113 struct target_sockaddr *target_saddr;
1114
bellard579a97f2007-11-11 14:26:47 +00001115 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1116 if (!target_saddr)
1117 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001118
1119 sa_family = tswap16(target_saddr->sa_family);
1120
1121 /* Oops. The caller might send a incomplete sun_path; sun_path
1122 * must be terminated by \0 (see the manual page), but
1123 * unfortunately it is quite common to specify sockaddr_un
1124 * length as "strlen(x->sun_path)" while it should be
1125 * "strlen(...) + 1". We'll fix that here if needed.
1126 * Linux kernel has a similar feature.
1127 */
1128
1129 if (sa_family == AF_UNIX) {
1130 if (len < unix_maxlen && len > 0) {
1131 char *cp = (char*)target_saddr;
1132
1133 if ( cp[len-1] && !cp[len] )
1134 len++;
1135 }
1136 if (len > unix_maxlen)
1137 len = unix_maxlen;
1138 }
1139
pbrook53a59602006-03-25 19:31:22 +00001140 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001141 addr->sa_family = sa_family;
Joakim Tjernlund33a29b52014-07-12 15:47:07 +02001142 if (sa_family == AF_PACKET) {
1143 struct target_sockaddr_ll *lladdr;
1144
1145 lladdr = (struct target_sockaddr_ll *)addr;
1146 lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
1147 lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
1148 }
pbrook53a59602006-03-25 19:31:22 +00001149 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001150
1151 return 0;
bellard7854b052003-03-29 17:22:23 +00001152}
1153
bellard579a97f2007-11-11 14:26:47 +00001154static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1155 struct sockaddr *addr,
1156 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001157{
pbrook53a59602006-03-25 19:31:22 +00001158 struct target_sockaddr *target_saddr;
1159
bellard579a97f2007-11-11 14:26:47 +00001160 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1161 if (!target_saddr)
1162 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001163 memcpy(target_saddr, addr, len);
1164 target_saddr->sa_family = tswap16(addr->sa_family);
1165 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001166
1167 return 0;
bellard7854b052003-03-29 17:22:23 +00001168}
1169
bellard5a4a8982007-11-11 17:39:18 +00001170static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1171 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001172{
1173 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001174 abi_long msg_controllen;
1175 abi_ulong target_cmsg_addr;
1176 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001177 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001178
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001179 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001180 if (msg_controllen < sizeof (struct target_cmsghdr))
1181 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001182 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001183 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1184 if (!target_cmsg)
1185 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001186
1187 while (cmsg && target_cmsg) {
1188 void *data = CMSG_DATA(cmsg);
1189 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1190
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001191 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001192 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1193
1194 space += CMSG_SPACE(len);
1195 if (space > msgh->msg_controllen) {
1196 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001197 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001198 break;
1199 }
1200
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001201 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1202 cmsg->cmsg_level = SOL_SOCKET;
1203 } else {
1204 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1205 }
bellard7854b052003-03-29 17:22:23 +00001206 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1207 cmsg->cmsg_len = CMSG_LEN(len);
1208
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001209 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001210 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1211 memcpy(data, target_data, len);
1212 } else {
1213 int *fd = (int *)data;
1214 int *target_fd = (int *)target_data;
1215 int i, numfds = len / sizeof(int);
1216
1217 for (i = 0; i < numfds; i++)
1218 fd[i] = tswap32(target_fd[i]);
1219 }
1220
1221 cmsg = CMSG_NXTHDR(msgh, cmsg);
1222 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1223 }
bellard5a4a8982007-11-11 17:39:18 +00001224 unlock_user(target_cmsg, target_cmsg_addr, 0);
1225 the_end:
bellard7854b052003-03-29 17:22:23 +00001226 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001227 return 0;
bellard7854b052003-03-29 17:22:23 +00001228}
1229
bellard5a4a8982007-11-11 17:39:18 +00001230static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1231 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001232{
1233 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001234 abi_long msg_controllen;
1235 abi_ulong target_cmsg_addr;
1236 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001237 socklen_t space = 0;
1238
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001239 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001240 if (msg_controllen < sizeof (struct target_cmsghdr))
1241 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001242 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001243 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1244 if (!target_cmsg)
1245 return -TARGET_EFAULT;
1246
bellard7854b052003-03-29 17:22:23 +00001247 while (cmsg && target_cmsg) {
1248 void *data = CMSG_DATA(cmsg);
1249 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1250
1251 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1252
1253 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001254 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001255 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001256 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001257 break;
1258 }
1259
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001260 if (cmsg->cmsg_level == SOL_SOCKET) {
1261 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1262 } else {
1263 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1264 }
bellard7854b052003-03-29 17:22:23 +00001265 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001266 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001267
Huw Davies52b65492014-04-17 14:02:47 +01001268 switch (cmsg->cmsg_level) {
1269 case SOL_SOCKET:
1270 switch (cmsg->cmsg_type) {
1271 case SCM_RIGHTS:
1272 {
1273 int *fd = (int *)data;
1274 int *target_fd = (int *)target_data;
1275 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001276
Huw Davies52b65492014-04-17 14:02:47 +01001277 for (i = 0; i < numfds; i++)
1278 target_fd[i] = tswap32(fd[i]);
1279 break;
1280 }
1281 case SO_TIMESTAMP:
1282 {
1283 struct timeval *tv = (struct timeval *)data;
1284 struct target_timeval *target_tv =
1285 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001286
Huw Davies52b65492014-04-17 14:02:47 +01001287 if (len != sizeof(struct timeval))
1288 goto unimplemented;
1289
1290 /* copy struct timeval to target */
1291 target_tv->tv_sec = tswapal(tv->tv_sec);
1292 target_tv->tv_usec = tswapal(tv->tv_usec);
1293 break;
1294 }
Huw Davies4bc29752014-04-17 14:02:48 +01001295 case SCM_CREDENTIALS:
1296 {
1297 struct ucred *cred = (struct ucred *)data;
1298 struct target_ucred *target_cred =
1299 (struct target_ucred *)target_data;
1300
1301 __put_user(cred->pid, &target_cred->pid);
1302 __put_user(cred->uid, &target_cred->uid);
1303 __put_user(cred->gid, &target_cred->gid);
1304 break;
1305 }
Huw Davies52b65492014-04-17 14:02:47 +01001306 default:
1307 goto unimplemented;
1308 }
1309 break;
1310
1311 default:
1312 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001313 gemu_log("Unsupported ancillary data: %d/%d\n",
1314 cmsg->cmsg_level, cmsg->cmsg_type);
1315 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001316 }
1317
1318 cmsg = CMSG_NXTHDR(msgh, cmsg);
1319 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1320 }
bellard5a4a8982007-11-11 17:39:18 +00001321 unlock_user(target_cmsg, target_cmsg_addr, space);
1322 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001323 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001324 return 0;
bellard7854b052003-03-29 17:22:23 +00001325}
1326
ths0da46a62007-10-20 20:23:07 +00001327/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001328static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001329 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001330{
blueswir1992f48a2007-10-14 16:27:31 +00001331 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001332 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001333 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001334 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001335
bellard8853f862004-02-22 14:57:26 +00001336 switch(level) {
1337 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001338 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001339 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001340 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001341
bellard2f619692007-11-16 10:46:05 +00001342 if (get_user_u32(val, optval_addr))
1343 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001344 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1345 break;
1346 case SOL_IP:
1347 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001348 case IP_TOS:
1349 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001350 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001351 case IP_ROUTER_ALERT:
1352 case IP_RECVOPTS:
1353 case IP_RETOPTS:
1354 case IP_PKTINFO:
1355 case IP_MTU_DISCOVER:
1356 case IP_RECVERR:
1357 case IP_RECVTOS:
1358#ifdef IP_FREEBIND
1359 case IP_FREEBIND:
1360#endif
1361 case IP_MULTICAST_TTL:
1362 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001363 val = 0;
1364 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001365 if (get_user_u32(val, optval_addr))
1366 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001367 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001368 if (get_user_u8(val, optval_addr))
1369 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001370 }
1371 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1372 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001373 case IP_ADD_MEMBERSHIP:
1374 case IP_DROP_MEMBERSHIP:
1375 if (optlen < sizeof (struct target_ip_mreq) ||
1376 optlen > sizeof (struct target_ip_mreqn))
1377 return -TARGET_EINVAL;
1378
1379 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1380 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1381 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1382 break;
1383
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001384 case IP_BLOCK_SOURCE:
1385 case IP_UNBLOCK_SOURCE:
1386 case IP_ADD_SOURCE_MEMBERSHIP:
1387 case IP_DROP_SOURCE_MEMBERSHIP:
1388 if (optlen != sizeof (struct target_ip_mreq_source))
1389 return -TARGET_EINVAL;
1390
1391 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1392 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1393 unlock_user (ip_mreq_source, optval_addr, 0);
1394 break;
1395
bellard8853f862004-02-22 14:57:26 +00001396 default:
1397 goto unimplemented;
1398 }
1399 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001400 case SOL_IPV6:
1401 switch (optname) {
1402 case IPV6_MTU_DISCOVER:
1403 case IPV6_MTU:
1404 case IPV6_V6ONLY:
1405 case IPV6_RECVPKTINFO:
1406 val = 0;
1407 if (optlen < sizeof(uint32_t)) {
1408 return -TARGET_EINVAL;
1409 }
1410 if (get_user_u32(val, optval_addr)) {
1411 return -TARGET_EFAULT;
1412 }
1413 ret = get_errno(setsockopt(sockfd, level, optname,
1414 &val, sizeof(val)));
1415 break;
1416 default:
1417 goto unimplemented;
1418 }
1419 break;
Jing Huang920394d2012-07-24 13:59:23 +00001420 case SOL_RAW:
1421 switch (optname) {
1422 case ICMP_FILTER:
1423 /* struct icmp_filter takes an u32 value */
1424 if (optlen < sizeof(uint32_t)) {
1425 return -TARGET_EINVAL;
1426 }
1427
1428 if (get_user_u32(val, optval_addr)) {
1429 return -TARGET_EFAULT;
1430 }
1431 ret = get_errno(setsockopt(sockfd, level, optname,
1432 &val, sizeof(val)));
1433 break;
1434
1435 default:
1436 goto unimplemented;
1437 }
1438 break;
bellard3532fa72006-06-24 15:06:03 +00001439 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001440 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001441 case TARGET_SO_RCVTIMEO:
1442 {
1443 struct timeval tv;
1444
1445 optname = SO_RCVTIMEO;
1446
1447set_timeout:
1448 if (optlen != sizeof(struct target_timeval)) {
1449 return -TARGET_EINVAL;
1450 }
1451
1452 if (copy_from_user_timeval(&tv, optval_addr)) {
1453 return -TARGET_EFAULT;
1454 }
1455
1456 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1457 &tv, sizeof(tv)));
1458 return ret;
1459 }
1460 case TARGET_SO_SNDTIMEO:
1461 optname = SO_SNDTIMEO;
1462 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001463 case TARGET_SO_ATTACH_FILTER:
1464 {
1465 struct target_sock_fprog *tfprog;
1466 struct target_sock_filter *tfilter;
1467 struct sock_fprog fprog;
1468 struct sock_filter *filter;
1469 int i;
1470
1471 if (optlen != sizeof(*tfprog)) {
1472 return -TARGET_EINVAL;
1473 }
1474 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1475 return -TARGET_EFAULT;
1476 }
1477 if (!lock_user_struct(VERIFY_READ, tfilter,
1478 tswapal(tfprog->filter), 0)) {
1479 unlock_user_struct(tfprog, optval_addr, 1);
1480 return -TARGET_EFAULT;
1481 }
1482
1483 fprog.len = tswap16(tfprog->len);
1484 filter = malloc(fprog.len * sizeof(*filter));
1485 if (filter == NULL) {
1486 unlock_user_struct(tfilter, tfprog->filter, 1);
1487 unlock_user_struct(tfprog, optval_addr, 1);
1488 return -TARGET_ENOMEM;
1489 }
1490 for (i = 0; i < fprog.len; i++) {
1491 filter[i].code = tswap16(tfilter[i].code);
1492 filter[i].jt = tfilter[i].jt;
1493 filter[i].jf = tfilter[i].jf;
1494 filter[i].k = tswap32(tfilter[i].k);
1495 }
1496 fprog.filter = filter;
1497
1498 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1499 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1500 free(filter);
1501
1502 unlock_user_struct(tfilter, tfprog->filter, 1);
1503 unlock_user_struct(tfprog, optval_addr, 1);
1504 return ret;
1505 }
Joakim Tjernlund451aaf62014-07-12 15:47:06 +02001506 case TARGET_SO_BINDTODEVICE:
1507 {
1508 char *dev_ifname, *addr_ifname;
1509
1510 if (optlen > IFNAMSIZ - 1) {
1511 optlen = IFNAMSIZ - 1;
1512 }
1513 dev_ifname = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1514 if (!dev_ifname) {
1515 return -TARGET_EFAULT;
1516 }
1517 optname = SO_BINDTODEVICE;
1518 addr_ifname = alloca(IFNAMSIZ);
1519 memcpy(addr_ifname, dev_ifname, optlen);
1520 addr_ifname[optlen] = 0;
1521 ret = get_errno(setsockopt(sockfd, level, optname, addr_ifname, optlen));
1522 unlock_user (dev_ifname, optval_addr, 0);
1523 return ret;
1524 }
bellard8853f862004-02-22 14:57:26 +00001525 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001526 case TARGET_SO_DEBUG:
1527 optname = SO_DEBUG;
1528 break;
1529 case TARGET_SO_REUSEADDR:
1530 optname = SO_REUSEADDR;
1531 break;
1532 case TARGET_SO_TYPE:
1533 optname = SO_TYPE;
1534 break;
1535 case TARGET_SO_ERROR:
1536 optname = SO_ERROR;
1537 break;
1538 case TARGET_SO_DONTROUTE:
1539 optname = SO_DONTROUTE;
1540 break;
1541 case TARGET_SO_BROADCAST:
1542 optname = SO_BROADCAST;
1543 break;
1544 case TARGET_SO_SNDBUF:
1545 optname = SO_SNDBUF;
1546 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001547 case TARGET_SO_SNDBUFFORCE:
1548 optname = SO_SNDBUFFORCE;
1549 break;
bellard3532fa72006-06-24 15:06:03 +00001550 case TARGET_SO_RCVBUF:
1551 optname = SO_RCVBUF;
1552 break;
Paul Burtond79b6cc2014-06-22 11:25:35 +01001553 case TARGET_SO_RCVBUFFORCE:
1554 optname = SO_RCVBUFFORCE;
1555 break;
bellard3532fa72006-06-24 15:06:03 +00001556 case TARGET_SO_KEEPALIVE:
1557 optname = SO_KEEPALIVE;
1558 break;
1559 case TARGET_SO_OOBINLINE:
1560 optname = SO_OOBINLINE;
1561 break;
1562 case TARGET_SO_NO_CHECK:
1563 optname = SO_NO_CHECK;
1564 break;
1565 case TARGET_SO_PRIORITY:
1566 optname = SO_PRIORITY;
1567 break;
bellard5e83e8e2005-03-01 22:32:06 +00001568#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001569 case TARGET_SO_BSDCOMPAT:
1570 optname = SO_BSDCOMPAT;
1571 break;
bellard5e83e8e2005-03-01 22:32:06 +00001572#endif
bellard3532fa72006-06-24 15:06:03 +00001573 case TARGET_SO_PASSCRED:
1574 optname = SO_PASSCRED;
1575 break;
Paul Burton82d0fe62014-06-22 11:25:36 +01001576 case TARGET_SO_PASSSEC:
1577 optname = SO_PASSSEC;
1578 break;
bellard3532fa72006-06-24 15:06:03 +00001579 case TARGET_SO_TIMESTAMP:
1580 optname = SO_TIMESTAMP;
1581 break;
1582 case TARGET_SO_RCVLOWAT:
1583 optname = SO_RCVLOWAT;
1584 break;
bellard8853f862004-02-22 14:57:26 +00001585 break;
1586 default:
1587 goto unimplemented;
1588 }
bellard3532fa72006-06-24 15:06:03 +00001589 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001590 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001591
bellard2f619692007-11-16 10:46:05 +00001592 if (get_user_u32(val, optval_addr))
1593 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001594 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001595 break;
bellard7854b052003-03-29 17:22:23 +00001596 default:
bellard8853f862004-02-22 14:57:26 +00001597 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001598 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001599 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001600 }
bellard8853f862004-02-22 14:57:26 +00001601 return ret;
bellard7854b052003-03-29 17:22:23 +00001602}
1603
ths0da46a62007-10-20 20:23:07 +00001604/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001605static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001606 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001607{
blueswir1992f48a2007-10-14 16:27:31 +00001608 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001609 int len, val;
1610 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001611
1612 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001613 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001614 level = SOL_SOCKET;
1615 switch (optname) {
1616 /* These don't just return a single integer */
1617 case TARGET_SO_LINGER:
1618 case TARGET_SO_RCVTIMEO:
1619 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001620 case TARGET_SO_PEERNAME:
1621 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001622 case TARGET_SO_PEERCRED: {
1623 struct ucred cr;
1624 socklen_t crlen;
1625 struct target_ucred *tcr;
1626
1627 if (get_user_u32(len, optlen)) {
1628 return -TARGET_EFAULT;
1629 }
1630 if (len < 0) {
1631 return -TARGET_EINVAL;
1632 }
1633
1634 crlen = sizeof(cr);
1635 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1636 &cr, &crlen));
1637 if (ret < 0) {
1638 return ret;
1639 }
1640 if (len > crlen) {
1641 len = crlen;
1642 }
1643 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1644 return -TARGET_EFAULT;
1645 }
1646 __put_user(cr.pid, &tcr->pid);
1647 __put_user(cr.uid, &tcr->uid);
1648 __put_user(cr.gid, &tcr->gid);
1649 unlock_user_struct(tcr, optval_addr, 1);
1650 if (put_user_u32(len, optlen)) {
1651 return -TARGET_EFAULT;
1652 }
1653 break;
1654 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001655 /* Options with 'int' argument. */
1656 case TARGET_SO_DEBUG:
1657 optname = SO_DEBUG;
1658 goto int_case;
1659 case TARGET_SO_REUSEADDR:
1660 optname = SO_REUSEADDR;
1661 goto int_case;
1662 case TARGET_SO_TYPE:
1663 optname = SO_TYPE;
1664 goto int_case;
1665 case TARGET_SO_ERROR:
1666 optname = SO_ERROR;
1667 goto int_case;
1668 case TARGET_SO_DONTROUTE:
1669 optname = SO_DONTROUTE;
1670 goto int_case;
1671 case TARGET_SO_BROADCAST:
1672 optname = SO_BROADCAST;
1673 goto int_case;
1674 case TARGET_SO_SNDBUF:
1675 optname = SO_SNDBUF;
1676 goto int_case;
1677 case TARGET_SO_RCVBUF:
1678 optname = SO_RCVBUF;
1679 goto int_case;
1680 case TARGET_SO_KEEPALIVE:
1681 optname = SO_KEEPALIVE;
1682 goto int_case;
1683 case TARGET_SO_OOBINLINE:
1684 optname = SO_OOBINLINE;
1685 goto int_case;
1686 case TARGET_SO_NO_CHECK:
1687 optname = SO_NO_CHECK;
1688 goto int_case;
1689 case TARGET_SO_PRIORITY:
1690 optname = SO_PRIORITY;
1691 goto int_case;
1692#ifdef SO_BSDCOMPAT
1693 case TARGET_SO_BSDCOMPAT:
1694 optname = SO_BSDCOMPAT;
1695 goto int_case;
1696#endif
1697 case TARGET_SO_PASSCRED:
1698 optname = SO_PASSCRED;
1699 goto int_case;
1700 case TARGET_SO_TIMESTAMP:
1701 optname = SO_TIMESTAMP;
1702 goto int_case;
1703 case TARGET_SO_RCVLOWAT:
1704 optname = SO_RCVLOWAT;
1705 goto int_case;
Paul Burtonaec1ca42014-06-22 11:25:34 +01001706 case TARGET_SO_ACCEPTCONN:
1707 optname = SO_ACCEPTCONN;
1708 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001709 default:
bellard2efbe912005-07-23 15:10:20 +00001710 goto int_case;
1711 }
1712 break;
1713 case SOL_TCP:
1714 /* TCP options all take an 'int' value. */
1715 int_case:
bellard2f619692007-11-16 10:46:05 +00001716 if (get_user_u32(len, optlen))
1717 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001718 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001719 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001720 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001721 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1722 if (ret < 0)
1723 return ret;
Paul Burton8289d112014-06-22 11:25:33 +01001724 if (optname == SO_TYPE) {
1725 val = host_to_target_sock_type(val);
1726 }
bellard2efbe912005-07-23 15:10:20 +00001727 if (len > lv)
1728 len = lv;
bellard2f619692007-11-16 10:46:05 +00001729 if (len == 4) {
1730 if (put_user_u32(val, optval_addr))
1731 return -TARGET_EFAULT;
1732 } else {
1733 if (put_user_u8(val, optval_addr))
1734 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001735 }
bellard2f619692007-11-16 10:46:05 +00001736 if (put_user_u32(len, optlen))
1737 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001738 break;
1739 case SOL_IP:
1740 switch(optname) {
1741 case IP_TOS:
1742 case IP_TTL:
1743 case IP_HDRINCL:
1744 case IP_ROUTER_ALERT:
1745 case IP_RECVOPTS:
1746 case IP_RETOPTS:
1747 case IP_PKTINFO:
1748 case IP_MTU_DISCOVER:
1749 case IP_RECVERR:
1750 case IP_RECVTOS:
1751#ifdef IP_FREEBIND
1752 case IP_FREEBIND:
1753#endif
1754 case IP_MULTICAST_TTL:
1755 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001756 if (get_user_u32(len, optlen))
1757 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001758 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001759 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001760 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001761 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1762 if (ret < 0)
1763 return ret;
bellard2efbe912005-07-23 15:10:20 +00001764 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001765 len = 1;
bellard2f619692007-11-16 10:46:05 +00001766 if (put_user_u32(len, optlen)
1767 || put_user_u8(val, optval_addr))
1768 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001769 } else {
bellard2efbe912005-07-23 15:10:20 +00001770 if (len > sizeof(int))
1771 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001772 if (put_user_u32(len, optlen)
1773 || put_user_u32(val, optval_addr))
1774 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001775 }
bellard8853f862004-02-22 14:57:26 +00001776 break;
bellard2efbe912005-07-23 15:10:20 +00001777 default:
thsc02f4992007-12-18 02:39:59 +00001778 ret = -TARGET_ENOPROTOOPT;
1779 break;
bellard8853f862004-02-22 14:57:26 +00001780 }
1781 break;
1782 default:
1783 unimplemented:
1784 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1785 level, optname);
thsc02f4992007-12-18 02:39:59 +00001786 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001787 break;
1788 }
1789 return ret;
bellard7854b052003-03-29 17:22:23 +00001790}
1791
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001792static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1793 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001794{
1795 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001796 struct iovec *vec;
1797 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001798 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001799 int err = 0;
pbrook53a59602006-03-25 19:31:22 +00001800
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001801 if (count == 0) {
1802 errno = 0;
1803 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001804 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001805 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001806 errno = EINVAL;
1807 return NULL;
1808 }
1809
1810 vec = calloc(count, sizeof(struct iovec));
1811 if (vec == NULL) {
1812 errno = ENOMEM;
1813 return NULL;
1814 }
1815
1816 target_vec = lock_user(VERIFY_READ, target_addr,
1817 count * sizeof(struct target_iovec), 1);
1818 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001819 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001820 goto fail2;
1821 }
1822
1823 /* ??? If host page size > target page size, this will result in a
1824 value larger than what we can actually support. */
1825 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1826 total_len = 0;
1827
1828 for (i = 0; i < count; i++) {
1829 abi_ulong base = tswapal(target_vec[i].iov_base);
1830 abi_long len = tswapal(target_vec[i].iov_len);
1831
1832 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001833 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001834 goto fail;
1835 } else if (len == 0) {
1836 /* Zero length pointer is ignored. */
1837 vec[i].iov_base = 0;
1838 } else {
1839 vec[i].iov_base = lock_user(type, base, len, copy);
1840 if (!vec[i].iov_base) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001841 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001842 goto fail;
1843 }
1844 if (len > max_len - total_len) {
1845 len = max_len - total_len;
1846 }
1847 }
1848 vec[i].iov_len = len;
1849 total_len += len;
1850 }
1851
1852 unlock_user(target_vec, target_addr, 0);
1853 return vec;
1854
1855 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001856 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001857 fail2:
1858 free(vec);
1859 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001860 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001861}
1862
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001863static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1864 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001865{
1866 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001867 int i;
1868
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001869 target_vec = lock_user(VERIFY_READ, target_addr,
1870 count * sizeof(struct target_iovec), 1);
1871 if (target_vec) {
1872 for (i = 0; i < count; i++) {
1873 abi_ulong base = tswapal(target_vec[i].iov_base);
1874 abi_long len = tswapal(target_vec[i].iov_base);
1875 if (len < 0) {
1876 break;
1877 }
balrogd732dcb2008-10-28 10:21:03 +00001878 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1879 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001880 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001881 }
bellard579a97f2007-11-11 14:26:47 +00001882
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001883 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001884}
1885
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001886static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001887{
1888 int host_type = 0;
1889 int target_type = *type;
1890
1891 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1892 case TARGET_SOCK_DGRAM:
1893 host_type = SOCK_DGRAM;
1894 break;
1895 case TARGET_SOCK_STREAM:
1896 host_type = SOCK_STREAM;
1897 break;
1898 default:
1899 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1900 break;
1901 }
1902 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001903#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001904 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001905#else
1906 return -TARGET_EINVAL;
1907#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001908 }
1909 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001910#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001911 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001912#elif !defined(O_NONBLOCK)
1913 return -TARGET_EINVAL;
1914#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001915 }
1916 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001917 return 0;
1918}
1919
1920/* Try to emulate socket type flags after socket creation. */
1921static int sock_flags_fixup(int fd, int target_type)
1922{
1923#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1924 if (target_type & TARGET_SOCK_NONBLOCK) {
1925 int flags = fcntl(fd, F_GETFL);
1926 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1927 close(fd);
1928 return -TARGET_EINVAL;
1929 }
1930 }
1931#endif
1932 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001933}
1934
ths0da46a62007-10-20 20:23:07 +00001935/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001936static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001937{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001938 int target_type = type;
1939 int ret;
1940
1941 ret = target_to_host_sock_type(&type);
1942 if (ret) {
1943 return ret;
1944 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001945
balrog12bc92a2007-10-30 21:06:14 +00001946 if (domain == PF_NETLINK)
Ed Swierk480eda22014-05-05 20:04:45 -07001947 return -TARGET_EAFNOSUPPORT;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001948 ret = get_errno(socket(domain, type, protocol));
1949 if (ret >= 0) {
1950 ret = sock_flags_fixup(ret, target_type);
1951 }
1952 return ret;
bellard3532fa72006-06-24 15:06:03 +00001953}
1954
ths0da46a62007-10-20 20:23:07 +00001955/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001956static abi_long do_bind(int sockfd, abi_ulong target_addr,
1957 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001958{
aurel328f7aeaf2009-01-30 19:47:57 +00001959 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001960 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001961
Blue Swirl38724252010-09-18 05:53:14 +00001962 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001963 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001964 }
aurel328f7aeaf2009-01-30 19:47:57 +00001965
aurel32607175e2009-04-15 16:11:59 +00001966 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001967
Arnaud Patard917507b2009-06-19 10:44:45 +03001968 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1969 if (ret)
1970 return ret;
1971
bellard3532fa72006-06-24 15:06:03 +00001972 return get_errno(bind(sockfd, addr, addrlen));
1973}
1974
ths0da46a62007-10-20 20:23:07 +00001975/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001976static abi_long do_connect(int sockfd, abi_ulong target_addr,
1977 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001978{
aurel328f7aeaf2009-01-30 19:47:57 +00001979 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001980 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001981
Blue Swirl38724252010-09-18 05:53:14 +00001982 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001983 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001984 }
aurel328f7aeaf2009-01-30 19:47:57 +00001985
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02001986 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001987
Arnaud Patard917507b2009-06-19 10:44:45 +03001988 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1989 if (ret)
1990 return ret;
1991
bellard3532fa72006-06-24 15:06:03 +00001992 return get_errno(connect(sockfd, addr, addrlen));
1993}
1994
Alexander Graff19e00d2014-03-02 19:36:42 +00001995/* do_sendrecvmsg_locked() Must return target values and target errnos. */
1996static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
1997 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001998{
balrog6de645c2008-10-28 10:26:29 +00001999 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00002000 struct msghdr msg;
2001 int count;
2002 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00002003 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00002004
bellard3532fa72006-06-24 15:06:03 +00002005 if (msgp->msg_name) {
2006 msg.msg_namelen = tswap32(msgp->msg_namelen);
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002007 msg.msg_name = alloca(msg.msg_namelen+1);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002008 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00002009 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002010 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002011 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03002012 }
bellard3532fa72006-06-24 15:06:03 +00002013 } else {
2014 msg.msg_name = NULL;
2015 msg.msg_namelen = 0;
2016 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002017 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00002018 msg.msg_control = alloca(msg.msg_controllen);
2019 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00002020
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002021 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002022 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002023 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
2024 target_vec, count, send);
2025 if (vec == NULL) {
2026 ret = -host_to_target_errno(errno);
2027 goto out2;
2028 }
bellard3532fa72006-06-24 15:06:03 +00002029 msg.msg_iovlen = count;
2030 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00002031
bellard3532fa72006-06-24 15:06:03 +00002032 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00002033 ret = target_to_host_cmsg(&msg, msgp);
2034 if (ret == 0)
2035 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00002036 } else {
2037 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00002038 if (!is_error(ret)) {
2039 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00002040 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00002041 if (!is_error(ret)) {
2042 msgp->msg_namelen = tswap32(msg.msg_namelen);
2043 if (msg.msg_name != NULL) {
2044 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
2045 msg.msg_name, msg.msg_namelen);
2046 if (ret) {
2047 goto out;
2048 }
2049 }
2050
balrog6de645c2008-10-28 10:26:29 +00002051 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002052 }
balrog6de645c2008-10-28 10:26:29 +00002053 }
bellard3532fa72006-06-24 15:06:03 +00002054 }
Jing Huangca619062012-07-24 13:58:02 +00002055
2056out:
bellard3532fa72006-06-24 15:06:03 +00002057 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002058out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002059 return ret;
2060}
2061
2062static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2063 int flags, int send)
2064{
2065 abi_long ret;
2066 struct target_msghdr *msgp;
2067
2068 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2069 msgp,
2070 target_msg,
2071 send ? 1 : 0)) {
2072 return -TARGET_EFAULT;
2073 }
2074 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002075 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002076 return ret;
2077}
2078
Alexander Graff19e00d2014-03-02 19:36:42 +00002079#ifdef TARGET_NR_sendmmsg
2080/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2081 * so it might not have this *mmsg-specific flag either.
2082 */
2083#ifndef MSG_WAITFORONE
2084#define MSG_WAITFORONE 0x10000
2085#endif
2086
2087static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2088 unsigned int vlen, unsigned int flags,
2089 int send)
2090{
2091 struct target_mmsghdr *mmsgp;
2092 abi_long ret = 0;
2093 int i;
2094
2095 if (vlen > UIO_MAXIOV) {
2096 vlen = UIO_MAXIOV;
2097 }
2098
2099 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2100 if (!mmsgp) {
2101 return -TARGET_EFAULT;
2102 }
2103
2104 for (i = 0; i < vlen; i++) {
2105 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2106 if (is_error(ret)) {
2107 break;
2108 }
2109 mmsgp[i].msg_len = tswap32(ret);
2110 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2111 if (flags & MSG_WAITFORONE) {
2112 flags |= MSG_DONTWAIT;
2113 }
2114 }
2115
2116 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2117
2118 /* Return number of datagrams sent if we sent any at all;
2119 * otherwise return the error.
2120 */
2121 if (i) {
2122 return i;
2123 }
2124 return ret;
2125}
2126#endif
2127
Peter Maydella94b4982013-02-08 04:35:04 +00002128/* If we don't have a system accept4() then just call accept.
2129 * The callsites to do_accept4() will ensure that they don't
2130 * pass a non-zero flags argument in this config.
2131 */
2132#ifndef CONFIG_ACCEPT4
2133static inline int accept4(int sockfd, struct sockaddr *addr,
2134 socklen_t *addrlen, int flags)
2135{
2136 assert(flags == 0);
2137 return accept(sockfd, addr, addrlen);
2138}
2139#endif
2140
2141/* do_accept4() Must return target values and target errnos. */
2142static abi_long do_accept4(int fd, abi_ulong target_addr,
2143 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002144{
bellard2f619692007-11-16 10:46:05 +00002145 socklen_t addrlen;
2146 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002147 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002148 int host_flags;
2149
2150 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002151
Peter Maydella94b4982013-02-08 04:35:04 +00002152 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002153 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002154 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002155
2156 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002157 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002158 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002159
Blue Swirl38724252010-09-18 05:53:14 +00002160 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002161 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002162 }
aurel328f7aeaf2009-01-30 19:47:57 +00002163
Arnaud Patard917507b2009-06-19 10:44:45 +03002164 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2165 return -TARGET_EINVAL;
2166
bellard2f619692007-11-16 10:46:05 +00002167 addr = alloca(addrlen);
2168
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002169 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002170 if (!is_error(ret)) {
2171 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002172 if (put_user_u32(addrlen, target_addrlen_addr))
2173 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002174 }
2175 return ret;
2176}
2177
ths0da46a62007-10-20 20:23:07 +00002178/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002179static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002180 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002181{
bellard2f619692007-11-16 10:46:05 +00002182 socklen_t addrlen;
2183 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002184 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002185
bellard2f619692007-11-16 10:46:05 +00002186 if (get_user_u32(addrlen, target_addrlen_addr))
2187 return -TARGET_EFAULT;
2188
Blue Swirl38724252010-09-18 05:53:14 +00002189 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002190 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002191 }
aurel328f7aeaf2009-01-30 19:47:57 +00002192
Arnaud Patard917507b2009-06-19 10:44:45 +03002193 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2194 return -TARGET_EFAULT;
2195
bellard2f619692007-11-16 10:46:05 +00002196 addr = alloca(addrlen);
2197
pbrook1be9e1d2006-11-19 15:26:04 +00002198 ret = get_errno(getpeername(fd, addr, &addrlen));
2199 if (!is_error(ret)) {
2200 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002201 if (put_user_u32(addrlen, target_addrlen_addr))
2202 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002203 }
2204 return ret;
2205}
2206
ths0da46a62007-10-20 20:23:07 +00002207/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002208static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002209 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002210{
bellard2f619692007-11-16 10:46:05 +00002211 socklen_t addrlen;
2212 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002213 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002214
bellard2f619692007-11-16 10:46:05 +00002215 if (get_user_u32(addrlen, target_addrlen_addr))
2216 return -TARGET_EFAULT;
2217
Blue Swirl38724252010-09-18 05:53:14 +00002218 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002219 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002220 }
aurel328f7aeaf2009-01-30 19:47:57 +00002221
Arnaud Patard917507b2009-06-19 10:44:45 +03002222 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2223 return -TARGET_EFAULT;
2224
bellard2f619692007-11-16 10:46:05 +00002225 addr = alloca(addrlen);
2226
pbrook1be9e1d2006-11-19 15:26:04 +00002227 ret = get_errno(getsockname(fd, addr, &addrlen));
2228 if (!is_error(ret)) {
2229 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002230 if (put_user_u32(addrlen, target_addrlen_addr))
2231 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002232 }
2233 return ret;
2234}
2235
ths0da46a62007-10-20 20:23:07 +00002236/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002237static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002238 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002239{
2240 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002241 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002242
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002243 target_to_host_sock_type(&type);
2244
pbrook1be9e1d2006-11-19 15:26:04 +00002245 ret = get_errno(socketpair(domain, type, protocol, tab));
2246 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002247 if (put_user_s32(tab[0], target_tab_addr)
2248 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2249 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002250 }
2251 return ret;
2252}
2253
ths0da46a62007-10-20 20:23:07 +00002254/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002255static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2256 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002257{
2258 void *addr;
2259 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002260 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002261
Blue Swirl38724252010-09-18 05:53:14 +00002262 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002263 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002264 }
aurel328f7aeaf2009-01-30 19:47:57 +00002265
bellard579a97f2007-11-11 14:26:47 +00002266 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2267 if (!host_msg)
2268 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002269 if (target_addr) {
Joakim Tjernlund2dd08df2014-07-11 17:18:03 +02002270 addr = alloca(addrlen+1);
Arnaud Patard917507b2009-06-19 10:44:45 +03002271 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2272 if (ret) {
2273 unlock_user(host_msg, msg, 0);
2274 return ret;
2275 }
pbrook1be9e1d2006-11-19 15:26:04 +00002276 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2277 } else {
2278 ret = get_errno(send(fd, host_msg, len, flags));
2279 }
2280 unlock_user(host_msg, msg, 0);
2281 return ret;
2282}
2283
ths0da46a62007-10-20 20:23:07 +00002284/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002285static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2286 abi_ulong target_addr,
2287 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002288{
2289 socklen_t addrlen;
2290 void *addr;
2291 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002292 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002293
bellard579a97f2007-11-11 14:26:47 +00002294 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2295 if (!host_msg)
2296 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002297 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002298 if (get_user_u32(addrlen, target_addrlen)) {
2299 ret = -TARGET_EFAULT;
2300 goto fail;
2301 }
Blue Swirl38724252010-09-18 05:53:14 +00002302 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002303 ret = -TARGET_EINVAL;
2304 goto fail;
2305 }
pbrook1be9e1d2006-11-19 15:26:04 +00002306 addr = alloca(addrlen);
2307 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2308 } else {
2309 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002310 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002311 }
2312 if (!is_error(ret)) {
2313 if (target_addr) {
2314 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002315 if (put_user_u32(addrlen, target_addrlen)) {
2316 ret = -TARGET_EFAULT;
2317 goto fail;
2318 }
pbrook1be9e1d2006-11-19 15:26:04 +00002319 }
2320 unlock_user(host_msg, msg, len);
2321 } else {
bellard2f619692007-11-16 10:46:05 +00002322fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002323 unlock_user(host_msg, msg, 0);
2324 }
2325 return ret;
2326}
2327
j_mayer32407102007-09-26 23:01:49 +00002328#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002329/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002330static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002331{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002332 static const unsigned ac[] = { /* number of arguments per call */
2333 [SOCKOP_socket] = 3, /* domain, type, protocol */
2334 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2335 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2336 [SOCKOP_listen] = 2, /* sockfd, backlog */
2337 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2338 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2339 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2340 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2341 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2342 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2343 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2344 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2345 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2346 [SOCKOP_shutdown] = 2, /* sockfd, how */
2347 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2348 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2349 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2350 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2351 };
2352 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002353
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002354 /* first, collect the arguments in a[] according to ac[] */
2355 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2356 unsigned i;
2357 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2358 for (i = 0; i < ac[num]; ++i) {
2359 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002360 return -TARGET_EFAULT;
2361 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002362 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002363 }
bellard2f619692007-11-16 10:46:05 +00002364
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002365 /* now when we have the args, actually handle the call */
2366 switch (num) {
2367 case SOCKOP_socket: /* domain, type, protocol */
2368 return do_socket(a[0], a[1], a[2]);
2369 case SOCKOP_bind: /* sockfd, addr, addrlen */
2370 return do_bind(a[0], a[1], a[2]);
2371 case SOCKOP_connect: /* sockfd, addr, addrlen */
2372 return do_connect(a[0], a[1], a[2]);
2373 case SOCKOP_listen: /* sockfd, backlog */
2374 return get_errno(listen(a[0], a[1]));
2375 case SOCKOP_accept: /* sockfd, addr, addrlen */
2376 return do_accept4(a[0], a[1], a[2], 0);
2377 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2378 return do_accept4(a[0], a[1], a[2], a[3]);
2379 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2380 return do_getsockname(a[0], a[1], a[2]);
2381 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2382 return do_getpeername(a[0], a[1], a[2]);
2383 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2384 return do_socketpair(a[0], a[1], a[2], a[3]);
2385 case SOCKOP_send: /* sockfd, msg, len, flags */
2386 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2387 case SOCKOP_recv: /* sockfd, msg, len, flags */
2388 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2389 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2390 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2391 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2392 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2393 case SOCKOP_shutdown: /* sockfd, how */
2394 return get_errno(shutdown(a[0], a[1]));
2395 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2396 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2397 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2398 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2399 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2400 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2401 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2402 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002403 default:
2404 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002405 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002406 }
bellard31e31b82003-02-18 22:55:36 +00002407}
j_mayer32407102007-09-26 23:01:49 +00002408#endif
bellard31e31b82003-02-18 22:55:36 +00002409
bellard8853f862004-02-22 14:57:26 +00002410#define N_SHM_REGIONS 32
2411
2412static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002413 abi_ulong start;
2414 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002415} shm_regions[N_SHM_REGIONS];
2416
ths3eb6b042007-06-03 14:26:27 +00002417struct target_semid_ds
2418{
2419 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002420 abi_ulong sem_otime;
2421 abi_ulong __unused1;
2422 abi_ulong sem_ctime;
2423 abi_ulong __unused2;
2424 abi_ulong sem_nsems;
2425 abi_ulong __unused3;
2426 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002427};
2428
bellard579a97f2007-11-11 14:26:47 +00002429static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2430 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002431{
2432 struct target_ipc_perm *target_ip;
2433 struct target_semid_ds *target_sd;
2434
bellard579a97f2007-11-11 14:26:47 +00002435 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2436 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002437 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002438 host_ip->__key = tswap32(target_ip->__key);
2439 host_ip->uid = tswap32(target_ip->uid);
2440 host_ip->gid = tswap32(target_ip->gid);
2441 host_ip->cuid = tswap32(target_ip->cuid);
2442 host_ip->cgid = tswap32(target_ip->cgid);
2443#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2444 host_ip->mode = tswap32(target_ip->mode);
2445#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002446 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002447#endif
2448#if defined(TARGET_PPC)
2449 host_ip->__seq = tswap32(target_ip->__seq);
2450#else
2451 host_ip->__seq = tswap16(target_ip->__seq);
2452#endif
ths3eb6b042007-06-03 14:26:27 +00002453 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002454 return 0;
ths3eb6b042007-06-03 14:26:27 +00002455}
2456
bellard579a97f2007-11-11 14:26:47 +00002457static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2458 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002459{
2460 struct target_ipc_perm *target_ip;
2461 struct target_semid_ds *target_sd;
2462
bellard579a97f2007-11-11 14:26:47 +00002463 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2464 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002465 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002466 target_ip->__key = tswap32(host_ip->__key);
2467 target_ip->uid = tswap32(host_ip->uid);
2468 target_ip->gid = tswap32(host_ip->gid);
2469 target_ip->cuid = tswap32(host_ip->cuid);
2470 target_ip->cgid = tswap32(host_ip->cgid);
2471#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2472 target_ip->mode = tswap32(host_ip->mode);
2473#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002474 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002475#endif
2476#if defined(TARGET_PPC)
2477 target_ip->__seq = tswap32(host_ip->__seq);
2478#else
2479 target_ip->__seq = tswap16(host_ip->__seq);
2480#endif
ths3eb6b042007-06-03 14:26:27 +00002481 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002482 return 0;
ths3eb6b042007-06-03 14:26:27 +00002483}
2484
bellard579a97f2007-11-11 14:26:47 +00002485static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2486 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002487{
2488 struct target_semid_ds *target_sd;
2489
bellard579a97f2007-11-11 14:26:47 +00002490 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2491 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002492 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2493 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002494 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2495 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2496 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002497 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002498 return 0;
ths3eb6b042007-06-03 14:26:27 +00002499}
2500
bellard579a97f2007-11-11 14:26:47 +00002501static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2502 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002503{
2504 struct target_semid_ds *target_sd;
2505
bellard579a97f2007-11-11 14:26:47 +00002506 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2507 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002508 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002509 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002510 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2511 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2512 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002513 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002514 return 0;
ths3eb6b042007-06-03 14:26:27 +00002515}
2516
aurel32e5289082009-04-18 16:16:12 +00002517struct target_seminfo {
2518 int semmap;
2519 int semmni;
2520 int semmns;
2521 int semmnu;
2522 int semmsl;
2523 int semopm;
2524 int semume;
2525 int semusz;
2526 int semvmx;
2527 int semaem;
2528};
2529
2530static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2531 struct seminfo *host_seminfo)
2532{
2533 struct target_seminfo *target_seminfo;
2534 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2535 return -TARGET_EFAULT;
2536 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2537 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2538 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2539 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2540 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2541 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2542 __put_user(host_seminfo->semume, &target_seminfo->semume);
2543 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2544 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2545 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2546 unlock_user_struct(target_seminfo, target_addr, 1);
2547 return 0;
2548}
2549
thsfa294812007-02-02 22:05:00 +00002550union semun {
2551 int val;
ths3eb6b042007-06-03 14:26:27 +00002552 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002553 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002554 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002555};
2556
ths3eb6b042007-06-03 14:26:27 +00002557union target_semun {
2558 int val;
aurel32e5289082009-04-18 16:16:12 +00002559 abi_ulong buf;
2560 abi_ulong array;
2561 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002562};
2563
aurel32e5289082009-04-18 16:16:12 +00002564static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2565 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002566{
aurel32e5289082009-04-18 16:16:12 +00002567 int nsems;
2568 unsigned short *array;
2569 union semun semun;
2570 struct semid_ds semid_ds;
2571 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002572
aurel32e5289082009-04-18 16:16:12 +00002573 semun.buf = &semid_ds;
2574
2575 ret = semctl(semid, 0, IPC_STAT, semun);
2576 if (ret == -1)
2577 return get_errno(ret);
2578
2579 nsems = semid_ds.sem_nsems;
2580
2581 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002582 if (!*host_array) {
2583 return -TARGET_ENOMEM;
2584 }
aurel32e5289082009-04-18 16:16:12 +00002585 array = lock_user(VERIFY_READ, target_addr,
2586 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002587 if (!array) {
2588 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002589 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002590 }
aurel32e5289082009-04-18 16:16:12 +00002591
2592 for(i=0; i<nsems; i++) {
2593 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002594 }
aurel32e5289082009-04-18 16:16:12 +00002595 unlock_user(array, target_addr, 0);
2596
bellard579a97f2007-11-11 14:26:47 +00002597 return 0;
ths3eb6b042007-06-03 14:26:27 +00002598}
2599
aurel32e5289082009-04-18 16:16:12 +00002600static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2601 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002602{
aurel32e5289082009-04-18 16:16:12 +00002603 int nsems;
2604 unsigned short *array;
2605 union semun semun;
2606 struct semid_ds semid_ds;
2607 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002608
aurel32e5289082009-04-18 16:16:12 +00002609 semun.buf = &semid_ds;
2610
2611 ret = semctl(semid, 0, IPC_STAT, semun);
2612 if (ret == -1)
2613 return get_errno(ret);
2614
2615 nsems = semid_ds.sem_nsems;
2616
2617 array = lock_user(VERIFY_WRITE, target_addr,
2618 nsems*sizeof(unsigned short), 0);
2619 if (!array)
2620 return -TARGET_EFAULT;
2621
2622 for(i=0; i<nsems; i++) {
2623 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002624 }
aurel32e5289082009-04-18 16:16:12 +00002625 free(*host_array);
2626 unlock_user(array, target_addr, 1);
2627
bellard579a97f2007-11-11 14:26:47 +00002628 return 0;
ths3eb6b042007-06-03 14:26:27 +00002629}
2630
aurel32e5289082009-04-18 16:16:12 +00002631static inline abi_long do_semctl(int semid, int semnum, int cmd,
2632 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002633{
2634 union semun arg;
2635 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302636 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002637 struct seminfo seminfo;
2638 abi_long ret = -TARGET_EINVAL;
2639 abi_long err;
2640 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002641
2642 switch( cmd ) {
2643 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002644 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002645 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002646 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002647 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002648 break;
2649 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002650 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002651 err = target_to_host_semarray(semid, &array, target_su.array);
2652 if (err)
2653 return err;
2654 arg.array = array;
2655 ret = get_errno(semctl(semid, semnum, cmd, arg));
2656 err = host_to_target_semarray(semid, target_su.array, &array);
2657 if (err)
2658 return err;
ths3eb6b042007-06-03 14:26:27 +00002659 break;
2660 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002661 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002662 case SEM_STAT:
2663 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2664 if (err)
2665 return err;
2666 arg.buf = &dsarg;
2667 ret = get_errno(semctl(semid, semnum, cmd, arg));
2668 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2669 if (err)
2670 return err;
ths3eb6b042007-06-03 14:26:27 +00002671 break;
aurel32e5289082009-04-18 16:16:12 +00002672 case IPC_INFO:
2673 case SEM_INFO:
2674 arg.__buf = &seminfo;
2675 ret = get_errno(semctl(semid, semnum, cmd, arg));
2676 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2677 if (err)
2678 return err;
2679 break;
2680 case IPC_RMID:
2681 case GETPID:
2682 case GETNCNT:
2683 case GETZCNT:
2684 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2685 break;
ths3eb6b042007-06-03 14:26:27 +00002686 }
2687
2688 return ret;
2689}
2690
aurel32e5289082009-04-18 16:16:12 +00002691struct target_sembuf {
2692 unsigned short sem_num;
2693 short sem_op;
2694 short sem_flg;
2695};
2696
2697static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2698 abi_ulong target_addr,
2699 unsigned nsops)
2700{
2701 struct target_sembuf *target_sembuf;
2702 int i;
2703
2704 target_sembuf = lock_user(VERIFY_READ, target_addr,
2705 nsops*sizeof(struct target_sembuf), 1);
2706 if (!target_sembuf)
2707 return -TARGET_EFAULT;
2708
2709 for(i=0; i<nsops; i++) {
2710 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2711 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2712 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2713 }
2714
2715 unlock_user(target_sembuf, target_addr, 0);
2716
2717 return 0;
2718}
2719
2720static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2721{
2722 struct sembuf sops[nsops];
2723
2724 if (target_to_host_sembuf(sops, ptr, nsops))
2725 return -TARGET_EFAULT;
2726
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002727 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002728}
2729
ths1bc012f2007-06-03 14:27:49 +00002730struct target_msqid_ds
2731{
aurel321c54ff92008-10-13 21:08:44 +00002732 struct target_ipc_perm msg_perm;
2733 abi_ulong msg_stime;
2734#if TARGET_ABI_BITS == 32
2735 abi_ulong __unused1;
2736#endif
2737 abi_ulong msg_rtime;
2738#if TARGET_ABI_BITS == 32
2739 abi_ulong __unused2;
2740#endif
2741 abi_ulong msg_ctime;
2742#if TARGET_ABI_BITS == 32
2743 abi_ulong __unused3;
2744#endif
2745 abi_ulong __msg_cbytes;
2746 abi_ulong msg_qnum;
2747 abi_ulong msg_qbytes;
2748 abi_ulong msg_lspid;
2749 abi_ulong msg_lrpid;
2750 abi_ulong __unused4;
2751 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002752};
2753
bellard579a97f2007-11-11 14:26:47 +00002754static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2755 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002756{
2757 struct target_msqid_ds *target_md;
2758
bellard579a97f2007-11-11 14:26:47 +00002759 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2760 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002761 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2762 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002763 host_md->msg_stime = tswapal(target_md->msg_stime);
2764 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2765 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2766 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2767 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2768 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2769 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2770 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002771 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002772 return 0;
ths1bc012f2007-06-03 14:27:49 +00002773}
2774
bellard579a97f2007-11-11 14:26:47 +00002775static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2776 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002777{
2778 struct target_msqid_ds *target_md;
2779
bellard579a97f2007-11-11 14:26:47 +00002780 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2781 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002782 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2783 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002784 target_md->msg_stime = tswapal(host_md->msg_stime);
2785 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2786 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2787 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2788 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2789 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2790 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2791 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002792 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002793 return 0;
ths1bc012f2007-06-03 14:27:49 +00002794}
2795
aurel321c54ff92008-10-13 21:08:44 +00002796struct target_msginfo {
2797 int msgpool;
2798 int msgmap;
2799 int msgmax;
2800 int msgmnb;
2801 int msgmni;
2802 int msgssz;
2803 int msgtql;
2804 unsigned short int msgseg;
2805};
2806
2807static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2808 struct msginfo *host_msginfo)
2809{
2810 struct target_msginfo *target_msginfo;
2811 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2812 return -TARGET_EFAULT;
2813 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2814 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2815 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2816 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2817 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2818 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2819 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2820 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2821 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002822 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002823}
2824
2825static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002826{
2827 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002828 struct msginfo msginfo;
2829 abi_long ret = -TARGET_EINVAL;
2830
2831 cmd &= 0xff;
2832
2833 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002834 case IPC_STAT:
2835 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002836 case MSG_STAT:
2837 if (target_to_host_msqid_ds(&dsarg,ptr))
2838 return -TARGET_EFAULT;
2839 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2840 if (host_to_target_msqid_ds(ptr,&dsarg))
2841 return -TARGET_EFAULT;
2842 break;
2843 case IPC_RMID:
2844 ret = get_errno(msgctl(msgid, cmd, NULL));
2845 break;
2846 case IPC_INFO:
2847 case MSG_INFO:
2848 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2849 if (host_to_target_msginfo(ptr, &msginfo))
2850 return -TARGET_EFAULT;
2851 break;
ths1bc012f2007-06-03 14:27:49 +00002852 }
aurel321c54ff92008-10-13 21:08:44 +00002853
ths1bc012f2007-06-03 14:27:49 +00002854 return ret;
2855}
2856
2857struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002858 abi_long mtype;
2859 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002860};
2861
blueswir1992f48a2007-10-14 16:27:31 +00002862static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2863 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002864{
2865 struct target_msgbuf *target_mb;
2866 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002867 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002868
bellard579a97f2007-11-11 14:26:47 +00002869 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2870 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002871 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002872 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002873 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002874 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2875 free(host_mb);
2876 unlock_user_struct(target_mb, msgp, 0);
2877
2878 return ret;
2879}
2880
blueswir1992f48a2007-10-14 16:27:31 +00002881static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002882 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002883 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002884{
2885 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002886 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002887 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002888 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002889
bellard579a97f2007-11-11 14:26:47 +00002890 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2891 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002892
Jim Meyering0d07fe42012-08-22 13:55:53 +02002893 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002894 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002895
bellard579a97f2007-11-11 14:26:47 +00002896 if (ret > 0) {
2897 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2898 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2899 if (!target_mtext) {
2900 ret = -TARGET_EFAULT;
2901 goto end;
2902 }
aurel321c54ff92008-10-13 21:08:44 +00002903 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002904 unlock_user(target_mtext, target_mtext_addr, ret);
2905 }
aurel321c54ff92008-10-13 21:08:44 +00002906
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002907 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002908
bellard579a97f2007-11-11 14:26:47 +00002909end:
2910 if (target_mb)
2911 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002912 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002913 return ret;
2914}
2915
Riku Voipio88a8c982009-04-03 10:42:00 +03002916static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2917 abi_ulong target_addr)
2918{
2919 struct target_shmid_ds *target_sd;
2920
2921 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2922 return -TARGET_EFAULT;
2923 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2924 return -TARGET_EFAULT;
2925 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2926 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2927 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2928 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2929 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2930 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2931 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2932 unlock_user_struct(target_sd, target_addr, 0);
2933 return 0;
2934}
2935
2936static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2937 struct shmid_ds *host_sd)
2938{
2939 struct target_shmid_ds *target_sd;
2940
2941 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2942 return -TARGET_EFAULT;
2943 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2944 return -TARGET_EFAULT;
2945 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2946 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2947 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2948 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2949 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2950 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2951 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2952 unlock_user_struct(target_sd, target_addr, 1);
2953 return 0;
2954}
2955
2956struct target_shminfo {
2957 abi_ulong shmmax;
2958 abi_ulong shmmin;
2959 abi_ulong shmmni;
2960 abi_ulong shmseg;
2961 abi_ulong shmall;
2962};
2963
2964static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2965 struct shminfo *host_shminfo)
2966{
2967 struct target_shminfo *target_shminfo;
2968 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2969 return -TARGET_EFAULT;
2970 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2971 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2972 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2973 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2974 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2975 unlock_user_struct(target_shminfo, target_addr, 1);
2976 return 0;
2977}
2978
2979struct target_shm_info {
2980 int used_ids;
2981 abi_ulong shm_tot;
2982 abi_ulong shm_rss;
2983 abi_ulong shm_swp;
2984 abi_ulong swap_attempts;
2985 abi_ulong swap_successes;
2986};
2987
2988static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2989 struct shm_info *host_shm_info)
2990{
2991 struct target_shm_info *target_shm_info;
2992 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2993 return -TARGET_EFAULT;
2994 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2995 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2996 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2997 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2998 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2999 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
3000 unlock_user_struct(target_shm_info, target_addr, 1);
3001 return 0;
3002}
3003
3004static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
3005{
3006 struct shmid_ds dsarg;
3007 struct shminfo shminfo;
3008 struct shm_info shm_info;
3009 abi_long ret = -TARGET_EINVAL;
3010
3011 cmd &= 0xff;
3012
3013 switch(cmd) {
3014 case IPC_STAT:
3015 case IPC_SET:
3016 case SHM_STAT:
3017 if (target_to_host_shmid_ds(&dsarg, buf))
3018 return -TARGET_EFAULT;
3019 ret = get_errno(shmctl(shmid, cmd, &dsarg));
3020 if (host_to_target_shmid_ds(buf, &dsarg))
3021 return -TARGET_EFAULT;
3022 break;
3023 case IPC_INFO:
3024 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
3025 if (host_to_target_shminfo(buf, &shminfo))
3026 return -TARGET_EFAULT;
3027 break;
3028 case SHM_INFO:
3029 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
3030 if (host_to_target_shm_info(buf, &shm_info))
3031 return -TARGET_EFAULT;
3032 break;
3033 case IPC_RMID:
3034 case SHM_LOCK:
3035 case SHM_UNLOCK:
3036 ret = get_errno(shmctl(shmid, cmd, NULL));
3037 break;
3038 }
3039
3040 return ret;
3041}
3042
3043static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
3044{
3045 abi_long raddr;
3046 void *host_raddr;
3047 struct shmid_ds shm_info;
3048 int i,ret;
3049
3050 /* find out the length of the shared memory segment */
3051 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3052 if (is_error(ret)) {
3053 /* can't get length, bail out */
3054 return ret;
3055 }
3056
3057 mmap_lock();
3058
3059 if (shmaddr)
3060 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3061 else {
3062 abi_ulong mmap_start;
3063
3064 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3065
3066 if (mmap_start == -1) {
3067 errno = ENOMEM;
3068 host_raddr = (void *)-1;
3069 } else
3070 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3071 }
3072
3073 if (host_raddr == (void *)-1) {
3074 mmap_unlock();
3075 return get_errno((long)host_raddr);
3076 }
3077 raddr=h2g((unsigned long)host_raddr);
3078
3079 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3080 PAGE_VALID | PAGE_READ |
3081 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3082
3083 for (i = 0; i < N_SHM_REGIONS; i++) {
3084 if (shm_regions[i].start == 0) {
3085 shm_regions[i].start = raddr;
3086 shm_regions[i].size = shm_info.shm_segsz;
3087 break;
3088 }
3089 }
3090
3091 mmap_unlock();
3092 return raddr;
3093
3094}
3095
3096static inline abi_long do_shmdt(abi_ulong shmaddr)
3097{
3098 int i;
3099
3100 for (i = 0; i < N_SHM_REGIONS; ++i) {
3101 if (shm_regions[i].start == shmaddr) {
3102 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003103 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003104 break;
3105 }
3106 }
3107
3108 return get_errno(shmdt(g2h(shmaddr)));
3109}
3110
aurel321c54ff92008-10-13 21:08:44 +00003111#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003112/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003113/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003114static abi_long do_ipc(unsigned int call, int first,
3115 int second, int third,
3116 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003117{
3118 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003119 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003120
3121 version = call >> 16;
3122 call &= 0xffff;
3123
3124 switch (call) {
thsfa294812007-02-02 22:05:00 +00003125 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003126 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003127 break;
3128
3129 case IPCOP_semget:
3130 ret = get_errno(semget(first, second, third));
3131 break;
3132
3133 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003134 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003135 break;
thsd96372e2007-02-02 22:05:44 +00003136
aurel321c54ff92008-10-13 21:08:44 +00003137 case IPCOP_msgget:
3138 ret = get_errno(msgget(first, second));
3139 break;
thsd96372e2007-02-02 22:05:44 +00003140
aurel321c54ff92008-10-13 21:08:44 +00003141 case IPCOP_msgsnd:
3142 ret = do_msgsnd(first, ptr, second, third);
3143 break;
thsd96372e2007-02-02 22:05:44 +00003144
aurel321c54ff92008-10-13 21:08:44 +00003145 case IPCOP_msgctl:
3146 ret = do_msgctl(first, second, ptr);
3147 break;
thsd96372e2007-02-02 22:05:44 +00003148
aurel321c54ff92008-10-13 21:08:44 +00003149 case IPCOP_msgrcv:
3150 switch (version) {
3151 case 0:
3152 {
3153 struct target_ipc_kludge {
3154 abi_long msgp;
3155 abi_long msgtyp;
3156 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003157
aurel321c54ff92008-10-13 21:08:44 +00003158 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3159 ret = -TARGET_EFAULT;
3160 break;
ths1bc012f2007-06-03 14:27:49 +00003161 }
aurel321c54ff92008-10-13 21:08:44 +00003162
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003163 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003164
3165 unlock_user_struct(tmp, ptr, 0);
3166 break;
3167 }
3168 default:
3169 ret = do_msgrcv(first, ptr, second, fifth, third);
3170 }
3171 break;
thsd96372e2007-02-02 22:05:44 +00003172
bellard8853f862004-02-22 14:57:26 +00003173 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003174 switch (version) {
3175 default:
bellard5a4a8982007-11-11 17:39:18 +00003176 {
3177 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003178 raddr = do_shmat(first, ptr, second);
3179 if (is_error(raddr))
3180 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003181 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003182 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003183 break;
3184 }
3185 case 1:
3186 ret = -TARGET_EINVAL;
3187 break;
bellard5a4a8982007-11-11 17:39:18 +00003188 }
bellard8853f862004-02-22 14:57:26 +00003189 break;
3190 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003191 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003192 break;
3193
3194 case IPCOP_shmget:
3195 /* IPC_* flag values are the same on all linux platforms */
3196 ret = get_errno(shmget(first, second, third));
3197 break;
3198
3199 /* IPC_* and SHM_* command values are the same on all linux platforms */
3200 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003201 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003202 break;
3203 default:
j_mayer32407102007-09-26 23:01:49 +00003204 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003205 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003206 break;
3207 }
3208 return ret;
3209}
j_mayer32407102007-09-26 23:01:49 +00003210#endif
bellard8853f862004-02-22 14:57:26 +00003211
bellard31e31b82003-02-18 22:55:36 +00003212/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003213
Blue Swirl001faf32009-05-13 17:53:17 +00003214#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003215#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3216enum {
3217#include "syscall_types.h"
3218};
3219#undef STRUCT
3220#undef STRUCT_SPECIAL
3221
Blue Swirl001faf32009-05-13 17:53:17 +00003222#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003223#define STRUCT_SPECIAL(name)
3224#include "syscall_types.h"
3225#undef STRUCT
3226#undef STRUCT_SPECIAL
3227
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003228typedef struct IOCTLEntry IOCTLEntry;
3229
3230typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3231 int fd, abi_long cmd, abi_long arg);
3232
3233struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003234 unsigned int target_cmd;
3235 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003236 const char *name;
3237 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003238 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003239 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003240};
bellard31e31b82003-02-18 22:55:36 +00003241
3242#define IOC_R 0x0001
3243#define IOC_W 0x0002
3244#define IOC_RW (IOC_R | IOC_W)
3245
3246#define MAX_STRUCT_SIZE 4096
3247
Peter Maydelldace20d2011-01-10 13:11:24 +00003248#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003249/* So fiemap access checks don't overflow on 32 bit systems.
3250 * This is very slightly smaller than the limit imposed by
3251 * the underlying kernel.
3252 */
3253#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3254 / sizeof(struct fiemap_extent))
3255
3256static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3257 int fd, abi_long cmd, abi_long arg)
3258{
3259 /* The parameter for this ioctl is a struct fiemap followed
3260 * by an array of struct fiemap_extent whose size is set
3261 * in fiemap->fm_extent_count. The array is filled in by the
3262 * ioctl.
3263 */
3264 int target_size_in, target_size_out;
3265 struct fiemap *fm;
3266 const argtype *arg_type = ie->arg_type;
3267 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3268 void *argptr, *p;
3269 abi_long ret;
3270 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3271 uint32_t outbufsz;
3272 int free_fm = 0;
3273
3274 assert(arg_type[0] == TYPE_PTR);
3275 assert(ie->access == IOC_RW);
3276 arg_type++;
3277 target_size_in = thunk_type_size(arg_type, 0);
3278 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3279 if (!argptr) {
3280 return -TARGET_EFAULT;
3281 }
3282 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3283 unlock_user(argptr, arg, 0);
3284 fm = (struct fiemap *)buf_temp;
3285 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3286 return -TARGET_EINVAL;
3287 }
3288
3289 outbufsz = sizeof (*fm) +
3290 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3291
3292 if (outbufsz > MAX_STRUCT_SIZE) {
3293 /* We can't fit all the extents into the fixed size buffer.
3294 * Allocate one that is large enough and use it instead.
3295 */
3296 fm = malloc(outbufsz);
3297 if (!fm) {
3298 return -TARGET_ENOMEM;
3299 }
3300 memcpy(fm, buf_temp, sizeof(struct fiemap));
3301 free_fm = 1;
3302 }
3303 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3304 if (!is_error(ret)) {
3305 target_size_out = target_size_in;
3306 /* An extent_count of 0 means we were only counting the extents
3307 * so there are no structs to copy
3308 */
3309 if (fm->fm_extent_count != 0) {
3310 target_size_out += fm->fm_mapped_extents * extent_size;
3311 }
3312 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3313 if (!argptr) {
3314 ret = -TARGET_EFAULT;
3315 } else {
3316 /* Convert the struct fiemap */
3317 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3318 if (fm->fm_extent_count != 0) {
3319 p = argptr + target_size_in;
3320 /* ...and then all the struct fiemap_extents */
3321 for (i = 0; i < fm->fm_mapped_extents; i++) {
3322 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3323 THUNK_TARGET);
3324 p += extent_size;
3325 }
3326 }
3327 unlock_user(argptr, arg, target_size_out);
3328 }
3329 }
3330 if (free_fm) {
3331 free(fm);
3332 }
3333 return ret;
3334}
Peter Maydelldace20d2011-01-10 13:11:24 +00003335#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003336
Laurent Vivier059c2f22011-03-30 00:12:12 +02003337static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3338 int fd, abi_long cmd, abi_long arg)
3339{
3340 const argtype *arg_type = ie->arg_type;
3341 int target_size;
3342 void *argptr;
3343 int ret;
3344 struct ifconf *host_ifconf;
3345 uint32_t outbufsz;
3346 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3347 int target_ifreq_size;
3348 int nb_ifreq;
3349 int free_buf = 0;
3350 int i;
3351 int target_ifc_len;
3352 abi_long target_ifc_buf;
3353 int host_ifc_len;
3354 char *host_ifc_buf;
3355
3356 assert(arg_type[0] == TYPE_PTR);
3357 assert(ie->access == IOC_RW);
3358
3359 arg_type++;
3360 target_size = thunk_type_size(arg_type, 0);
3361
3362 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3363 if (!argptr)
3364 return -TARGET_EFAULT;
3365 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3366 unlock_user(argptr, arg, 0);
3367
3368 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3369 target_ifc_len = host_ifconf->ifc_len;
3370 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3371
3372 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3373 nb_ifreq = target_ifc_len / target_ifreq_size;
3374 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3375
3376 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3377 if (outbufsz > MAX_STRUCT_SIZE) {
3378 /* We can't fit all the extents into the fixed size buffer.
3379 * Allocate one that is large enough and use it instead.
3380 */
3381 host_ifconf = malloc(outbufsz);
3382 if (!host_ifconf) {
3383 return -TARGET_ENOMEM;
3384 }
3385 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3386 free_buf = 1;
3387 }
3388 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3389
3390 host_ifconf->ifc_len = host_ifc_len;
3391 host_ifconf->ifc_buf = host_ifc_buf;
3392
3393 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3394 if (!is_error(ret)) {
3395 /* convert host ifc_len to target ifc_len */
3396
3397 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3398 target_ifc_len = nb_ifreq * target_ifreq_size;
3399 host_ifconf->ifc_len = target_ifc_len;
3400
3401 /* restore target ifc_buf */
3402
3403 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3404
3405 /* copy struct ifconf to target user */
3406
3407 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3408 if (!argptr)
3409 return -TARGET_EFAULT;
3410 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3411 unlock_user(argptr, arg, target_size);
3412
3413 /* copy ifreq[] to target user */
3414
3415 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3416 for (i = 0; i < nb_ifreq ; i++) {
3417 thunk_convert(argptr + i * target_ifreq_size,
3418 host_ifc_buf + i * sizeof(struct ifreq),
3419 ifreq_arg_type, THUNK_TARGET);
3420 }
3421 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3422 }
3423
3424 if (free_buf) {
3425 free(host_ifconf);
3426 }
3427
3428 return ret;
3429}
3430
Alexander Graf56e904e2012-01-31 18:42:06 +01003431static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3432 abi_long cmd, abi_long arg)
3433{
3434 void *argptr;
3435 struct dm_ioctl *host_dm;
3436 abi_long guest_data;
3437 uint32_t guest_data_size;
3438 int target_size;
3439 const argtype *arg_type = ie->arg_type;
3440 abi_long ret;
3441 void *big_buf = NULL;
3442 char *host_data;
3443
3444 arg_type++;
3445 target_size = thunk_type_size(arg_type, 0);
3446 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3447 if (!argptr) {
3448 ret = -TARGET_EFAULT;
3449 goto out;
3450 }
3451 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3452 unlock_user(argptr, arg, 0);
3453
3454 /* buf_temp is too small, so fetch things into a bigger buffer */
3455 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3456 memcpy(big_buf, buf_temp, target_size);
3457 buf_temp = big_buf;
3458 host_dm = big_buf;
3459
3460 guest_data = arg + host_dm->data_start;
3461 if ((guest_data - arg) < 0) {
3462 ret = -EINVAL;
3463 goto out;
3464 }
3465 guest_data_size = host_dm->data_size - host_dm->data_start;
3466 host_data = (char*)host_dm + host_dm->data_start;
3467
3468 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3469 switch (ie->host_cmd) {
3470 case DM_REMOVE_ALL:
3471 case DM_LIST_DEVICES:
3472 case DM_DEV_CREATE:
3473 case DM_DEV_REMOVE:
3474 case DM_DEV_SUSPEND:
3475 case DM_DEV_STATUS:
3476 case DM_DEV_WAIT:
3477 case DM_TABLE_STATUS:
3478 case DM_TABLE_CLEAR:
3479 case DM_TABLE_DEPS:
3480 case DM_LIST_VERSIONS:
3481 /* no input data */
3482 break;
3483 case DM_DEV_RENAME:
3484 case DM_DEV_SET_GEOMETRY:
3485 /* data contains only strings */
3486 memcpy(host_data, argptr, guest_data_size);
3487 break;
3488 case DM_TARGET_MSG:
3489 memcpy(host_data, argptr, guest_data_size);
3490 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3491 break;
3492 case DM_TABLE_LOAD:
3493 {
3494 void *gspec = argptr;
3495 void *cur_data = host_data;
3496 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3497 int spec_size = thunk_type_size(arg_type, 0);
3498 int i;
3499
3500 for (i = 0; i < host_dm->target_count; i++) {
3501 struct dm_target_spec *spec = cur_data;
3502 uint32_t next;
3503 int slen;
3504
3505 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3506 slen = strlen((char*)gspec + spec_size) + 1;
3507 next = spec->next;
3508 spec->next = sizeof(*spec) + slen;
3509 strcpy((char*)&spec[1], gspec + spec_size);
3510 gspec += next;
3511 cur_data += spec->next;
3512 }
3513 break;
3514 }
3515 default:
3516 ret = -TARGET_EINVAL;
3517 goto out;
3518 }
3519 unlock_user(argptr, guest_data, 0);
3520
3521 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3522 if (!is_error(ret)) {
3523 guest_data = arg + host_dm->data_start;
3524 guest_data_size = host_dm->data_size - host_dm->data_start;
3525 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3526 switch (ie->host_cmd) {
3527 case DM_REMOVE_ALL:
3528 case DM_DEV_CREATE:
3529 case DM_DEV_REMOVE:
3530 case DM_DEV_RENAME:
3531 case DM_DEV_SUSPEND:
3532 case DM_DEV_STATUS:
3533 case DM_TABLE_LOAD:
3534 case DM_TABLE_CLEAR:
3535 case DM_TARGET_MSG:
3536 case DM_DEV_SET_GEOMETRY:
3537 /* no return data */
3538 break;
3539 case DM_LIST_DEVICES:
3540 {
3541 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3542 uint32_t remaining_data = guest_data_size;
3543 void *cur_data = argptr;
3544 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3545 int nl_size = 12; /* can't use thunk_size due to alignment */
3546
3547 while (1) {
3548 uint32_t next = nl->next;
3549 if (next) {
3550 nl->next = nl_size + (strlen(nl->name) + 1);
3551 }
3552 if (remaining_data < nl->next) {
3553 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3554 break;
3555 }
3556 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3557 strcpy(cur_data + nl_size, nl->name);
3558 cur_data += nl->next;
3559 remaining_data -= nl->next;
3560 if (!next) {
3561 break;
3562 }
3563 nl = (void*)nl + next;
3564 }
3565 break;
3566 }
3567 case DM_DEV_WAIT:
3568 case DM_TABLE_STATUS:
3569 {
3570 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3571 void *cur_data = argptr;
3572 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3573 int spec_size = thunk_type_size(arg_type, 0);
3574 int i;
3575
3576 for (i = 0; i < host_dm->target_count; i++) {
3577 uint32_t next = spec->next;
3578 int slen = strlen((char*)&spec[1]) + 1;
3579 spec->next = (cur_data - argptr) + spec_size + slen;
3580 if (guest_data_size < spec->next) {
3581 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3582 break;
3583 }
3584 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3585 strcpy(cur_data + spec_size, (char*)&spec[1]);
3586 cur_data = argptr + spec->next;
3587 spec = (void*)host_dm + host_dm->data_start + next;
3588 }
3589 break;
3590 }
3591 case DM_TABLE_DEPS:
3592 {
3593 void *hdata = (void*)host_dm + host_dm->data_start;
3594 int count = *(uint32_t*)hdata;
3595 uint64_t *hdev = hdata + 8;
3596 uint64_t *gdev = argptr + 8;
3597 int i;
3598
3599 *(uint32_t*)argptr = tswap32(count);
3600 for (i = 0; i < count; i++) {
3601 *gdev = tswap64(*hdev);
3602 gdev++;
3603 hdev++;
3604 }
3605 break;
3606 }
3607 case DM_LIST_VERSIONS:
3608 {
3609 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3610 uint32_t remaining_data = guest_data_size;
3611 void *cur_data = argptr;
3612 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3613 int vers_size = thunk_type_size(arg_type, 0);
3614
3615 while (1) {
3616 uint32_t next = vers->next;
3617 if (next) {
3618 vers->next = vers_size + (strlen(vers->name) + 1);
3619 }
3620 if (remaining_data < vers->next) {
3621 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3622 break;
3623 }
3624 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3625 strcpy(cur_data + vers_size, vers->name);
3626 cur_data += vers->next;
3627 remaining_data -= vers->next;
3628 if (!next) {
3629 break;
3630 }
3631 vers = (void*)vers + next;
3632 }
3633 break;
3634 }
3635 default:
3636 ret = -TARGET_EINVAL;
3637 goto out;
3638 }
3639 unlock_user(argptr, guest_data, guest_data_size);
3640
3641 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3642 if (!argptr) {
3643 ret = -TARGET_EFAULT;
3644 goto out;
3645 }
3646 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3647 unlock_user(argptr, arg, target_size);
3648 }
3649out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003650 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003651 return ret;
3652}
3653
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003654static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3655 int fd, abi_long cmd, abi_long arg)
3656{
3657 const argtype *arg_type = ie->arg_type;
3658 const StructEntry *se;
3659 const argtype *field_types;
3660 const int *dst_offsets, *src_offsets;
3661 int target_size;
3662 void *argptr;
3663 abi_ulong *target_rt_dev_ptr;
3664 unsigned long *host_rt_dev_ptr;
3665 abi_long ret;
3666 int i;
3667
3668 assert(ie->access == IOC_W);
3669 assert(*arg_type == TYPE_PTR);
3670 arg_type++;
3671 assert(*arg_type == TYPE_STRUCT);
3672 target_size = thunk_type_size(arg_type, 0);
3673 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3674 if (!argptr) {
3675 return -TARGET_EFAULT;
3676 }
3677 arg_type++;
3678 assert(*arg_type == (int)STRUCT_rtentry);
3679 se = struct_entries + *arg_type++;
3680 assert(se->convert[0] == NULL);
3681 /* convert struct here to be able to catch rt_dev string */
3682 field_types = se->field_types;
3683 dst_offsets = se->field_offsets[THUNK_HOST];
3684 src_offsets = se->field_offsets[THUNK_TARGET];
3685 for (i = 0; i < se->nb_fields; i++) {
3686 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3687 assert(*field_types == TYPE_PTRVOID);
3688 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3689 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3690 if (*target_rt_dev_ptr != 0) {
3691 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3692 tswapal(*target_rt_dev_ptr));
3693 if (!*host_rt_dev_ptr) {
3694 unlock_user(argptr, arg, 0);
3695 return -TARGET_EFAULT;
3696 }
3697 } else {
3698 *host_rt_dev_ptr = 0;
3699 }
3700 field_types++;
3701 continue;
3702 }
3703 field_types = thunk_convert(buf_temp + dst_offsets[i],
3704 argptr + src_offsets[i],
3705 field_types, THUNK_HOST);
3706 }
3707 unlock_user(argptr, arg, 0);
3708
3709 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3710 if (*host_rt_dev_ptr != 0) {
3711 unlock_user((void *)*host_rt_dev_ptr,
3712 *target_rt_dev_ptr, 0);
3713 }
3714 return ret;
3715}
3716
Paul Burtonca56f5b2014-06-22 11:25:47 +01003717static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
3718 int fd, abi_long cmd, abi_long arg)
3719{
3720 int sig = target_to_host_signal(arg);
3721 return get_errno(ioctl(fd, ie->host_cmd, sig));
3722}
3723
blueswir19f106a72008-10-05 10:52:52 +00003724static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003725#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003726 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3727#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3728 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003729#include "ioctls.h"
3730 { 0, 0, },
3731};
3732
pbrook53a59602006-03-25 19:31:22 +00003733/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003734/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003735static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003736{
3737 const IOCTLEntry *ie;
3738 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003739 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003740 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003741 int target_size;
3742 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003743
3744 ie = ioctl_entries;
3745 for(;;) {
3746 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003747 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003748 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003749 }
3750 if (ie->target_cmd == cmd)
3751 break;
3752 ie++;
3753 }
3754 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003755#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003756 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003757#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003758 if (ie->do_ioctl) {
3759 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3760 }
3761
bellard31e31b82003-02-18 22:55:36 +00003762 switch(arg_type[0]) {
3763 case TYPE_NULL:
3764 /* no argument */
3765 ret = get_errno(ioctl(fd, ie->host_cmd));
3766 break;
3767 case TYPE_PTRVOID:
3768 case TYPE_INT:
3769 /* int argment */
3770 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3771 break;
3772 case TYPE_PTR:
3773 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003774 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003775 switch(ie->access) {
3776 case IOC_R:
3777 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3778 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003779 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3780 if (!argptr)
3781 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003782 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3783 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003784 }
3785 break;
3786 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003787 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3788 if (!argptr)
3789 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003790 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3791 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003792 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3793 break;
3794 default:
3795 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003796 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3797 if (!argptr)
3798 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003799 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3800 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003801 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3802 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003803 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3804 if (!argptr)
3805 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003806 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3807 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003808 }
3809 break;
3810 }
3811 break;
3812 default:
j_mayer32407102007-09-26 23:01:49 +00003813 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3814 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003815 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003816 break;
3817 }
3818 return ret;
3819}
3820
blueswir1b39bc502008-10-05 10:51:10 +00003821static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003822 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3823 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3824 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3825 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3826 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3827 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3828 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3829 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3830 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3831 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3832 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3833 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3834 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3835 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3836 { 0, 0, 0, 0 }
3837};
3838
blueswir1b39bc502008-10-05 10:51:10 +00003839static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003840 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3841 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3842 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3843 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3844 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3845 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3846 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3847 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3848 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3849 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3850 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3851 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3852 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3853 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3854 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3855 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3856 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3857 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3858 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3859 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3860 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3861 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3862 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3863 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3864 { 0, 0, 0, 0 }
3865};
3866
blueswir1b39bc502008-10-05 10:51:10 +00003867static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003868 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3869 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3870 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3871 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3872 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3873 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3874 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3875 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3876 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3877 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3878 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3879 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3880 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3881 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3882 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3883 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3884 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3885 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3886 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3887 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3888 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3889 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3890 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3891 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3892 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3893 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3894 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3895 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3896 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3897 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3898 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3899 { 0, 0, 0, 0 }
3900};
3901
blueswir1b39bc502008-10-05 10:51:10 +00003902static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003903 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3904 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3905 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3906 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3907 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3908 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3909 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3910 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3911 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3912 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3913 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3914 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3915 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3916 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3917 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3918 { 0, 0, 0, 0 }
3919};
3920
3921static void target_to_host_termios (void *dst, const void *src)
3922{
3923 struct host_termios *host = dst;
3924 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003925
ths5fafdf22007-09-16 21:08:06 +00003926 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003927 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003928 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003929 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003930 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003931 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003932 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003933 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3934 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003935
Arnaud Patard44607122009-04-21 17:39:08 +03003936 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003937 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3938 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003939 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003940 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003941 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003942 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003943 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003944 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003945 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003946 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3947 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003948 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3949 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3950 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3951 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3952 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003953 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003954}
ths3b46e622007-09-17 08:09:54 +00003955
bellard31e31b82003-02-18 22:55:36 +00003956static void host_to_target_termios (void *dst, const void *src)
3957{
3958 struct target_termios *target = dst;
3959 const struct host_termios *host = src;
3960
ths5fafdf22007-09-16 21:08:06 +00003961 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003962 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003963 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003964 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003965 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003966 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003967 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003968 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3969 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003970
Arnaud Patard44607122009-04-21 17:39:08 +03003971 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003972 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3973 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3974 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3975 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3976 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3977 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3978 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3979 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3980 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3981 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3982 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3983 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3984 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3985 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3986 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3987 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3988 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3989}
3990
blueswir18e853dc2008-10-05 10:49:32 +00003991static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003992 .convert = { host_to_target_termios, target_to_host_termios },
3993 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3994 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3995};
3996
bellard5286db72003-06-05 00:57:30 +00003997static bitmask_transtbl mmap_flags_tbl[] = {
3998 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3999 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
4000 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
4001 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
4002 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
4003 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
4004 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
4005 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
Christophe Lyone8efd8e2014-02-03 17:04:32 +01004006 { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
4007 MAP_NORESERVE },
bellard5286db72003-06-05 00:57:30 +00004008 { 0, 0, 0, 0 }
4009};
4010
bellard2ab83ea2003-06-15 19:56:46 +00004011#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00004012
4013/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00004014static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00004015
bellard03acab62007-11-11 14:57:14 +00004016static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004017{
4018 int size;
pbrook53a59602006-03-25 19:31:22 +00004019 void *p;
bellard6dbad632003-03-16 18:05:05 +00004020
4021 if (!ldt_table)
4022 return 0;
4023 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
4024 if (size > bytecount)
4025 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00004026 p = lock_user(VERIFY_WRITE, ptr, size, 0);
4027 if (!p)
bellard03acab62007-11-11 14:57:14 +00004028 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00004029 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00004030 memcpy(p, ldt_table, size);
4031 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00004032 return size;
4033}
4034
4035/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00004036static abi_long write_ldt(CPUX86State *env,
4037 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00004038{
4039 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00004040 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00004041 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00004042 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00004043 uint32_t *lp, entry_1, entry_2;
4044
4045 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00004046 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00004047 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00004048 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00004049 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004050 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00004051 ldt_info.limit = tswap32(target_ldt_info->limit);
4052 ldt_info.flags = tswap32(target_ldt_info->flags);
4053 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00004054
bellard6dbad632003-03-16 18:05:05 +00004055 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00004056 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004057 seg_32bit = ldt_info.flags & 1;
4058 contents = (ldt_info.flags >> 1) & 3;
4059 read_exec_only = (ldt_info.flags >> 3) & 1;
4060 limit_in_pages = (ldt_info.flags >> 4) & 1;
4061 seg_not_present = (ldt_info.flags >> 5) & 1;
4062 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004063#ifdef TARGET_ABI32
4064 lm = 0;
4065#else
4066 lm = (ldt_info.flags >> 7) & 1;
4067#endif
bellard6dbad632003-03-16 18:05:05 +00004068 if (contents == 3) {
4069 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004070 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004071 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004072 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004073 }
4074 /* allocate the LDT */
4075 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004076 env->ldt.base = target_mmap(0,
4077 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4078 PROT_READ|PROT_WRITE,
4079 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4080 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004081 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004082 memset(g2h(env->ldt.base), 0,
4083 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004084 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004085 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004086 }
4087
4088 /* NOTE: same code as Linux kernel */
4089 /* Allow LDTs to be cleared by the user. */
4090 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4091 if (oldmode ||
4092 (contents == 0 &&
4093 read_exec_only == 1 &&
4094 seg_32bit == 0 &&
4095 limit_in_pages == 0 &&
4096 seg_not_present == 1 &&
4097 useable == 0 )) {
4098 entry_1 = 0;
4099 entry_2 = 0;
4100 goto install;
4101 }
4102 }
ths3b46e622007-09-17 08:09:54 +00004103
bellard6dbad632003-03-16 18:05:05 +00004104 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4105 (ldt_info.limit & 0x0ffff);
4106 entry_2 = (ldt_info.base_addr & 0xff000000) |
4107 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4108 (ldt_info.limit & 0xf0000) |
4109 ((read_exec_only ^ 1) << 9) |
4110 (contents << 10) |
4111 ((seg_not_present ^ 1) << 15) |
4112 (seg_32bit << 22) |
4113 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004114 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004115 0x7000;
4116 if (!oldmode)
4117 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004118
bellard6dbad632003-03-16 18:05:05 +00004119 /* Install the new entry ... */
4120install:
4121 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4122 lp[0] = tswap32(entry_1);
4123 lp[1] = tswap32(entry_2);
4124 return 0;
4125}
4126
4127/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004128static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4129 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004130{
bellard03acab62007-11-11 14:57:14 +00004131 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004132
bellard6dbad632003-03-16 18:05:05 +00004133 switch (func) {
4134 case 0:
4135 ret = read_ldt(ptr, bytecount);
4136 break;
4137 case 1:
4138 ret = write_ldt(env, ptr, bytecount, 1);
4139 break;
4140 case 0x11:
4141 ret = write_ldt(env, ptr, bytecount, 0);
4142 break;
bellard03acab62007-11-11 14:57:14 +00004143 default:
4144 ret = -TARGET_ENOSYS;
4145 break;
bellard6dbad632003-03-16 18:05:05 +00004146 }
4147 return ret;
4148}
bellard1b6b0292003-03-22 17:31:38 +00004149
blueswir14583f582008-08-24 10:35:55 +00004150#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004151abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004152{
4153 uint64_t *gdt_table = g2h(env->gdt.base);
4154 struct target_modify_ldt_ldt_s ldt_info;
4155 struct target_modify_ldt_ldt_s *target_ldt_info;
4156 int seg_32bit, contents, read_exec_only, limit_in_pages;
4157 int seg_not_present, useable, lm;
4158 uint32_t *lp, entry_1, entry_2;
4159 int i;
4160
4161 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4162 if (!target_ldt_info)
4163 return -TARGET_EFAULT;
4164 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004165 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004166 ldt_info.limit = tswap32(target_ldt_info->limit);
4167 ldt_info.flags = tswap32(target_ldt_info->flags);
4168 if (ldt_info.entry_number == -1) {
4169 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4170 if (gdt_table[i] == 0) {
4171 ldt_info.entry_number = i;
4172 target_ldt_info->entry_number = tswap32(i);
4173 break;
4174 }
4175 }
4176 }
4177 unlock_user_struct(target_ldt_info, ptr, 1);
4178
4179 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4180 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4181 return -TARGET_EINVAL;
4182 seg_32bit = ldt_info.flags & 1;
4183 contents = (ldt_info.flags >> 1) & 3;
4184 read_exec_only = (ldt_info.flags >> 3) & 1;
4185 limit_in_pages = (ldt_info.flags >> 4) & 1;
4186 seg_not_present = (ldt_info.flags >> 5) & 1;
4187 useable = (ldt_info.flags >> 6) & 1;
4188#ifdef TARGET_ABI32
4189 lm = 0;
4190#else
4191 lm = (ldt_info.flags >> 7) & 1;
4192#endif
4193
4194 if (contents == 3) {
4195 if (seg_not_present == 0)
4196 return -TARGET_EINVAL;
4197 }
4198
4199 /* NOTE: same code as Linux kernel */
4200 /* Allow LDTs to be cleared by the user. */
4201 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4202 if ((contents == 0 &&
4203 read_exec_only == 1 &&
4204 seg_32bit == 0 &&
4205 limit_in_pages == 0 &&
4206 seg_not_present == 1 &&
4207 useable == 0 )) {
4208 entry_1 = 0;
4209 entry_2 = 0;
4210 goto install;
4211 }
4212 }
4213
4214 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4215 (ldt_info.limit & 0x0ffff);
4216 entry_2 = (ldt_info.base_addr & 0xff000000) |
4217 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4218 (ldt_info.limit & 0xf0000) |
4219 ((read_exec_only ^ 1) << 9) |
4220 (contents << 10) |
4221 ((seg_not_present ^ 1) << 15) |
4222 (seg_32bit << 22) |
4223 (limit_in_pages << 23) |
4224 (useable << 20) |
4225 (lm << 21) |
4226 0x7000;
4227
4228 /* Install the new entry ... */
4229install:
4230 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4231 lp[0] = tswap32(entry_1);
4232 lp[1] = tswap32(entry_2);
4233 return 0;
4234}
4235
blueswir18fcd3692008-08-17 20:26:25 +00004236static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004237{
4238 struct target_modify_ldt_ldt_s *target_ldt_info;
4239 uint64_t *gdt_table = g2h(env->gdt.base);
4240 uint32_t base_addr, limit, flags;
4241 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4242 int seg_not_present, useable, lm;
4243 uint32_t *lp, entry_1, entry_2;
4244
4245 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4246 if (!target_ldt_info)
4247 return -TARGET_EFAULT;
4248 idx = tswap32(target_ldt_info->entry_number);
4249 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4250 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4251 unlock_user_struct(target_ldt_info, ptr, 1);
4252 return -TARGET_EINVAL;
4253 }
4254 lp = (uint32_t *)(gdt_table + idx);
4255 entry_1 = tswap32(lp[0]);
4256 entry_2 = tswap32(lp[1]);
4257
4258 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4259 contents = (entry_2 >> 10) & 3;
4260 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4261 seg_32bit = (entry_2 >> 22) & 1;
4262 limit_in_pages = (entry_2 >> 23) & 1;
4263 useable = (entry_2 >> 20) & 1;
4264#ifdef TARGET_ABI32
4265 lm = 0;
4266#else
4267 lm = (entry_2 >> 21) & 1;
4268#endif
4269 flags = (seg_32bit << 0) | (contents << 1) |
4270 (read_exec_only << 3) | (limit_in_pages << 4) |
4271 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4272 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4273 base_addr = (entry_1 >> 16) |
4274 (entry_2 & 0xff000000) |
4275 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004276 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004277 target_ldt_info->limit = tswap32(limit);
4278 target_ldt_info->flags = tswap32(flags);
4279 unlock_user_struct(target_ldt_info, ptr, 1);
4280 return 0;
4281}
blueswir14583f582008-08-24 10:35:55 +00004282#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004283
bellardd2fd1af2007-11-14 18:08:56 +00004284#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004285abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004286{
Juan Quintela1add8692011-06-16 17:37:09 +01004287 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004288 abi_ulong val;
4289 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004290
bellardd2fd1af2007-11-14 18:08:56 +00004291 switch(code) {
4292 case TARGET_ARCH_SET_GS:
4293 case TARGET_ARCH_SET_FS:
4294 if (code == TARGET_ARCH_SET_GS)
4295 idx = R_GS;
4296 else
4297 idx = R_FS;
4298 cpu_x86_load_seg(env, idx, 0);
4299 env->segs[idx].base = addr;
4300 break;
4301 case TARGET_ARCH_GET_GS:
4302 case TARGET_ARCH_GET_FS:
4303 if (code == TARGET_ARCH_GET_GS)
4304 idx = R_GS;
4305 else
4306 idx = R_FS;
4307 val = env->segs[idx].base;
4308 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004309 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004310 break;
4311 default:
4312 ret = -TARGET_EINVAL;
4313 break;
4314 }
Juan Quintela1add8692011-06-16 17:37:09 +01004315 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004316}
4317#endif
4318
bellard2ab83ea2003-06-15 19:56:46 +00004319#endif /* defined(TARGET_I386) */
4320
Riku Voipio05098a92011-03-04 15:27:29 +02004321#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004322
pbrookd865bab2008-06-07 22:12:17 +00004323
4324static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4325typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004326 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004327 pthread_mutex_t mutex;
4328 pthread_cond_t cond;
4329 pthread_t thread;
4330 uint32_t tid;
4331 abi_ulong child_tidptr;
4332 abi_ulong parent_tidptr;
4333 sigset_t sigmask;
4334} new_thread_info;
4335
4336static void *clone_func(void *arg)
4337{
4338 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004339 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004340 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004341 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004342
4343 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004344 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004345 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004346 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004347 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004348 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004349 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004350 if (info->child_tidptr)
4351 put_user_u32(info->tid, info->child_tidptr);
4352 if (info->parent_tidptr)
4353 put_user_u32(info->tid, info->parent_tidptr);
4354 /* Enable signals. */
4355 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4356 /* Signal to the parent that we're ready. */
4357 pthread_mutex_lock(&info->mutex);
4358 pthread_cond_broadcast(&info->cond);
4359 pthread_mutex_unlock(&info->mutex);
4360 /* Wait until the parent has finshed initializing the tls state. */
4361 pthread_mutex_lock(&clone_lock);
4362 pthread_mutex_unlock(&clone_lock);
4363 cpu_loop(env);
4364 /* never exits */
4365 return NULL;
4366}
bellard1b6b0292003-03-22 17:31:38 +00004367
ths0da46a62007-10-20 20:23:07 +00004368/* do_fork() Must return host values and target errnos (unlike most
4369 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004370static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004371 abi_ulong parent_tidptr, target_ulong newtls,
4372 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004373{
Andreas Färber0429a972013-08-26 18:14:44 +02004374 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004375 int ret;
bellard5cd43932003-03-29 16:54:36 +00004376 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004377 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004378 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004379 unsigned int nptl_flags;
4380 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004381
balrog436d1242008-09-21 02:39:45 +00004382 /* Emulate vfork() with fork() */
4383 if (flags & CLONE_VFORK)
4384 flags &= ~(CLONE_VFORK | CLONE_VM);
4385
bellard1b6b0292003-03-22 17:31:38 +00004386 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004387 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004388 new_thread_info info;
4389 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004390
Anthony Liguori7267c092011-08-20 22:09:37 -05004391 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004392 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004393 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004394 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004395 /* Init regs that differ from the parent. */
4396 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004397 new_cpu = ENV_GET_CPU(new_env);
4398 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004399 ts->bprm = parent_ts->bprm;
4400 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004401 nptl_flags = flags;
4402 flags &= ~CLONE_NPTL_FLAGS2;
4403
pbrookc2764712009-03-07 15:24:59 +00004404 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4405 ts->child_tidptr = child_tidptr;
4406 }
4407
pbrookd865bab2008-06-07 22:12:17 +00004408 if (nptl_flags & CLONE_SETTLS)
4409 cpu_set_tls (new_env, newtls);
4410
4411 /* Grab a mutex so that thread setup appears atomic. */
4412 pthread_mutex_lock(&clone_lock);
4413
4414 memset(&info, 0, sizeof(info));
4415 pthread_mutex_init(&info.mutex, NULL);
4416 pthread_mutex_lock(&info.mutex);
4417 pthread_cond_init(&info.cond, NULL);
4418 info.env = new_env;
4419 if (nptl_flags & CLONE_CHILD_SETTID)
4420 info.child_tidptr = child_tidptr;
4421 if (nptl_flags & CLONE_PARENT_SETTID)
4422 info.parent_tidptr = parent_tidptr;
4423
4424 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004425 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4426 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004427 /* It is not safe to deliver signals until the child has finished
4428 initializing, so temporarily block all signals. */
4429 sigfillset(&sigmask);
4430 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4431
4432 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004433 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004434
4435 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4436 pthread_attr_destroy(&attr);
4437 if (ret == 0) {
4438 /* Wait for the child to initialize. */
4439 pthread_cond_wait(&info.cond, &info.mutex);
4440 ret = info.tid;
4441 if (flags & CLONE_PARENT_SETTID)
4442 put_user_u32(ret, parent_tidptr);
4443 } else {
4444 ret = -1;
4445 }
4446 pthread_mutex_unlock(&info.mutex);
4447 pthread_cond_destroy(&info.cond);
4448 pthread_mutex_destroy(&info.mutex);
4449 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004450 } else {
4451 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004452 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004453 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004454 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004455 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004456 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004457 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004458 cpu_clone_regs(env, newsp);
4459 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004460 /* There is a race condition here. The parent process could
4461 theoretically read the TID in the child process before the child
4462 tid is set. This would require using either ptrace
4463 (not implemented) or having *_tidptr to point at a shared memory
4464 mapping. We can't repeat the spinlock hack used above because
4465 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004466 if (flags & CLONE_CHILD_SETTID)
4467 put_user_u32(gettid(), child_tidptr);
4468 if (flags & CLONE_PARENT_SETTID)
4469 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004470 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004471 if (flags & CLONE_SETTLS)
4472 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004473 if (flags & CLONE_CHILD_CLEARTID)
4474 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004475 } else {
4476 fork_end(0);
4477 }
bellard1b6b0292003-03-22 17:31:38 +00004478 }
4479 return ret;
4480}
4481
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004482/* warning : doesn't handle linux specific flags... */
4483static int target_to_host_fcntl_cmd(int cmd)
4484{
4485 switch(cmd) {
4486 case TARGET_F_DUPFD:
4487 case TARGET_F_GETFD:
4488 case TARGET_F_SETFD:
4489 case TARGET_F_GETFL:
4490 case TARGET_F_SETFL:
4491 return cmd;
4492 case TARGET_F_GETLK:
4493 return F_GETLK;
4494 case TARGET_F_SETLK:
4495 return F_SETLK;
4496 case TARGET_F_SETLKW:
4497 return F_SETLKW;
4498 case TARGET_F_GETOWN:
4499 return F_GETOWN;
4500 case TARGET_F_SETOWN:
4501 return F_SETOWN;
4502 case TARGET_F_GETSIG:
4503 return F_GETSIG;
4504 case TARGET_F_SETSIG:
4505 return F_SETSIG;
4506#if TARGET_ABI_BITS == 32
4507 case TARGET_F_GETLK64:
4508 return F_GETLK64;
4509 case TARGET_F_SETLK64:
4510 return F_SETLK64;
4511 case TARGET_F_SETLKW64:
4512 return F_SETLKW64;
4513#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004514 case TARGET_F_SETLEASE:
4515 return F_SETLEASE;
4516 case TARGET_F_GETLEASE:
4517 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004518#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004519 case TARGET_F_DUPFD_CLOEXEC:
4520 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004521#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004522 case TARGET_F_NOTIFY:
4523 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004524#ifdef F_GETOWN_EX
4525 case TARGET_F_GETOWN_EX:
4526 return F_GETOWN_EX;
4527#endif
4528#ifdef F_SETOWN_EX
4529 case TARGET_F_SETOWN_EX:
4530 return F_SETOWN_EX;
4531#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004532 default:
4533 return -TARGET_EINVAL;
4534 }
4535 return -TARGET_EINVAL;
4536}
4537
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004538#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4539static const bitmask_transtbl flock_tbl[] = {
4540 TRANSTBL_CONVERT(F_RDLCK),
4541 TRANSTBL_CONVERT(F_WRLCK),
4542 TRANSTBL_CONVERT(F_UNLCK),
4543 TRANSTBL_CONVERT(F_EXLCK),
4544 TRANSTBL_CONVERT(F_SHLCK),
4545 { 0, 0, 0, 0 }
4546};
4547
blueswir1992f48a2007-10-14 16:27:31 +00004548static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004549{
4550 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004551 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004552 struct flock64 fl64;
4553 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004554#ifdef F_GETOWN_EX
4555 struct f_owner_ex fox;
4556 struct target_f_owner_ex *target_fox;
4557#endif
blueswir1992f48a2007-10-14 16:27:31 +00004558 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004559 int host_cmd = target_to_host_fcntl_cmd(cmd);
4560
4561 if (host_cmd == -TARGET_EINVAL)
4562 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004563
bellard7775e9e2003-05-14 22:46:48 +00004564 switch(cmd) {
4565 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004566 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4567 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004568 fl.l_type =
4569 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004570 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004571 fl.l_start = tswapal(target_fl->l_start);
4572 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004573 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004574 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004575 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004576 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004577 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4578 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004579 target_fl->l_type =
4580 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004581 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004582 target_fl->l_start = tswapal(fl.l_start);
4583 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004584 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004585 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004586 }
4587 break;
ths3b46e622007-09-17 08:09:54 +00004588
bellard7775e9e2003-05-14 22:46:48 +00004589 case TARGET_F_SETLK:
4590 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004591 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4592 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004593 fl.l_type =
4594 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004595 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004596 fl.l_start = tswapal(target_fl->l_start);
4597 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004598 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004599 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004600 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004601 break;
ths3b46e622007-09-17 08:09:54 +00004602
bellard7775e9e2003-05-14 22:46:48 +00004603 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004604 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4605 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004606 fl64.l_type =
4607 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004608 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004609 fl64.l_start = tswap64(target_fl64->l_start);
4610 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004611 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004612 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004613 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004614 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004615 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4616 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004617 target_fl64->l_type =
4618 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004619 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004620 target_fl64->l_start = tswap64(fl64.l_start);
4621 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004622 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004623 unlock_user_struct(target_fl64, arg, 1);
4624 }
bellard9ee1fa22007-11-11 15:11:19 +00004625 break;
bellard7775e9e2003-05-14 22:46:48 +00004626 case TARGET_F_SETLK64:
4627 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004628 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4629 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004630 fl64.l_type =
4631 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004632 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004633 fl64.l_start = tswap64(target_fl64->l_start);
4634 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004635 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004636 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004637 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004638 break;
4639
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004640 case TARGET_F_GETFL:
4641 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004642 if (ret >= 0) {
4643 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4644 }
bellardffa65c32004-01-04 23:57:22 +00004645 break;
4646
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004647 case TARGET_F_SETFL:
4648 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4649 break;
4650
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004651#ifdef F_GETOWN_EX
4652 case TARGET_F_GETOWN_EX:
4653 ret = get_errno(fcntl(fd, host_cmd, &fox));
4654 if (ret >= 0) {
4655 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4656 return -TARGET_EFAULT;
4657 target_fox->type = tswap32(fox.type);
4658 target_fox->pid = tswap32(fox.pid);
4659 unlock_user_struct(target_fox, arg, 1);
4660 }
4661 break;
4662#endif
4663
4664#ifdef F_SETOWN_EX
4665 case TARGET_F_SETOWN_EX:
4666 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4667 return -TARGET_EFAULT;
4668 fox.type = tswap32(target_fox->type);
4669 fox.pid = tswap32(target_fox->pid);
4670 unlock_user_struct(target_fox, arg, 0);
4671 ret = get_errno(fcntl(fd, host_cmd, &fox));
4672 break;
4673#endif
4674
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004675 case TARGET_F_SETOWN:
4676 case TARGET_F_GETOWN:
4677 case TARGET_F_SETSIG:
4678 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004679 case TARGET_F_SETLEASE:
4680 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004681 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004682 break;
4683
bellard7775e9e2003-05-14 22:46:48 +00004684 default:
bellard9ee1fa22007-11-11 15:11:19 +00004685 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004686 break;
4687 }
4688 return ret;
4689}
4690
bellard67867302003-11-23 17:05:30 +00004691#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004692
bellard67867302003-11-23 17:05:30 +00004693static inline int high2lowuid(int uid)
4694{
4695 if (uid > 65535)
4696 return 65534;
4697 else
4698 return uid;
4699}
4700
4701static inline int high2lowgid(int gid)
4702{
4703 if (gid > 65535)
4704 return 65534;
4705 else
4706 return gid;
4707}
4708
4709static inline int low2highuid(int uid)
4710{
4711 if ((int16_t)uid == -1)
4712 return -1;
4713 else
4714 return uid;
4715}
4716
4717static inline int low2highgid(int gid)
4718{
4719 if ((int16_t)gid == -1)
4720 return -1;
4721 else
4722 return gid;
4723}
Riku Voipio0c866a72011-04-18 15:23:06 +03004724static inline int tswapid(int id)
4725{
4726 return tswap16(id);
4727}
Peter Maydell76ca3102014-03-02 19:36:41 +00004728
4729#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4730
Riku Voipio0c866a72011-04-18 15:23:06 +03004731#else /* !USE_UID16 */
4732static inline int high2lowuid(int uid)
4733{
4734 return uid;
4735}
4736static inline int high2lowgid(int gid)
4737{
4738 return gid;
4739}
4740static inline int low2highuid(int uid)
4741{
4742 return uid;
4743}
4744static inline int low2highgid(int gid)
4745{
4746 return gid;
4747}
4748static inline int tswapid(int id)
4749{
4750 return tswap32(id);
4751}
Peter Maydell76ca3102014-03-02 19:36:41 +00004752
4753#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4754
bellard67867302003-11-23 17:05:30 +00004755#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004756
bellard31e31b82003-02-18 22:55:36 +00004757void syscall_init(void)
4758{
bellard2ab83ea2003-06-15 19:56:46 +00004759 IOCTLEntry *ie;
4760 const argtype *arg_type;
4761 int size;
thsb92c47c2007-11-01 00:07:38 +00004762 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004763
Blue Swirl001faf32009-05-13 17:53:17 +00004764#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004765#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004766#include "syscall_types.h"
4767#undef STRUCT
4768#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004769
Peter Maydelldd6e9572012-07-23 08:07:22 +00004770 /* Build target_to_host_errno_table[] table from
4771 * host_to_target_errno_table[]. */
4772 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4773 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4774 }
4775
bellard2ab83ea2003-06-15 19:56:46 +00004776 /* we patch the ioctl size if necessary. We rely on the fact that
4777 no ioctl has all the bits at '1' in the size field */
4778 ie = ioctl_entries;
4779 while (ie->target_cmd != 0) {
4780 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4781 TARGET_IOC_SIZEMASK) {
4782 arg_type = ie->arg_type;
4783 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004784 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004785 ie->target_cmd);
4786 exit(1);
4787 }
4788 arg_type++;
4789 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004790 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004791 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4792 (size << TARGET_IOC_SIZESHIFT);
4793 }
thsb92c47c2007-11-01 00:07:38 +00004794
bellard2ab83ea2003-06-15 19:56:46 +00004795 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004796#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4797 (defined(__x86_64__) && defined(TARGET_X86_64))
4798 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4799 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4800 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004801 }
4802#endif
4803 ie++;
4804 }
bellard31e31b82003-02-18 22:55:36 +00004805}
bellardc573ff62004-01-04 15:51:36 +00004806
blueswir1992f48a2007-10-14 16:27:31 +00004807#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004808static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4809{
thsaf325d32008-06-10 15:29:15 +00004810#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004811 return ((uint64_t)word0 << 32) | word1;
4812#else
4813 return ((uint64_t)word1 << 32) | word0;
4814#endif
4815}
blueswir1992f48a2007-10-14 16:27:31 +00004816#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004817static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4818{
4819 return word0;
4820}
blueswir1992f48a2007-10-14 16:27:31 +00004821#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004822
4823#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004824static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4825 abi_long arg2,
4826 abi_long arg3,
4827 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004828{
Riku Voipio48e515d2011-07-12 15:40:51 +03004829 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004830 arg2 = arg3;
4831 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004832 }
pbrookce4defa2006-02-09 16:49:55 +00004833 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4834}
4835#endif
4836
4837#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004838static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4839 abi_long arg2,
4840 abi_long arg3,
4841 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004842{
Riku Voipio48e515d2011-07-12 15:40:51 +03004843 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004844 arg2 = arg3;
4845 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004846 }
pbrookce4defa2006-02-09 16:49:55 +00004847 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4848}
4849#endif
4850
bellard579a97f2007-11-11 14:26:47 +00004851static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4852 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004853{
4854 struct target_timespec *target_ts;
4855
bellard579a97f2007-11-11 14:26:47 +00004856 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4857 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004858 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4859 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004860 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004861 return 0;
pbrook53a59602006-03-25 19:31:22 +00004862}
4863
bellard579a97f2007-11-11 14:26:47 +00004864static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4865 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004866{
4867 struct target_timespec *target_ts;
4868
bellard579a97f2007-11-11 14:26:47 +00004869 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4870 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004871 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4872 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004873 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004874 return 0;
pbrook53a59602006-03-25 19:31:22 +00004875}
4876
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004877static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4878 abi_ulong target_addr)
4879{
4880 struct target_itimerspec *target_itspec;
4881
4882 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4883 return -TARGET_EFAULT;
4884 }
4885
4886 host_itspec->it_interval.tv_sec =
4887 tswapal(target_itspec->it_interval.tv_sec);
4888 host_itspec->it_interval.tv_nsec =
4889 tswapal(target_itspec->it_interval.tv_nsec);
4890 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4891 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4892
4893 unlock_user_struct(target_itspec, target_addr, 1);
4894 return 0;
4895}
4896
4897static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4898 struct itimerspec *host_its)
4899{
4900 struct target_itimerspec *target_itspec;
4901
4902 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4903 return -TARGET_EFAULT;
4904 }
4905
4906 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4907 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4908
4909 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4910 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4911
4912 unlock_user_struct(target_itspec, target_addr, 0);
4913 return 0;
4914}
4915
Peter Maydellc0659762014-08-09 15:42:32 +01004916static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
4917 abi_ulong target_addr)
4918{
4919 struct target_sigevent *target_sevp;
4920
4921 if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
4922 return -TARGET_EFAULT;
4923 }
4924
4925 /* This union is awkward on 64 bit systems because it has a 32 bit
4926 * integer and a pointer in it; we follow the conversion approach
4927 * used for handling sigval types in signal.c so the guest should get
4928 * the correct value back even if we did a 64 bit byteswap and it's
4929 * using the 32 bit integer.
4930 */
4931 host_sevp->sigev_value.sival_ptr =
4932 (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
4933 host_sevp->sigev_signo =
4934 target_to_host_signal(tswap32(target_sevp->sigev_signo));
4935 host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
4936 host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid);
4937
4938 unlock_user_struct(target_sevp, target_addr, 1);
4939 return 0;
4940}
4941
aurel329d33b762009-04-08 23:07:05 +00004942#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004943static inline abi_long host_to_target_stat64(void *cpu_env,
4944 abi_ulong target_addr,
4945 struct stat *host_st)
4946{
Alexander Graf09701192013-09-03 20:12:15 +01004947#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004948 if (((CPUARMState *)cpu_env)->eabi) {
4949 struct target_eabi_stat64 *target_st;
4950
4951 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4952 return -TARGET_EFAULT;
4953 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4954 __put_user(host_st->st_dev, &target_st->st_dev);
4955 __put_user(host_st->st_ino, &target_st->st_ino);
4956#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4957 __put_user(host_st->st_ino, &target_st->__st_ino);
4958#endif
4959 __put_user(host_st->st_mode, &target_st->st_mode);
4960 __put_user(host_st->st_nlink, &target_st->st_nlink);
4961 __put_user(host_st->st_uid, &target_st->st_uid);
4962 __put_user(host_st->st_gid, &target_st->st_gid);
4963 __put_user(host_st->st_rdev, &target_st->st_rdev);
4964 __put_user(host_st->st_size, &target_st->st_size);
4965 __put_user(host_st->st_blksize, &target_st->st_blksize);
4966 __put_user(host_st->st_blocks, &target_st->st_blocks);
4967 __put_user(host_st->st_atime, &target_st->target_st_atime);
4968 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4969 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4970 unlock_user_struct(target_st, target_addr, 1);
4971 } else
4972#endif
4973 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004974#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004975 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004976#else
4977 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004978#endif
balrog6a24a772008-09-20 02:23:36 +00004979
4980 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4981 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004982 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004983 __put_user(host_st->st_dev, &target_st->st_dev);
4984 __put_user(host_st->st_ino, &target_st->st_ino);
4985#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4986 __put_user(host_st->st_ino, &target_st->__st_ino);
4987#endif
4988 __put_user(host_st->st_mode, &target_st->st_mode);
4989 __put_user(host_st->st_nlink, &target_st->st_nlink);
4990 __put_user(host_st->st_uid, &target_st->st_uid);
4991 __put_user(host_st->st_gid, &target_st->st_gid);
4992 __put_user(host_st->st_rdev, &target_st->st_rdev);
4993 /* XXX: better use of kernel struct */
4994 __put_user(host_st->st_size, &target_st->st_size);
4995 __put_user(host_st->st_blksize, &target_st->st_blksize);
4996 __put_user(host_st->st_blocks, &target_st->st_blocks);
4997 __put_user(host_st->st_atime, &target_st->target_st_atime);
4998 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4999 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
5000 unlock_user_struct(target_st, target_addr, 1);
5001 }
5002
5003 return 0;
5004}
5005#endif
5006
pbrookbd0c5662008-05-29 14:34:11 +00005007/* ??? Using host futex calls even when target atomic operations
5008 are not really atomic probably breaks things. However implementing
5009 futexes locally would make futexes shared between multiple processes
5010 tricky. However they're probably useless because guest atomic
5011 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00005012static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
5013 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00005014{
5015 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07005016 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00005017
5018 /* ??? We assume FUTEX_* constants are the same on both host
5019 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03005020#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07005021 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005022#else
Nathan Froyda16aae02009-08-03 08:43:29 -07005023 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03005024#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07005025 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00005026 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07005027 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00005028 if (timeout) {
5029 pts = &ts;
5030 target_to_host_timespec(pts, timeout);
5031 } else {
5032 pts = NULL;
5033 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03005034 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07005035 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00005036 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005037 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005038 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03005039 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00005040 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00005041 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07005042 case FUTEX_WAKE_OP:
5043 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
5044 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
5045 But the prototype takes a `struct timespec *'; insert casts
5046 to satisfy the compiler. We do not need to tswap TIMEOUT
5047 since it's not compared to guest memory. */
5048 pts = (struct timespec *)(uintptr_t) timeout;
5049 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
5050 g2h(uaddr2),
5051 (base_op == FUTEX_CMP_REQUEUE
5052 ? tswap32(val3)
5053 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00005054 default:
5055 return -TARGET_ENOSYS;
5056 }
5057}
pbrookbd0c5662008-05-29 14:34:11 +00005058
pbrook1d9d8b52009-04-16 15:17:02 +00005059/* Map host to target signal numbers for the wait family of syscalls.
5060 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07005061int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00005062{
5063 if (WIFSIGNALED(status)) {
5064 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
5065 }
5066 if (WIFSTOPPED(status)) {
5067 return (host_to_target_signal(WSTOPSIG(status)) << 8)
5068 | (status & 0xff);
5069 }
5070 return status;
5071}
5072
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005073static int open_self_cmdline(void *cpu_env, int fd)
5074{
5075 int fd_orig = -1;
5076 bool word_skipped = false;
5077
5078 fd_orig = open("/proc/self/cmdline", O_RDONLY);
5079 if (fd_orig < 0) {
5080 return fd_orig;
5081 }
5082
5083 while (true) {
5084 ssize_t nb_read;
5085 char buf[128];
5086 char *cp_buf = buf;
5087
5088 nb_read = read(fd_orig, buf, sizeof(buf));
5089 if (nb_read < 0) {
5090 fd_orig = close(fd_orig);
5091 return -1;
5092 } else if (nb_read == 0) {
5093 break;
5094 }
5095
5096 if (!word_skipped) {
5097 /* Skip the first string, which is the path to qemu-*-static
5098 instead of the actual command. */
5099 cp_buf = memchr(buf, 0, sizeof(buf));
5100 if (cp_buf) {
5101 /* Null byte found, skip one string */
5102 cp_buf++;
5103 nb_read -= cp_buf - buf;
5104 word_skipped = true;
5105 }
5106 }
5107
5108 if (word_skipped) {
5109 if (write(fd, cp_buf, nb_read) != nb_read) {
5110 return -1;
5111 }
5112 }
5113 }
5114
5115 return close(fd_orig);
5116}
5117
Alexander Graf36c08d42011-11-02 20:23:24 +01005118static int open_self_maps(void *cpu_env, int fd)
5119{
Andreas Färber0429a972013-08-26 18:14:44 +02005120 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5121 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005122 FILE *fp;
5123 char *line = NULL;
5124 size_t len = 0;
5125 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005126
Alexander Graf1a49ef22012-05-01 16:30:28 +01005127 fp = fopen("/proc/self/maps", "r");
5128 if (fp == NULL) {
5129 return -EACCES;
5130 }
5131
5132 while ((read = getline(&line, &len, fp)) != -1) {
5133 int fields, dev_maj, dev_min, inode;
5134 uint64_t min, max, offset;
5135 char flag_r, flag_w, flag_x, flag_p;
5136 char path[512] = "";
5137 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5138 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5139 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5140
5141 if ((fields < 10) || (fields > 11)) {
5142 continue;
5143 }
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005144 if (h2g_valid(min)) {
5145 int flags = page_get_flags(h2g(min));
5146 max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
5147 if (page_check_range(h2g(min), max - min, flags) == -1) {
5148 continue;
5149 }
5150 if (h2g(min) == ts->info->stack_limit) {
5151 pstrcpy(path, sizeof(path), " [stack]");
5152 }
Alexander Graf1a49ef22012-05-01 16:30:28 +01005153 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005154 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Mikhail Ilyind67f4aa2014-08-05 17:33:51 +04005155 h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005156 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005157 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005158 }
5159 }
5160
5161 free(line);
5162 fclose(fp);
5163
Alexander Graf36c08d42011-11-02 20:23:24 +01005164 return 0;
5165}
5166
Alexander Graf480b8e72011-11-02 20:23:25 +01005167static int open_self_stat(void *cpu_env, int fd)
5168{
Andreas Färber0429a972013-08-26 18:14:44 +02005169 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5170 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005171 abi_ulong start_stack = ts->info->start_stack;
5172 int i;
5173
5174 for (i = 0; i < 44; i++) {
5175 char buf[128];
5176 int len;
5177 uint64_t val = 0;
5178
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005179 if (i == 0) {
5180 /* pid */
5181 val = getpid();
5182 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5183 } else if (i == 1) {
5184 /* app name */
5185 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5186 } else if (i == 27) {
5187 /* stack bottom */
5188 val = start_stack;
5189 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5190 } else {
5191 /* for the rest, there is MasterCard */
5192 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005193 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005194
Alexander Graf480b8e72011-11-02 20:23:25 +01005195 len = strlen(buf);
5196 if (write(fd, buf, len) != len) {
5197 return -1;
5198 }
5199 }
5200
5201 return 0;
5202}
5203
Alexander Graf257450e2011-11-02 20:23:26 +01005204static int open_self_auxv(void *cpu_env, int fd)
5205{
Andreas Färber0429a972013-08-26 18:14:44 +02005206 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5207 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005208 abi_ulong auxv = ts->info->saved_auxv;
5209 abi_ulong len = ts->info->auxv_len;
5210 char *ptr;
5211
5212 /*
5213 * Auxiliary vector is stored in target process stack.
5214 * read in whole auxv vector and copy it to file
5215 */
5216 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5217 if (ptr != NULL) {
5218 while (len > 0) {
5219 ssize_t r;
5220 r = write(fd, ptr, len);
5221 if (r <= 0) {
5222 break;
5223 }
5224 len -= r;
5225 ptr += r;
5226 }
5227 lseek(fd, 0, SEEK_SET);
5228 unlock_user(ptr, auxv, len);
5229 }
5230
5231 return 0;
5232}
5233
Andreas Schwab463d8e72013-07-02 14:04:12 +01005234static int is_proc_myself(const char *filename, const char *entry)
5235{
5236 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5237 filename += strlen("/proc/");
5238 if (!strncmp(filename, "self/", strlen("self/"))) {
5239 filename += strlen("self/");
5240 } else if (*filename >= '1' && *filename <= '9') {
5241 char myself[80];
5242 snprintf(myself, sizeof(myself), "%d/", getpid());
5243 if (!strncmp(filename, myself, strlen(myself))) {
5244 filename += strlen(myself);
5245 } else {
5246 return 0;
5247 }
5248 } else {
5249 return 0;
5250 }
5251 if (!strcmp(filename, entry)) {
5252 return 1;
5253 }
5254 }
5255 return 0;
5256}
5257
Laurent Vivierde6b9932013-08-30 01:46:40 +02005258#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5259static int is_proc(const char *filename, const char *entry)
5260{
5261 return strcmp(filename, entry) == 0;
5262}
5263
5264static int open_net_route(void *cpu_env, int fd)
5265{
5266 FILE *fp;
5267 char *line = NULL;
5268 size_t len = 0;
5269 ssize_t read;
5270
5271 fp = fopen("/proc/net/route", "r");
5272 if (fp == NULL) {
5273 return -EACCES;
5274 }
5275
5276 /* read header */
5277
5278 read = getline(&line, &len, fp);
5279 dprintf(fd, "%s", line);
5280
5281 /* read routes */
5282
5283 while ((read = getline(&line, &len, fp)) != -1) {
5284 char iface[16];
5285 uint32_t dest, gw, mask;
5286 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5287 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5288 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5289 &mask, &mtu, &window, &irtt);
5290 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5291 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5292 metric, tswap32(mask), mtu, window, irtt);
5293 }
5294
5295 free(line);
5296 fclose(fp);
5297
5298 return 0;
5299}
5300#endif
5301
Riku Voipio0b2effd2014-08-06 10:36:37 +03005302static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
Alexander Graf3be14d02011-11-02 20:23:23 +01005303{
5304 struct fake_open {
5305 const char *filename;
5306 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005307 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005308 };
5309 const struct fake_open *fake_open;
5310 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005311 { "maps", open_self_maps, is_proc_myself },
5312 { "stat", open_self_stat, is_proc_myself },
5313 { "auxv", open_self_auxv, is_proc_myself },
Wim Vander Schelden76b94242014-06-18 11:02:39 +02005314 { "cmdline", open_self_cmdline, is_proc_myself },
Laurent Vivierde6b9932013-08-30 01:46:40 +02005315#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5316 { "/proc/net/route", open_net_route, is_proc },
5317#endif
5318 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005319 };
5320
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005321 if (is_proc_myself(pathname, "exe")) {
5322 int execfd = qemu_getauxval(AT_EXECFD);
Riku Voipio0b2effd2014-08-06 10:36:37 +03005323 return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode));
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005324 }
5325
Alexander Graf3be14d02011-11-02 20:23:23 +01005326 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005327 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005328 break;
5329 }
5330 }
5331
5332 if (fake_open->filename) {
5333 const char *tmpdir;
5334 char filename[PATH_MAX];
5335 int fd, r;
5336
5337 /* create temporary file to map stat to */
5338 tmpdir = getenv("TMPDIR");
5339 if (!tmpdir)
5340 tmpdir = "/tmp";
5341 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5342 fd = mkstemp(filename);
5343 if (fd < 0) {
5344 return fd;
5345 }
5346 unlink(filename);
5347
5348 if ((r = fake_open->fill(cpu_env, fd))) {
5349 close(fd);
5350 return r;
5351 }
5352 lseek(fd, 0, SEEK_SET);
5353
5354 return fd;
5355 }
5356
Riku Voipio0b2effd2014-08-06 10:36:37 +03005357 return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
Alexander Graf3be14d02011-11-02 20:23:23 +01005358}
5359
ths0da46a62007-10-20 20:23:07 +00005360/* do_syscall() should always have a single exit point at the end so
5361 that actions, such as logging of syscall results, can be performed.
5362 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005363abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5364 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005365 abi_long arg5, abi_long arg6, abi_long arg7,
5366 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005367{
Andreas Färber182735e2013-05-29 22:29:20 +02005368 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005369 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005370 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005371 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005372 void *p;
ths3b46e622007-09-17 08:09:54 +00005373
bellard72f03902003-02-18 23:33:18 +00005374#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005375 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005376#endif
thsb92c47c2007-11-01 00:07:38 +00005377 if(do_strace)
5378 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5379
bellard31e31b82003-02-18 22:55:36 +00005380 switch(num) {
5381 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005382 /* In old applications this may be used to implement _exit(2).
5383 However in threaded applictions it is used for thread termination,
5384 and _exit_group is used for application termination.
5385 Do thread termination if we have more then one thread. */
5386 /* FIXME: This probably breaks if a signal arrives. We should probably
5387 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005388 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005389 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005390
Andreas Färber9b056fc2013-06-24 23:53:10 +02005391 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005392 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005393 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005394 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005395 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005396 if (ts->child_tidptr) {
5397 put_user_u32(0, ts->child_tidptr);
5398 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5399 NULL, NULL, 0);
5400 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005401 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005402 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005403 g_free(ts);
5404 pthread_exit(NULL);
5405 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005406#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005407 _mcleanup();
5408#endif
bellarde9009672005-04-26 20:42:36 +00005409 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005410 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005411 ret = 0; /* avoid warning */
5412 break;
5413 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005414 if (arg3 == 0)
5415 ret = 0;
5416 else {
5417 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5418 goto efault;
5419 ret = get_errno(read(arg1, p, arg3));
5420 unlock_user(p, arg2, ret);
5421 }
bellard31e31b82003-02-18 22:55:36 +00005422 break;
5423 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005424 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5425 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005426 ret = get_errno(write(arg1, p, arg3));
5427 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005428 break;
5429 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005430 if (!(p = lock_user_string(arg1)))
5431 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005432 ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
5433 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5434 arg3));
pbrook53a59602006-03-25 19:31:22 +00005435 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005436 break;
ths82424832007-09-24 09:21:55 +00005437 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005438 if (!(p = lock_user_string(arg2)))
5439 goto efault;
Riku Voipio0b2effd2014-08-06 10:36:37 +03005440 ret = get_errno(do_openat(cpu_env, arg1, p,
5441 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5442 arg4));
bellard579a97f2007-11-11 14:26:47 +00005443 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005444 break;
bellard31e31b82003-02-18 22:55:36 +00005445 case TARGET_NR_close:
5446 ret = get_errno(close(arg1));
5447 break;
5448 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005449 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005450 break;
5451 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005452 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005453 break;
thse5febef2007-04-01 18:31:35 +00005454#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005455 case TARGET_NR_waitpid:
5456 {
pbrook53a59602006-03-25 19:31:22 +00005457 int status;
5458 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005459 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005460 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005461 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005462 }
5463 break;
thse5febef2007-04-01 18:31:35 +00005464#endif
pbrookf0cbb612008-05-30 18:20:05 +00005465#ifdef TARGET_NR_waitid
5466 case TARGET_NR_waitid:
5467 {
5468 siginfo_t info;
5469 info.si_pid = 0;
5470 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5471 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005472 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005473 goto efault;
5474 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005475 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005476 }
5477 }
5478 break;
5479#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005480#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005481 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005482 if (!(p = lock_user_string(arg1)))
5483 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005484 ret = get_errno(creat(p, arg2));
5485 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005486 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005487#endif
bellard31e31b82003-02-18 22:55:36 +00005488 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005489 {
5490 void * p2;
5491 p = lock_user_string(arg1);
5492 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005493 if (!p || !p2)
5494 ret = -TARGET_EFAULT;
5495 else
5496 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005497 unlock_user(p2, arg2, 0);
5498 unlock_user(p, arg1, 0);
5499 }
bellard31e31b82003-02-18 22:55:36 +00005500 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005501#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005502 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005503 {
5504 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005505 if (!arg2 || !arg4)
5506 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005507 p = lock_user_string(arg2);
5508 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005509 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005510 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005511 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005512 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005513 unlock_user(p, arg2, 0);
5514 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005515 }
5516 break;
5517#endif
bellard31e31b82003-02-18 22:55:36 +00005518 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005519 if (!(p = lock_user_string(arg1)))
5520 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005521 ret = get_errno(unlink(p));
5522 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005523 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005524#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005525 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005526 if (!(p = lock_user_string(arg2)))
5527 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005528 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005529 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005530 break;
balrogb7d35e62007-12-12 00:40:24 +00005531#endif
bellard31e31b82003-02-18 22:55:36 +00005532 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005533 {
5534 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005535 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005536 abi_ulong gp;
5537 abi_ulong guest_argp;
5538 abi_ulong guest_envp;
5539 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005540 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005541 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005542
bellardf7341ff2003-03-30 21:00:25 +00005543 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005544 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005545 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005546 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005547 goto efault;
ths03aa1972007-12-02 06:28:08 +00005548 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005549 break;
bellard7854b052003-03-29 17:22:23 +00005550 argc++;
bellard2f619692007-11-16 10:46:05 +00005551 }
bellardf7341ff2003-03-30 21:00:25 +00005552 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005553 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005554 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005555 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005556 goto efault;
ths03aa1972007-12-02 06:28:08 +00005557 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005558 break;
bellard7854b052003-03-29 17:22:23 +00005559 envc++;
bellard2f619692007-11-16 10:46:05 +00005560 }
bellard7854b052003-03-29 17:22:23 +00005561
bellardf7341ff2003-03-30 21:00:25 +00005562 argp = alloca((argc + 1) * sizeof(void *));
5563 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005564
pbrookda94d262008-05-30 18:24:00 +00005565 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005566 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005567 if (get_user_ual(addr, gp))
5568 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005569 if (!addr)
5570 break;
bellard2f619692007-11-16 10:46:05 +00005571 if (!(*q = lock_user_string(addr)))
5572 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005573 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005574 }
bellardf7341ff2003-03-30 21:00:25 +00005575 *q = NULL;
5576
pbrookda94d262008-05-30 18:24:00 +00005577 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005578 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005579 if (get_user_ual(addr, gp))
5580 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005581 if (!addr)
5582 break;
bellard2f619692007-11-16 10:46:05 +00005583 if (!(*q = lock_user_string(addr)))
5584 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005585 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005586 }
bellardf7341ff2003-03-30 21:00:25 +00005587 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005588
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005589 /* This case will not be caught by the host's execve() if its
5590 page size is bigger than the target's. */
5591 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5592 ret = -TARGET_E2BIG;
5593 goto execve_end;
5594 }
bellard2f619692007-11-16 10:46:05 +00005595 if (!(p = lock_user_string(arg1)))
5596 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005597 ret = get_errno(execve(p, argp, envp));
5598 unlock_user(p, arg1, 0);
5599
bellard2f619692007-11-16 10:46:05 +00005600 goto execve_end;
5601
5602 execve_efault:
5603 ret = -TARGET_EFAULT;
5604
5605 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005606 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005607 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005608 if (get_user_ual(addr, gp)
5609 || !addr)
5610 break;
pbrook53a59602006-03-25 19:31:22 +00005611 unlock_user(*q, addr, 0);
5612 }
5613 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005614 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005615 if (get_user_ual(addr, gp)
5616 || !addr)
5617 break;
pbrook53a59602006-03-25 19:31:22 +00005618 unlock_user(*q, addr, 0);
5619 }
bellard7854b052003-03-29 17:22:23 +00005620 }
bellard31e31b82003-02-18 22:55:36 +00005621 break;
5622 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005623 if (!(p = lock_user_string(arg1)))
5624 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005625 ret = get_errno(chdir(p));
5626 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005627 break;
bellarda315a142005-01-30 22:59:18 +00005628#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005629 case TARGET_NR_time:
5630 {
pbrook53a59602006-03-25 19:31:22 +00005631 time_t host_time;
5632 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005633 if (!is_error(ret)
5634 && arg1
5635 && put_user_sal(host_time, arg1))
5636 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005637 }
5638 break;
bellarda315a142005-01-30 22:59:18 +00005639#endif
bellard31e31b82003-02-18 22:55:36 +00005640 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005641 if (!(p = lock_user_string(arg1)))
5642 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005643 ret = get_errno(mknod(p, arg2, arg3));
5644 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005645 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005646#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005647 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005648 if (!(p = lock_user_string(arg2)))
5649 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005650 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005651 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005652 break;
5653#endif
bellard31e31b82003-02-18 22:55:36 +00005654 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005655 if (!(p = lock_user_string(arg1)))
5656 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005657 ret = get_errno(chmod(p, arg2));
5658 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005659 break;
bellardebc05482003-09-30 21:08:41 +00005660#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005661 case TARGET_NR_break:
5662 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005663#endif
5664#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005665 case TARGET_NR_oldstat:
5666 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005667#endif
bellard31e31b82003-02-18 22:55:36 +00005668 case TARGET_NR_lseek:
5669 ret = get_errno(lseek(arg1, arg2, arg3));
5670 break;
Richard Henderson92317332010-05-03 10:07:53 -07005671#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5672 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005673 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005674 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005675 ret = get_errno(getpid());
5676 break;
Richard Henderson92317332010-05-03 10:07:53 -07005677#endif
5678#ifdef TARGET_NR_getpid
5679 case TARGET_NR_getpid:
5680 ret = get_errno(getpid());
5681 break;
5682#endif
bellard31e31b82003-02-18 22:55:36 +00005683 case TARGET_NR_mount:
Paul Burton356d7712014-06-22 11:25:37 +01005684 {
5685 /* need to look at the data field */
5686 void *p2, *p3;
5687
5688 if (arg1) {
5689 p = lock_user_string(arg1);
5690 if (!p) {
5691 goto efault;
5692 }
5693 } else {
5694 p = NULL;
5695 }
5696
5697 p2 = lock_user_string(arg2);
5698 if (!p2) {
5699 if (arg1) {
5700 unlock_user(p, arg1, 0);
5701 }
5702 goto efault;
5703 }
5704
5705 if (arg3) {
5706 p3 = lock_user_string(arg3);
5707 if (!p3) {
5708 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005709 unlock_user(p, arg1, 0);
Paul Burton356d7712014-06-22 11:25:37 +01005710 }
5711 unlock_user(p2, arg2, 0);
5712 goto efault;
5713 }
5714 } else {
5715 p3 = NULL;
5716 }
5717
5718 /* FIXME - arg5 should be locked, but it isn't clear how to
5719 * do that since it's not guaranteed to be a NULL-terminated
5720 * string.
5721 */
5722 if (!arg5) {
5723 ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
5724 } else {
5725 ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
5726 }
5727 ret = get_errno(ret);
5728
5729 if (arg1) {
5730 unlock_user(p, arg1, 0);
5731 }
5732 unlock_user(p2, arg2, 0);
5733 if (arg3) {
5734 unlock_user(p3, arg3, 0);
5735 }
5736 }
5737 break;
thse5febef2007-04-01 18:31:35 +00005738#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005739 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005740 if (!(p = lock_user_string(arg1)))
5741 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005742 ret = get_errno(umount(p));
5743 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005744 break;
thse5febef2007-04-01 18:31:35 +00005745#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005746#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005747 case TARGET_NR_stime:
5748 {
pbrook53a59602006-03-25 19:31:22 +00005749 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005750 if (get_user_sal(host_time, arg1))
5751 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005752 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005753 }
5754 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005755#endif
bellard31e31b82003-02-18 22:55:36 +00005756 case TARGET_NR_ptrace:
5757 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005758#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005759 case TARGET_NR_alarm:
5760 ret = alarm(arg1);
5761 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005762#endif
bellardebc05482003-09-30 21:08:41 +00005763#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005764 case TARGET_NR_oldfstat:
5765 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005766#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005767#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005768 case TARGET_NR_pause:
5769 ret = get_errno(pause());
5770 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005771#endif
thse5febef2007-04-01 18:31:35 +00005772#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005773 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005774 {
pbrook53a59602006-03-25 19:31:22 +00005775 struct utimbuf tbuf, *host_tbuf;
5776 struct target_utimbuf *target_tbuf;
5777 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005778 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5779 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005780 tbuf.actime = tswapal(target_tbuf->actime);
5781 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005782 unlock_user_struct(target_tbuf, arg2, 0);
5783 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005784 } else {
pbrook53a59602006-03-25 19:31:22 +00005785 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005786 }
bellard579a97f2007-11-11 14:26:47 +00005787 if (!(p = lock_user_string(arg1)))
5788 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005789 ret = get_errno(utime(p, host_tbuf));
5790 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005791 }
5792 break;
thse5febef2007-04-01 18:31:35 +00005793#endif
bellard978a66f2004-12-06 22:58:05 +00005794 case TARGET_NR_utimes:
5795 {
bellard978a66f2004-12-06 22:58:05 +00005796 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005797 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005798 if (copy_from_user_timeval(&tv[0], arg2)
5799 || copy_from_user_timeval(&tv[1],
5800 arg2 + sizeof(struct target_timeval)))
5801 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005802 tvp = tv;
5803 } else {
5804 tvp = NULL;
5805 }
bellard579a97f2007-11-11 14:26:47 +00005806 if (!(p = lock_user_string(arg1)))
5807 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005808 ret = get_errno(utimes(p, tvp));
5809 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005810 }
5811 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005812#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005813 case TARGET_NR_futimesat:
5814 {
5815 struct timeval *tvp, tv[2];
5816 if (arg3) {
5817 if (copy_from_user_timeval(&tv[0], arg3)
5818 || copy_from_user_timeval(&tv[1],
5819 arg3 + sizeof(struct target_timeval)))
5820 goto efault;
5821 tvp = tv;
5822 } else {
5823 tvp = NULL;
5824 }
5825 if (!(p = lock_user_string(arg2)))
5826 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005827 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005828 unlock_user(p, arg2, 0);
5829 }
5830 break;
5831#endif
bellardebc05482003-09-30 21:08:41 +00005832#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005833 case TARGET_NR_stty:
5834 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005835#endif
5836#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005837 case TARGET_NR_gtty:
5838 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005839#endif
bellard31e31b82003-02-18 22:55:36 +00005840 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005841 if (!(p = lock_user_string(arg1)))
5842 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005843 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005844 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005845 break;
ths92a34c12007-09-24 09:27:49 +00005846#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5847 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005848 if (!(p = lock_user_string(arg2)))
5849 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005850 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005851 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005852 break;
5853#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005854#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005855 case TARGET_NR_nice:
5856 ret = get_errno(nice(arg1));
5857 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005858#endif
bellardebc05482003-09-30 21:08:41 +00005859#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005860 case TARGET_NR_ftime:
5861 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005862#endif
bellard31e31b82003-02-18 22:55:36 +00005863 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005864 sync();
5865 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005866 break;
5867 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005868 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005869 break;
5870 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005871 {
5872 void *p2;
5873 p = lock_user_string(arg1);
5874 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005875 if (!p || !p2)
5876 ret = -TARGET_EFAULT;
5877 else
5878 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005879 unlock_user(p2, arg2, 0);
5880 unlock_user(p, arg1, 0);
5881 }
bellard31e31b82003-02-18 22:55:36 +00005882 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005883#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005884 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005885 {
bellard579a97f2007-11-11 14:26:47 +00005886 void *p2;
ths722183f2007-09-24 09:24:37 +00005887 p = lock_user_string(arg2);
5888 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005889 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005890 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005891 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005892 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005893 unlock_user(p2, arg4, 0);
5894 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005895 }
5896 break;
5897#endif
bellard31e31b82003-02-18 22:55:36 +00005898 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005899 if (!(p = lock_user_string(arg1)))
5900 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005901 ret = get_errno(mkdir(p, arg2));
5902 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005903 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005904#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005905 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005906 if (!(p = lock_user_string(arg2)))
5907 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005908 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005909 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005910 break;
5911#endif
bellard31e31b82003-02-18 22:55:36 +00005912 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005913 if (!(p = lock_user_string(arg1)))
5914 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005915 ret = get_errno(rmdir(p));
5916 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005917 break;
5918 case TARGET_NR_dup:
5919 ret = get_errno(dup(arg1));
5920 break;
5921 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005922 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005923 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005924#ifdef TARGET_NR_pipe2
5925 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005926 ret = do_pipe(cpu_env, arg1,
5927 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005928 break;
5929#endif
bellard31e31b82003-02-18 22:55:36 +00005930 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005931 {
pbrook53a59602006-03-25 19:31:22 +00005932 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005933 struct tms tms;
5934 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005935 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005936 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5937 if (!tmsp)
5938 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005939 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5940 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5941 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5942 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005943 }
bellardc596ed12003-07-13 17:32:31 +00005944 if (!is_error(ret))
5945 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005946 }
5947 break;
bellardebc05482003-09-30 21:08:41 +00005948#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005949 case TARGET_NR_prof:
5950 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005951#endif
thse5febef2007-04-01 18:31:35 +00005952#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005953 case TARGET_NR_signal:
5954 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005955#endif
bellard31e31b82003-02-18 22:55:36 +00005956 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005957 if (arg1 == 0) {
5958 ret = get_errno(acct(NULL));
5959 } else {
5960 if (!(p = lock_user_string(arg1)))
5961 goto efault;
5962 ret = get_errno(acct(path(p)));
5963 unlock_user(p, arg1, 0);
5964 }
pbrook24836682006-04-16 14:14:53 +00005965 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005966#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005967 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005968 if (!(p = lock_user_string(arg1)))
5969 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005970 ret = get_errno(umount2(p, arg2));
5971 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005972 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005973#endif
bellardebc05482003-09-30 21:08:41 +00005974#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005975 case TARGET_NR_lock:
5976 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005977#endif
bellard31e31b82003-02-18 22:55:36 +00005978 case TARGET_NR_ioctl:
5979 ret = do_ioctl(arg1, arg2, arg3);
5980 break;
5981 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005982 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005983 break;
bellardebc05482003-09-30 21:08:41 +00005984#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005985 case TARGET_NR_mpx:
5986 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005987#endif
bellard31e31b82003-02-18 22:55:36 +00005988 case TARGET_NR_setpgid:
5989 ret = get_errno(setpgid(arg1, arg2));
5990 break;
bellardebc05482003-09-30 21:08:41 +00005991#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005992 case TARGET_NR_ulimit:
5993 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005994#endif
5995#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005996 case TARGET_NR_oldolduname:
5997 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005998#endif
bellard31e31b82003-02-18 22:55:36 +00005999 case TARGET_NR_umask:
6000 ret = get_errno(umask(arg1));
6001 break;
6002 case TARGET_NR_chroot:
bellard579a97f2007-11-11 14:26:47 +00006003 if (!(p = lock_user_string(arg1)))
6004 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006005 ret = get_errno(chroot(p));
6006 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006007 break;
6008 case TARGET_NR_ustat:
6009 goto unimplemented;
6010 case TARGET_NR_dup2:
6011 ret = get_errno(dup2(arg1, arg2));
6012 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03006013#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
6014 case TARGET_NR_dup3:
6015 ret = get_errno(dup3(arg1, arg2, arg3));
6016 break;
6017#endif
j_mayer7a3148a2007-04-05 07:13:51 +00006018#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006019 case TARGET_NR_getppid:
6020 ret = get_errno(getppid());
6021 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006022#endif
bellard31e31b82003-02-18 22:55:36 +00006023 case TARGET_NR_getpgrp:
6024 ret = get_errno(getpgrp());
6025 break;
6026 case TARGET_NR_setsid:
6027 ret = get_errno(setsid());
6028 break;
thse5febef2007-04-01 18:31:35 +00006029#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00006030 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00006031 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006032#if defined(TARGET_ALPHA)
6033 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00006034 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00006035 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006036 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6037 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006038 act._sa_handler = old_act->_sa_handler;
6039 target_siginitset(&act.sa_mask, old_act->sa_mask);
6040 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08006041 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00006042 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006043 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00006044 }
6045 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00006046 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006047 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6048 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006049 old_act->_sa_handler = oact._sa_handler;
6050 old_act->sa_mask = oact.sa_mask.sig[0];
6051 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00006052 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00006053 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006054#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00006055 struct target_sigaction act, oact, *pact, *old_act;
6056
6057 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00006058 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6059 goto efault;
bellard106ec872006-06-27 21:08:10 +00006060 act._sa_handler = old_act->_sa_handler;
6061 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
6062 act.sa_flags = old_act->sa_flags;
6063 unlock_user_struct(old_act, arg2, 0);
6064 pact = &act;
6065 } else {
6066 pact = NULL;
6067 }
6068
6069 ret = get_errno(do_sigaction(arg1, pact, &oact));
6070
6071 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00006072 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6073 goto efault;
bellard106ec872006-06-27 21:08:10 +00006074 old_act->_sa_handler = oact._sa_handler;
6075 old_act->sa_flags = oact.sa_flags;
6076 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
6077 old_act->sa_mask.sig[1] = 0;
6078 old_act->sa_mask.sig[2] = 0;
6079 old_act->sa_mask.sig[3] = 0;
6080 unlock_user_struct(old_act, arg3, 1);
6081 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08006082#else
6083 struct target_old_sigaction *old_act;
6084 struct target_sigaction act, oact, *pact;
6085 if (arg2) {
6086 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
6087 goto efault;
6088 act._sa_handler = old_act->_sa_handler;
6089 target_siginitset(&act.sa_mask, old_act->sa_mask);
6090 act.sa_flags = old_act->sa_flags;
6091 act.sa_restorer = old_act->sa_restorer;
6092 unlock_user_struct(old_act, arg2, 0);
6093 pact = &act;
6094 } else {
6095 pact = NULL;
6096 }
6097 ret = get_errno(do_sigaction(arg1, pact, &oact));
6098 if (!is_error(ret) && arg3) {
6099 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6100 goto efault;
6101 old_act->_sa_handler = oact._sa_handler;
6102 old_act->sa_mask = oact.sa_mask.sig[0];
6103 old_act->sa_flags = oact.sa_flags;
6104 old_act->sa_restorer = oact.sa_restorer;
6105 unlock_user_struct(old_act, arg3, 1);
6106 }
ths388bb212007-05-13 13:58:00 +00006107#endif
bellard31e31b82003-02-18 22:55:36 +00006108 }
6109 break;
thse5febef2007-04-01 18:31:35 +00006110#endif
bellard66fb9762003-03-23 01:06:05 +00006111 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006112 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006113#if defined(TARGET_ALPHA)
6114 struct target_sigaction act, oact, *pact = 0;
6115 struct target_rt_sigaction *rt_act;
6116 /* ??? arg4 == sizeof(sigset_t). */
6117 if (arg2) {
6118 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6119 goto efault;
6120 act._sa_handler = rt_act->_sa_handler;
6121 act.sa_mask = rt_act->sa_mask;
6122 act.sa_flags = rt_act->sa_flags;
6123 act.sa_restorer = arg5;
6124 unlock_user_struct(rt_act, arg2, 0);
6125 pact = &act;
6126 }
6127 ret = get_errno(do_sigaction(arg1, pact, &oact));
6128 if (!is_error(ret) && arg3) {
6129 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6130 goto efault;
6131 rt_act->_sa_handler = oact._sa_handler;
6132 rt_act->sa_mask = oact.sa_mask;
6133 rt_act->sa_flags = oact.sa_flags;
6134 unlock_user_struct(rt_act, arg3, 1);
6135 }
6136#else
pbrook53a59602006-03-25 19:31:22 +00006137 struct target_sigaction *act;
6138 struct target_sigaction *oact;
6139
bellard579a97f2007-11-11 14:26:47 +00006140 if (arg2) {
6141 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6142 goto efault;
6143 } else
pbrook53a59602006-03-25 19:31:22 +00006144 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006145 if (arg3) {
6146 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6147 ret = -TARGET_EFAULT;
6148 goto rt_sigaction_fail;
6149 }
6150 } else
pbrook53a59602006-03-25 19:31:22 +00006151 oact = NULL;
6152 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006153 rt_sigaction_fail:
6154 if (act)
pbrook53a59602006-03-25 19:31:22 +00006155 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006156 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006157 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006158#endif
pbrook53a59602006-03-25 19:31:22 +00006159 }
bellard66fb9762003-03-23 01:06:05 +00006160 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006161#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006162 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006163 {
6164 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006165 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006166 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006167 host_to_target_old_sigset(&target_set, &cur_set);
6168 ret = target_set;
6169 }
6170 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006171#endif
6172#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006173 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006174 {
6175 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006176 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006177 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006178 target_to_host_old_sigset(&set, &target_set);
6179 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006180 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006181 host_to_target_old_sigset(&target_set, &oset);
6182 ret = target_set;
6183 }
6184 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006185#endif
thse5febef2007-04-01 18:31:35 +00006186#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006187 case TARGET_NR_sigprocmask:
6188 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006189#if defined(TARGET_ALPHA)
6190 sigset_t set, oldset;
6191 abi_ulong mask;
6192 int how;
6193
6194 switch (arg1) {
6195 case TARGET_SIG_BLOCK:
6196 how = SIG_BLOCK;
6197 break;
6198 case TARGET_SIG_UNBLOCK:
6199 how = SIG_UNBLOCK;
6200 break;
6201 case TARGET_SIG_SETMASK:
6202 how = SIG_SETMASK;
6203 break;
6204 default:
6205 ret = -TARGET_EINVAL;
6206 goto fail;
6207 }
6208 mask = arg2;
6209 target_to_host_old_sigset(&set, &mask);
6210
Alex Barcelo1c275922014-03-14 14:36:55 +00006211 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006212 if (!is_error(ret)) {
6213 host_to_target_old_sigset(&mask, &oldset);
6214 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006215 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006216 }
6217#else
bellard66fb9762003-03-23 01:06:05 +00006218 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006219 int how;
ths3b46e622007-09-17 08:09:54 +00006220
pbrook53a59602006-03-25 19:31:22 +00006221 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006222 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006223 case TARGET_SIG_BLOCK:
6224 how = SIG_BLOCK;
6225 break;
6226 case TARGET_SIG_UNBLOCK:
6227 how = SIG_UNBLOCK;
6228 break;
6229 case TARGET_SIG_SETMASK:
6230 how = SIG_SETMASK;
6231 break;
6232 default:
ths0da46a62007-10-20 20:23:07 +00006233 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006234 goto fail;
6235 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006236 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006237 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006238 target_to_host_old_sigset(&set, p);
6239 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006240 set_ptr = &set;
6241 } else {
6242 how = 0;
6243 set_ptr = NULL;
6244 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006245 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006246 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006247 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006248 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006249 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006250 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006251 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006252#endif
bellard66fb9762003-03-23 01:06:05 +00006253 }
6254 break;
thse5febef2007-04-01 18:31:35 +00006255#endif
bellard66fb9762003-03-23 01:06:05 +00006256 case TARGET_NR_rt_sigprocmask:
6257 {
6258 int how = arg1;
6259 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006260
pbrook53a59602006-03-25 19:31:22 +00006261 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006262 switch(how) {
6263 case TARGET_SIG_BLOCK:
6264 how = SIG_BLOCK;
6265 break;
6266 case TARGET_SIG_UNBLOCK:
6267 how = SIG_UNBLOCK;
6268 break;
6269 case TARGET_SIG_SETMASK:
6270 how = SIG_SETMASK;
6271 break;
6272 default:
ths0da46a62007-10-20 20:23:07 +00006273 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006274 goto fail;
6275 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006276 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006277 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006278 target_to_host_sigset(&set, p);
6279 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006280 set_ptr = &set;
6281 } else {
6282 how = 0;
6283 set_ptr = NULL;
6284 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006285 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006286 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006287 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006288 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006289 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006290 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006291 }
6292 }
6293 break;
thse5febef2007-04-01 18:31:35 +00006294#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006295 case TARGET_NR_sigpending:
6296 {
6297 sigset_t set;
6298 ret = get_errno(sigpending(&set));
6299 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006300 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006301 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006302 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006303 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006304 }
6305 }
6306 break;
thse5febef2007-04-01 18:31:35 +00006307#endif
bellard66fb9762003-03-23 01:06:05 +00006308 case TARGET_NR_rt_sigpending:
6309 {
6310 sigset_t set;
6311 ret = get_errno(sigpending(&set));
6312 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006313 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006314 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006315 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006316 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006317 }
6318 }
6319 break;
thse5febef2007-04-01 18:31:35 +00006320#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006321 case TARGET_NR_sigsuspend:
6322 {
6323 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006324#if defined(TARGET_ALPHA)
6325 abi_ulong mask = arg1;
6326 target_to_host_old_sigset(&set, &mask);
6327#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006328 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006329 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006330 target_to_host_old_sigset(&set, p);
6331 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006332#endif
bellard66fb9762003-03-23 01:06:05 +00006333 ret = get_errno(sigsuspend(&set));
6334 }
6335 break;
thse5febef2007-04-01 18:31:35 +00006336#endif
bellard66fb9762003-03-23 01:06:05 +00006337 case TARGET_NR_rt_sigsuspend:
6338 {
6339 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006340 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006341 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006342 target_to_host_sigset(&set, p);
6343 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006344 ret = get_errno(sigsuspend(&set));
6345 }
6346 break;
6347 case TARGET_NR_rt_sigtimedwait:
6348 {
bellard66fb9762003-03-23 01:06:05 +00006349 sigset_t set;
6350 struct timespec uts, *puts;
6351 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006352
Anthony Liguoric227f092009-10-01 16:12:16 -05006353 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006354 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006355 target_to_host_sigset(&set, p);
6356 unlock_user(p, arg1, 0);
6357 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006358 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006359 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006360 } else {
6361 puts = NULL;
6362 }
6363 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006364 if (!is_error(ret)) {
6365 if (arg2) {
6366 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6367 0);
6368 if (!p) {
6369 goto efault;
6370 }
6371 host_to_target_siginfo(p, &uinfo);
6372 unlock_user(p, arg2, sizeof(target_siginfo_t));
6373 }
6374 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006375 }
6376 }
6377 break;
6378 case TARGET_NR_rt_sigqueueinfo:
6379 {
6380 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006381 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006382 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006383 target_to_host_siginfo(&uinfo, p);
6384 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006385 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6386 }
6387 break;
thse5febef2007-04-01 18:31:35 +00006388#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006389 case TARGET_NR_sigreturn:
6390 /* NOTE: ret is eax, so not transcoding must be done */
6391 ret = do_sigreturn(cpu_env);
6392 break;
thse5febef2007-04-01 18:31:35 +00006393#endif
bellard66fb9762003-03-23 01:06:05 +00006394 case TARGET_NR_rt_sigreturn:
6395 /* NOTE: ret is eax, so not transcoding must be done */
6396 ret = do_rt_sigreturn(cpu_env);
6397 break;
bellard31e31b82003-02-18 22:55:36 +00006398 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006399 if (!(p = lock_user_string(arg1)))
6400 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006401 ret = get_errno(sethostname(p, arg2));
6402 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006403 break;
6404 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006405 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006406 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006407 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006408 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006409 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6410 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006411 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6412 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006413 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006414 ret = get_errno(setrlimit(resource, &rlim));
6415 }
6416 break;
bellard31e31b82003-02-18 22:55:36 +00006417 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006418 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006419 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006420 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006421 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006422
bellard9de5e442003-03-23 16:49:39 +00006423 ret = get_errno(getrlimit(resource, &rlim));
6424 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006425 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6426 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006427 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6428 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006429 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006430 }
6431 }
6432 break;
bellard31e31b82003-02-18 22:55:36 +00006433 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006434 {
6435 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006436 ret = get_errno(getrusage(arg1, &rusage));
6437 if (!is_error(ret)) {
Petar Jovanovica39fb272014-04-08 19:24:30 +02006438 ret = host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006439 }
6440 }
6441 break;
bellard31e31b82003-02-18 22:55:36 +00006442 case TARGET_NR_gettimeofday:
6443 {
bellard31e31b82003-02-18 22:55:36 +00006444 struct timeval tv;
6445 ret = get_errno(gettimeofday(&tv, NULL));
6446 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006447 if (copy_to_user_timeval(arg1, &tv))
6448 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006449 }
6450 }
6451 break;
6452 case TARGET_NR_settimeofday:
6453 {
Paul Burtonb67d8032014-06-22 11:25:41 +01006454 struct timeval tv, *ptv = NULL;
Paul Burtonef4467e2014-06-22 11:25:40 +01006455 struct timezone tz, *ptz = NULL;
6456
Paul Burtonb67d8032014-06-22 11:25:41 +01006457 if (arg1) {
6458 if (copy_from_user_timeval(&tv, arg1)) {
6459 goto efault;
6460 }
6461 ptv = &tv;
6462 }
Paul Burtonef4467e2014-06-22 11:25:40 +01006463
6464 if (arg2) {
6465 if (copy_from_user_timezone(&tz, arg2)) {
6466 goto efault;
6467 }
6468 ptz = &tz;
6469 }
6470
Paul Burtonb67d8032014-06-22 11:25:41 +01006471 ret = get_errno(settimeofday(ptv, ptz));
bellard31e31b82003-02-18 22:55:36 +00006472 }
6473 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006474#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006475 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006476#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6477 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6478#else
bellardf2674e32003-07-09 12:26:09 +00006479 {
pbrook53a59602006-03-25 19:31:22 +00006480 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006481 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006482 long nsel;
6483
bellard579a97f2007-11-11 14:26:47 +00006484 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6485 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006486 nsel = tswapal(sel->n);
6487 inp = tswapal(sel->inp);
6488 outp = tswapal(sel->outp);
6489 exp = tswapal(sel->exp);
6490 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006491 unlock_user_struct(sel, arg1, 0);
6492 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006493 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006494#endif
bellardf2674e32003-07-09 12:26:09 +00006495 break;
bellard048f6b42005-11-26 18:47:20 +00006496#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006497#ifdef TARGET_NR_pselect6
6498 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006499 {
6500 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6501 fd_set rfds, wfds, efds;
6502 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6503 struct timespec ts, *ts_ptr;
6504
6505 /*
6506 * The 6th arg is actually two args smashed together,
6507 * so we cannot use the C library.
6508 */
6509 sigset_t set;
6510 struct {
6511 sigset_t *set;
6512 size_t size;
6513 } sig, *sig_ptr;
6514
6515 abi_ulong arg_sigset, arg_sigsize, *arg7;
6516 target_sigset_t *target_sigset;
6517
6518 n = arg1;
6519 rfd_addr = arg2;
6520 wfd_addr = arg3;
6521 efd_addr = arg4;
6522 ts_addr = arg5;
6523
6524 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6525 if (ret) {
6526 goto fail;
6527 }
6528 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6529 if (ret) {
6530 goto fail;
6531 }
6532 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6533 if (ret) {
6534 goto fail;
6535 }
6536
6537 /*
6538 * This takes a timespec, and not a timeval, so we cannot
6539 * use the do_select() helper ...
6540 */
6541 if (ts_addr) {
6542 if (target_to_host_timespec(&ts, ts_addr)) {
6543 goto efault;
6544 }
6545 ts_ptr = &ts;
6546 } else {
6547 ts_ptr = NULL;
6548 }
6549
6550 /* Extract the two packed args for the sigset */
6551 if (arg6) {
6552 sig_ptr = &sig;
6553 sig.size = _NSIG / 8;
6554
6555 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6556 if (!arg7) {
6557 goto efault;
6558 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006559 arg_sigset = tswapal(arg7[0]);
6560 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006561 unlock_user(arg7, arg6, 0);
6562
6563 if (arg_sigset) {
6564 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006565 if (arg_sigsize != sizeof(*target_sigset)) {
6566 /* Like the kernel, we enforce correct size sigsets */
6567 ret = -TARGET_EINVAL;
6568 goto fail;
6569 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006570 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6571 sizeof(*target_sigset), 1);
6572 if (!target_sigset) {
6573 goto efault;
6574 }
6575 target_to_host_sigset(&set, target_sigset);
6576 unlock_user(target_sigset, arg_sigset, 0);
6577 } else {
6578 sig.set = NULL;
6579 }
6580 } else {
6581 sig_ptr = NULL;
6582 }
6583
6584 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6585 ts_ptr, sig_ptr));
6586
6587 if (!is_error(ret)) {
6588 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6589 goto efault;
6590 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6591 goto efault;
6592 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6593 goto efault;
6594
6595 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6596 goto efault;
6597 }
6598 }
6599 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006600#endif
bellard31e31b82003-02-18 22:55:36 +00006601 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006602 {
6603 void *p2;
6604 p = lock_user_string(arg1);
6605 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006606 if (!p || !p2)
6607 ret = -TARGET_EFAULT;
6608 else
6609 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006610 unlock_user(p2, arg2, 0);
6611 unlock_user(p, arg1, 0);
6612 }
bellard31e31b82003-02-18 22:55:36 +00006613 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006614#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006615 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006616 {
bellard579a97f2007-11-11 14:26:47 +00006617 void *p2;
thsf0b62432007-09-24 09:25:40 +00006618 p = lock_user_string(arg1);
6619 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006620 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006621 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006622 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006623 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006624 unlock_user(p2, arg3, 0);
6625 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006626 }
6627 break;
6628#endif
bellardebc05482003-09-30 21:08:41 +00006629#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006630 case TARGET_NR_oldlstat:
6631 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006632#endif
bellard31e31b82003-02-18 22:55:36 +00006633 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006634 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006635 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006636 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006637 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006638 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006639 ret = -TARGET_EFAULT;
Mike Frysingerf17f4982014-08-08 09:40:25 +09006640 } else if (!arg3) {
6641 /* Short circuit this for the magic exe check. */
6642 ret = -TARGET_EINVAL;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006643 } else if (is_proc_myself((const char *)p, "exe")) {
6644 char real[PATH_MAX], *temp;
6645 temp = realpath(exec_path, real);
Mike Frysingerf17f4982014-08-08 09:40:25 +09006646 /* Return value is # of bytes that we wrote to the buffer. */
6647 if (temp == NULL) {
6648 ret = get_errno(-1);
6649 } else {
6650 /* Don't worry about sign mismatch as earlier mapping
6651 * logic would have thrown a bad address error. */
6652 ret = MIN(strlen(real), arg3);
6653 /* We cannot NUL terminate the string. */
6654 memcpy(p2, real, ret);
6655 }
Andreas Schwab463d8e72013-07-02 14:04:12 +01006656 } else {
6657 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006658 }
pbrook53a59602006-03-25 19:31:22 +00006659 unlock_user(p2, arg2, ret);
6660 unlock_user(p, arg1, 0);
6661 }
bellard31e31b82003-02-18 22:55:36 +00006662 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006663#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006664 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006665 {
bellard579a97f2007-11-11 14:26:47 +00006666 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006667 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006668 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006669 if (!p || !p2) {
6670 ret = -TARGET_EFAULT;
6671 } else if (is_proc_myself((const char *)p, "exe")) {
6672 char real[PATH_MAX], *temp;
6673 temp = realpath(exec_path, real);
6674 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6675 snprintf((char *)p2, arg4, "%s", real);
6676 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006677 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006678 }
bellard579a97f2007-11-11 14:26:47 +00006679 unlock_user(p2, arg3, ret);
6680 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006681 }
6682 break;
6683#endif
thse5febef2007-04-01 18:31:35 +00006684#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006685 case TARGET_NR_uselib:
6686 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006687#endif
6688#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006689 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006690 if (!(p = lock_user_string(arg1)))
6691 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006692 ret = get_errno(swapon(p, arg2));
6693 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006694 break;
thse5febef2007-04-01 18:31:35 +00006695#endif
bellard31e31b82003-02-18 22:55:36 +00006696 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006697 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6698 /* arg4 must be ignored in all other cases */
6699 p = lock_user_string(arg4);
6700 if (!p) {
6701 goto efault;
6702 }
6703 ret = get_errno(reboot(arg1, arg2, arg3, p));
6704 unlock_user(p, arg4, 0);
6705 } else {
6706 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6707 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006708 break;
thse5febef2007-04-01 18:31:35 +00006709#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006710 case TARGET_NR_readdir:
6711 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006712#endif
6713#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006714 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006715#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6716 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006717 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6718 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006719 {
blueswir1992f48a2007-10-14 16:27:31 +00006720 abi_ulong *v;
6721 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006722 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6723 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006724 v1 = tswapal(v[0]);
6725 v2 = tswapal(v[1]);
6726 v3 = tswapal(v[2]);
6727 v4 = tswapal(v[3]);
6728 v5 = tswapal(v[4]);
6729 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006730 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006731 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006732 target_to_host_bitmask(v4, mmap_flags_tbl),
6733 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006734 }
bellard31e31b82003-02-18 22:55:36 +00006735#else
ths5fafdf22007-09-16 21:08:06 +00006736 ret = get_errno(target_mmap(arg1, arg2, arg3,
6737 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006738 arg5,
6739 arg6));
bellard31e31b82003-02-18 22:55:36 +00006740#endif
bellard6fb883e2003-07-09 17:12:39 +00006741 break;
thse5febef2007-04-01 18:31:35 +00006742#endif
bellarda315a142005-01-30 22:59:18 +00006743#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006744 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006745#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006746#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006747#endif
ths5fafdf22007-09-16 21:08:06 +00006748 ret = get_errno(target_mmap(arg1, arg2, arg3,
6749 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006750 arg5,
bellardc573ff62004-01-04 15:51:36 +00006751 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006752 break;
bellarda315a142005-01-30 22:59:18 +00006753#endif
bellard31e31b82003-02-18 22:55:36 +00006754 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006755 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006756 break;
bellard9de5e442003-03-23 16:49:39 +00006757 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006758 {
Andreas Färber0429a972013-08-26 18:14:44 +02006759 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006760 /* Special hack to detect libc making the stack executable. */
6761 if ((arg3 & PROT_GROWSDOWN)
6762 && arg1 >= ts->info->stack_limit
6763 && arg1 <= ts->info->start_stack) {
6764 arg3 &= ~PROT_GROWSDOWN;
6765 arg2 = arg2 + arg1 - ts->info->stack_limit;
6766 arg1 = ts->info->stack_limit;
6767 }
6768 }
bellard54936002003-05-13 00:25:15 +00006769 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006770 break;
thse5febef2007-04-01 18:31:35 +00006771#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006772 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006773 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006774 break;
thse5febef2007-04-01 18:31:35 +00006775#endif
pbrook53a59602006-03-25 19:31:22 +00006776 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006777#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006778 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006779 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006780 break;
thse5febef2007-04-01 18:31:35 +00006781#endif
6782#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006783 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006784 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006785 break;
thse5febef2007-04-01 18:31:35 +00006786#endif
6787#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006788 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006789 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006790 break;
thse5febef2007-04-01 18:31:35 +00006791#endif
6792#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006793 case TARGET_NR_mlockall:
6794 ret = get_errno(mlockall(arg1));
6795 break;
thse5febef2007-04-01 18:31:35 +00006796#endif
6797#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006798 case TARGET_NR_munlockall:
6799 ret = get_errno(munlockall());
6800 break;
thse5febef2007-04-01 18:31:35 +00006801#endif
bellard31e31b82003-02-18 22:55:36 +00006802 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006803 if (!(p = lock_user_string(arg1)))
6804 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006805 ret = get_errno(truncate(p, arg2));
6806 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006807 break;
6808 case TARGET_NR_ftruncate:
6809 ret = get_errno(ftruncate(arg1, arg2));
6810 break;
6811 case TARGET_NR_fchmod:
6812 ret = get_errno(fchmod(arg1, arg2));
6813 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006814#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006815 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006816 if (!(p = lock_user_string(arg2)))
6817 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006818 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006819 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006820 break;
6821#endif
bellard31e31b82003-02-18 22:55:36 +00006822 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006823 /* Note that negative values are valid for getpriority, so we must
6824 differentiate based on errno settings. */
6825 errno = 0;
6826 ret = getpriority(arg1, arg2);
6827 if (ret == -1 && errno != 0) {
6828 ret = -host_to_target_errno(errno);
6829 break;
6830 }
6831#ifdef TARGET_ALPHA
6832 /* Return value is the unbiased priority. Signal no error. */
6833 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6834#else
6835 /* Return value is a biased priority to avoid negative numbers. */
6836 ret = 20 - ret;
6837#endif
bellard31e31b82003-02-18 22:55:36 +00006838 break;
6839 case TARGET_NR_setpriority:
6840 ret = get_errno(setpriority(arg1, arg2, arg3));
6841 break;
bellardebc05482003-09-30 21:08:41 +00006842#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006843 case TARGET_NR_profil:
6844 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006845#endif
bellard31e31b82003-02-18 22:55:36 +00006846 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006847 if (!(p = lock_user_string(arg1)))
6848 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006849 ret = get_errno(statfs(path(p), &stfs));
6850 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006851 convert_statfs:
6852 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006853 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006854
bellard579a97f2007-11-11 14:26:47 +00006855 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6856 goto efault;
6857 __put_user(stfs.f_type, &target_stfs->f_type);
6858 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6859 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6860 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6861 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6862 __put_user(stfs.f_files, &target_stfs->f_files);
6863 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6864 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6865 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6866 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006867 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6868 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006869 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006870 }
6871 break;
6872 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006873 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006874 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006875#ifdef TARGET_NR_statfs64
6876 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006877 if (!(p = lock_user_string(arg1)))
6878 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006879 ret = get_errno(statfs(path(p), &stfs));
6880 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006881 convert_statfs64:
6882 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006883 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006884
bellard579a97f2007-11-11 14:26:47 +00006885 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6886 goto efault;
6887 __put_user(stfs.f_type, &target_stfs->f_type);
6888 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6889 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6890 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6891 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6892 __put_user(stfs.f_files, &target_stfs->f_files);
6893 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6894 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6895 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6896 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006897 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6898 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006899 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006900 }
6901 break;
6902 case TARGET_NR_fstatfs64:
6903 ret = get_errno(fstatfs(arg1, &stfs));
6904 goto convert_statfs64;
6905#endif
bellardebc05482003-09-30 21:08:41 +00006906#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006907 case TARGET_NR_ioperm:
6908 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006909#endif
thse5febef2007-04-01 18:31:35 +00006910#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006911 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006912 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006913 break;
thse5febef2007-04-01 18:31:35 +00006914#endif
bellard3532fa72006-06-24 15:06:03 +00006915#ifdef TARGET_NR_accept
6916 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006917 ret = do_accept4(arg1, arg2, arg3, 0);
6918 break;
6919#endif
6920#ifdef TARGET_NR_accept4
6921 case TARGET_NR_accept4:
6922#ifdef CONFIG_ACCEPT4
6923 ret = do_accept4(arg1, arg2, arg3, arg4);
6924#else
6925 goto unimplemented;
6926#endif
bellard3532fa72006-06-24 15:06:03 +00006927 break;
6928#endif
6929#ifdef TARGET_NR_bind
6930 case TARGET_NR_bind:
6931 ret = do_bind(arg1, arg2, arg3);
6932 break;
6933#endif
6934#ifdef TARGET_NR_connect
6935 case TARGET_NR_connect:
6936 ret = do_connect(arg1, arg2, arg3);
6937 break;
6938#endif
6939#ifdef TARGET_NR_getpeername
6940 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006941 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006942 break;
6943#endif
6944#ifdef TARGET_NR_getsockname
6945 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006946 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006947 break;
6948#endif
6949#ifdef TARGET_NR_getsockopt
6950 case TARGET_NR_getsockopt:
6951 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6952 break;
6953#endif
6954#ifdef TARGET_NR_listen
6955 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006956 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006957 break;
6958#endif
6959#ifdef TARGET_NR_recv
6960 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006961 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006962 break;
6963#endif
6964#ifdef TARGET_NR_recvfrom
6965 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006966 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006967 break;
6968#endif
6969#ifdef TARGET_NR_recvmsg
6970 case TARGET_NR_recvmsg:
6971 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6972 break;
6973#endif
6974#ifdef TARGET_NR_send
6975 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006976 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006977 break;
6978#endif
6979#ifdef TARGET_NR_sendmsg
6980 case TARGET_NR_sendmsg:
6981 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6982 break;
6983#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006984#ifdef TARGET_NR_sendmmsg
6985 case TARGET_NR_sendmmsg:
6986 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6987 break;
6988 case TARGET_NR_recvmmsg:
6989 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6990 break;
6991#endif
bellard3532fa72006-06-24 15:06:03 +00006992#ifdef TARGET_NR_sendto
6993 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006994 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006995 break;
6996#endif
6997#ifdef TARGET_NR_shutdown
6998 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006999 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00007000 break;
7001#endif
7002#ifdef TARGET_NR_socket
7003 case TARGET_NR_socket:
7004 ret = do_socket(arg1, arg2, arg3);
7005 break;
7006#endif
7007#ifdef TARGET_NR_socketpair
7008 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00007009 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00007010 break;
7011#endif
7012#ifdef TARGET_NR_setsockopt
7013 case TARGET_NR_setsockopt:
7014 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
7015 break;
7016#endif
ths7494b0f2007-02-11 18:26:53 +00007017
bellard31e31b82003-02-18 22:55:36 +00007018 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00007019 if (!(p = lock_user_string(arg2)))
7020 goto efault;
thse5574482007-02-11 20:03:13 +00007021 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
7022 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00007023 break;
7024
bellard31e31b82003-02-18 22:55:36 +00007025 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00007026 {
bellard66fb9762003-03-23 01:06:05 +00007027 struct itimerval value, ovalue, *pvalue;
7028
pbrook53a59602006-03-25 19:31:22 +00007029 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00007030 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00007031 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
7032 || copy_from_user_timeval(&pvalue->it_value,
7033 arg2 + sizeof(struct target_timeval)))
7034 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007035 } else {
7036 pvalue = NULL;
7037 }
7038 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00007039 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00007040 if (copy_to_user_timeval(arg3,
7041 &ovalue.it_interval)
7042 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
7043 &ovalue.it_value))
7044 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007045 }
7046 }
7047 break;
bellard31e31b82003-02-18 22:55:36 +00007048 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00007049 {
bellard66fb9762003-03-23 01:06:05 +00007050 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00007051
bellard66fb9762003-03-23 01:06:05 +00007052 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00007053 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00007054 if (copy_to_user_timeval(arg2,
7055 &value.it_interval)
7056 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
7057 &value.it_value))
7058 goto efault;
bellard66fb9762003-03-23 01:06:05 +00007059 }
7060 }
7061 break;
bellard31e31b82003-02-18 22:55:36 +00007062 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00007063 if (!(p = lock_user_string(arg1)))
7064 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007065 ret = get_errno(stat(path(p), &st));
7066 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007067 goto do_stat;
7068 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00007069 if (!(p = lock_user_string(arg1)))
7070 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007071 ret = get_errno(lstat(path(p), &st));
7072 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007073 goto do_stat;
7074 case TARGET_NR_fstat:
7075 {
7076 ret = get_errno(fstat(arg1, &st));
7077 do_stat:
7078 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007079 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00007080
bellard579a97f2007-11-11 14:26:47 +00007081 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
7082 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02007083 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00007084 __put_user(st.st_dev, &target_st->st_dev);
7085 __put_user(st.st_ino, &target_st->st_ino);
7086 __put_user(st.st_mode, &target_st->st_mode);
7087 __put_user(st.st_uid, &target_st->st_uid);
7088 __put_user(st.st_gid, &target_st->st_gid);
7089 __put_user(st.st_nlink, &target_st->st_nlink);
7090 __put_user(st.st_rdev, &target_st->st_rdev);
7091 __put_user(st.st_size, &target_st->st_size);
7092 __put_user(st.st_blksize, &target_st->st_blksize);
7093 __put_user(st.st_blocks, &target_st->st_blocks);
7094 __put_user(st.st_atime, &target_st->target_st_atime);
7095 __put_user(st.st_mtime, &target_st->target_st_mtime);
7096 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00007097 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00007098 }
7099 }
7100 break;
bellardebc05482003-09-30 21:08:41 +00007101#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00007102 case TARGET_NR_olduname:
7103 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007104#endif
7105#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00007106 case TARGET_NR_iopl:
7107 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007108#endif
bellard31e31b82003-02-18 22:55:36 +00007109 case TARGET_NR_vhangup:
7110 ret = get_errno(vhangup());
7111 break;
bellardebc05482003-09-30 21:08:41 +00007112#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00007113 case TARGET_NR_idle:
7114 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007115#endif
bellard42ad6ae2005-01-03 22:48:11 +00007116#ifdef TARGET_NR_syscall
7117 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007118 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7119 arg6, arg7, arg8, 0);
7120 break;
bellard42ad6ae2005-01-03 22:48:11 +00007121#endif
bellard31e31b82003-02-18 22:55:36 +00007122 case TARGET_NR_wait4:
7123 {
7124 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007125 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007126 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007127 abi_ulong target_rusage = arg4;
Petar Jovanovica39fb272014-04-08 19:24:30 +02007128 abi_long rusage_err;
bellard31e31b82003-02-18 22:55:36 +00007129 if (target_rusage)
7130 rusage_ptr = &rusage;
7131 else
7132 rusage_ptr = NULL;
7133 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7134 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007135 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007136 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007137 if (put_user_s32(status, status_ptr))
7138 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007139 }
Petar Jovanovica39fb272014-04-08 19:24:30 +02007140 if (target_rusage) {
7141 rusage_err = host_to_target_rusage(target_rusage, &rusage);
7142 if (rusage_err) {
7143 ret = rusage_err;
7144 }
7145 }
bellard31e31b82003-02-18 22:55:36 +00007146 }
7147 }
7148 break;
thse5febef2007-04-01 18:31:35 +00007149#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007150 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007151 if (!(p = lock_user_string(arg1)))
7152 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007153 ret = get_errno(swapoff(p));
7154 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007155 break;
thse5febef2007-04-01 18:31:35 +00007156#endif
bellard31e31b82003-02-18 22:55:36 +00007157 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007158 {
pbrook53a59602006-03-25 19:31:22 +00007159 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007160 struct sysinfo value;
7161 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007162 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007163 {
bellard579a97f2007-11-11 14:26:47 +00007164 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7165 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007166 __put_user(value.uptime, &target_value->uptime);
7167 __put_user(value.loads[0], &target_value->loads[0]);
7168 __put_user(value.loads[1], &target_value->loads[1]);
7169 __put_user(value.loads[2], &target_value->loads[2]);
7170 __put_user(value.totalram, &target_value->totalram);
7171 __put_user(value.freeram, &target_value->freeram);
7172 __put_user(value.sharedram, &target_value->sharedram);
7173 __put_user(value.bufferram, &target_value->bufferram);
7174 __put_user(value.totalswap, &target_value->totalswap);
7175 __put_user(value.freeswap, &target_value->freeswap);
7176 __put_user(value.procs, &target_value->procs);
7177 __put_user(value.totalhigh, &target_value->totalhigh);
7178 __put_user(value.freehigh, &target_value->freehigh);
7179 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007180 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007181 }
7182 }
7183 break;
thse5febef2007-04-01 18:31:35 +00007184#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007185 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007186 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7187 break;
thse5febef2007-04-01 18:31:35 +00007188#endif
aurel32e5289082009-04-18 16:16:12 +00007189#ifdef TARGET_NR_semget
7190 case TARGET_NR_semget:
7191 ret = get_errno(semget(arg1, arg2, arg3));
7192 break;
7193#endif
7194#ifdef TARGET_NR_semop
7195 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007196 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007197 break;
7198#endif
7199#ifdef TARGET_NR_semctl
7200 case TARGET_NR_semctl:
7201 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7202 break;
7203#endif
aurel32eeb438c2008-10-13 21:08:55 +00007204#ifdef TARGET_NR_msgctl
7205 case TARGET_NR_msgctl:
7206 ret = do_msgctl(arg1, arg2, arg3);
7207 break;
7208#endif
7209#ifdef TARGET_NR_msgget
7210 case TARGET_NR_msgget:
7211 ret = get_errno(msgget(arg1, arg2));
7212 break;
7213#endif
7214#ifdef TARGET_NR_msgrcv
7215 case TARGET_NR_msgrcv:
7216 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7217 break;
7218#endif
7219#ifdef TARGET_NR_msgsnd
7220 case TARGET_NR_msgsnd:
7221 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7222 break;
7223#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007224#ifdef TARGET_NR_shmget
7225 case TARGET_NR_shmget:
7226 ret = get_errno(shmget(arg1, arg2, arg3));
7227 break;
7228#endif
7229#ifdef TARGET_NR_shmctl
7230 case TARGET_NR_shmctl:
7231 ret = do_shmctl(arg1, arg2, arg3);
7232 break;
7233#endif
7234#ifdef TARGET_NR_shmat
7235 case TARGET_NR_shmat:
7236 ret = do_shmat(arg1, arg2, arg3);
7237 break;
7238#endif
7239#ifdef TARGET_NR_shmdt
7240 case TARGET_NR_shmdt:
7241 ret = do_shmdt(arg1);
7242 break;
7243#endif
bellard31e31b82003-02-18 22:55:36 +00007244 case TARGET_NR_fsync:
7245 ret = get_errno(fsync(arg1));
7246 break;
bellard31e31b82003-02-18 22:55:36 +00007247 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007248 /* Linux manages to have three different orderings for its
7249 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7250 * match the kernel's CONFIG_CLONE_* settings.
7251 * Microblaze is further special in that it uses a sixth
7252 * implicit argument to clone for the TLS pointer.
7253 */
7254#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007255 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007256#elif defined(TARGET_CLONE_BACKWARDS)
7257 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7258#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007259 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007260#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007261 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007262#endif
bellard1b6b0292003-03-22 17:31:38 +00007263 break;
bellardec86b0f2003-04-11 00:15:04 +00007264#ifdef __NR_exit_group
7265 /* new thread calls */
7266 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007267#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007268 _mcleanup();
7269#endif
bellarde9009672005-04-26 20:42:36 +00007270 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007271 ret = get_errno(exit_group(arg1));
7272 break;
7273#endif
bellard31e31b82003-02-18 22:55:36 +00007274 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007275 if (!(p = lock_user_string(arg1)))
7276 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007277 ret = get_errno(setdomainname(p, arg2));
7278 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007279 break;
7280 case TARGET_NR_uname:
7281 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007282 {
7283 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007284
bellard579a97f2007-11-11 14:26:47 +00007285 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7286 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007287 ret = get_errno(sys_uname(buf));
7288 if (!is_error(ret)) {
7289 /* Overrite the native machine name with whatever is being
7290 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007291 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007292 /* Allow the user to override the reported release. */
7293 if (qemu_uname_release && *qemu_uname_release)
7294 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007295 }
pbrook53a59602006-03-25 19:31:22 +00007296 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007297 }
bellard31e31b82003-02-18 22:55:36 +00007298 break;
bellard6dbad632003-03-16 18:05:05 +00007299#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007300 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007301 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007302 break;
j_mayer84409dd2007-04-06 08:56:50 +00007303#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007304 case TARGET_NR_vm86old:
7305 goto unimplemented;
7306 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007307 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007308 break;
7309#endif
j_mayer84409dd2007-04-06 08:56:50 +00007310#endif
bellard31e31b82003-02-18 22:55:36 +00007311 case TARGET_NR_adjtimex:
7312 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007313#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007314 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007315#endif
bellard31e31b82003-02-18 22:55:36 +00007316 case TARGET_NR_init_module:
7317 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007318#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007319 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007320#endif
bellard31e31b82003-02-18 22:55:36 +00007321 goto unimplemented;
7322 case TARGET_NR_quotactl:
7323 goto unimplemented;
7324 case TARGET_NR_getpgid:
7325 ret = get_errno(getpgid(arg1));
7326 break;
7327 case TARGET_NR_fchdir:
7328 ret = get_errno(fchdir(arg1));
7329 break;
j_mayer84409dd2007-04-06 08:56:50 +00007330#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007331 case TARGET_NR_bdflush:
7332 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007333#endif
thse5febef2007-04-01 18:31:35 +00007334#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007335 case TARGET_NR_sysfs:
7336 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007337#endif
bellard31e31b82003-02-18 22:55:36 +00007338 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007339 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007340 break;
thse5febef2007-04-01 18:31:35 +00007341#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007342 case TARGET_NR_afs_syscall:
7343 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007344#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007345#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007346 case TARGET_NR__llseek:
7347 {
7348 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007349#if !defined(__NR_llseek)
7350 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7351 if (res == -1) {
7352 ret = get_errno(res);
7353 } else {
7354 ret = 0;
7355 }
7356#else
bellard31e31b82003-02-18 22:55:36 +00007357 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007358#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007359 if ((ret == 0) && put_user_s64(res, arg4)) {
7360 goto efault;
7361 }
bellard31e31b82003-02-18 22:55:36 +00007362 }
7363 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007364#endif
bellard31e31b82003-02-18 22:55:36 +00007365 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007366#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007367#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007368 {
pbrook53a59602006-03-25 19:31:22 +00007369 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007370 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007371 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007372
7373 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007374 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007375 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007376 goto fail;
7377 }
ths3b46e622007-09-17 08:09:54 +00007378
bellard4add45b2003-06-05 01:52:59 +00007379 ret = get_errno(sys_getdents(arg1, dirp, count));
7380 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007381 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007382 struct target_dirent *tde;
7383 int len = ret;
7384 int reclen, treclen;
7385 int count1, tnamelen;
7386
7387 count1 = 0;
7388 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007389 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7390 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007391 tde = target_dirp;
7392 while (len > 0) {
7393 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007394 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7395 assert(tnamelen >= 0);
7396 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7397 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007398 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007399 tde->d_ino = tswapal(de->d_ino);
7400 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007401 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007402 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007403 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007404 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007405 count1 += treclen;
7406 }
7407 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007408 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007409 }
7410 free(dirp);
7411 }
7412#else
bellard31e31b82003-02-18 22:55:36 +00007413 {
aurel326556a832008-10-13 21:08:17 +00007414 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007415 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007416
bellard579a97f2007-11-11 14:26:47 +00007417 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7418 goto efault;
bellard72f03902003-02-18 23:33:18 +00007419 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007420 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007421 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007422 int len = ret;
7423 int reclen;
7424 de = dirp;
7425 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007426 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007427 if (reclen > len)
7428 break;
bellard8083a3e2003-03-24 23:12:16 +00007429 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007430 tswapls(&de->d_ino);
7431 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007432 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007433 len -= reclen;
7434 }
7435 }
pbrook53a59602006-03-25 19:31:22 +00007436 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007437 }
bellard4add45b2003-06-05 01:52:59 +00007438#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007439#else
7440 /* Implement getdents in terms of getdents64 */
7441 {
7442 struct linux_dirent64 *dirp;
7443 abi_long count = arg3;
7444
7445 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7446 if (!dirp) {
7447 goto efault;
7448 }
7449 ret = get_errno(sys_getdents64(arg1, dirp, count));
7450 if (!is_error(ret)) {
7451 /* Convert the dirent64 structs to target dirent. We do this
7452 * in-place, since we can guarantee that a target_dirent is no
7453 * larger than a dirent64; however this means we have to be
7454 * careful to read everything before writing in the new format.
7455 */
7456 struct linux_dirent64 *de;
7457 struct target_dirent *tde;
7458 int len = ret;
7459 int tlen = 0;
7460
7461 de = dirp;
7462 tde = (struct target_dirent *)dirp;
7463 while (len > 0) {
7464 int namelen, treclen;
7465 int reclen = de->d_reclen;
7466 uint64_t ino = de->d_ino;
7467 int64_t off = de->d_off;
7468 uint8_t type = de->d_type;
7469
7470 namelen = strlen(de->d_name);
7471 treclen = offsetof(struct target_dirent, d_name)
7472 + namelen + 2;
7473 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7474
7475 memmove(tde->d_name, de->d_name, namelen + 1);
7476 tde->d_ino = tswapal(ino);
7477 tde->d_off = tswapal(off);
7478 tde->d_reclen = tswap16(treclen);
7479 /* The target_dirent type is in what was formerly a padding
7480 * byte at the end of the structure:
7481 */
7482 *(((char *)tde) + treclen - 1) = type;
7483
7484 de = (struct linux_dirent64 *)((char *)de + reclen);
7485 tde = (struct target_dirent *)((char *)tde + treclen);
7486 len -= reclen;
7487 tlen += treclen;
7488 }
7489 ret = tlen;
7490 }
7491 unlock_user(dirp, arg2, ret);
7492 }
7493#endif
bellard31e31b82003-02-18 22:55:36 +00007494 break;
ths3ae43202007-09-16 21:39:48 +00007495#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007496 case TARGET_NR_getdents64:
7497 {
aurel326556a832008-10-13 21:08:17 +00007498 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007499 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007500 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7501 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007502 ret = get_errno(sys_getdents64(arg1, dirp, count));
7503 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007504 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007505 int len = ret;
7506 int reclen;
7507 de = dirp;
7508 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007509 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007510 if (reclen > len)
7511 break;
bellard8083a3e2003-03-24 23:12:16 +00007512 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007513 tswap64s((uint64_t *)&de->d_ino);
7514 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007515 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007516 len -= reclen;
7517 }
7518 }
pbrook53a59602006-03-25 19:31:22 +00007519 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007520 }
7521 break;
bellarda541f292004-04-12 20:39:29 +00007522#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007523#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007524 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007525 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007526 break;
thse5febef2007-04-01 18:31:35 +00007527#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007528#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7529# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007530 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007531# endif
7532# ifdef TARGET_NR_ppoll
7533 case TARGET_NR_ppoll:
7534# endif
bellard9de5e442003-03-23 16:49:39 +00007535 {
pbrook53a59602006-03-25 19:31:22 +00007536 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007537 unsigned int nfds = arg2;
7538 int timeout = arg3;
7539 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007540 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007541
bellard579a97f2007-11-11 14:26:47 +00007542 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7543 if (!target_pfd)
7544 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007545
bellard9de5e442003-03-23 16:49:39 +00007546 pfd = alloca(sizeof(struct pollfd) * nfds);
7547 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007548 pfd[i].fd = tswap32(target_pfd[i].fd);
7549 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007550 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007551
7552# ifdef TARGET_NR_ppoll
7553 if (num == TARGET_NR_ppoll) {
7554 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7555 target_sigset_t *target_set;
7556 sigset_t _set, *set = &_set;
7557
7558 if (arg3) {
7559 if (target_to_host_timespec(timeout_ts, arg3)) {
7560 unlock_user(target_pfd, arg1, 0);
7561 goto efault;
7562 }
7563 } else {
7564 timeout_ts = NULL;
7565 }
7566
7567 if (arg4) {
7568 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7569 if (!target_set) {
7570 unlock_user(target_pfd, arg1, 0);
7571 goto efault;
7572 }
7573 target_to_host_sigset(set, target_set);
7574 } else {
7575 set = NULL;
7576 }
7577
7578 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7579
7580 if (!is_error(ret) && arg3) {
7581 host_to_target_timespec(arg3, timeout_ts);
7582 }
7583 if (arg4) {
7584 unlock_user(target_set, arg4, 0);
7585 }
7586 } else
7587# endif
7588 ret = get_errno(poll(pfd, nfds, timeout));
7589
bellard9de5e442003-03-23 16:49:39 +00007590 if (!is_error(ret)) {
7591 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007592 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007593 }
7594 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007595 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007596 }
7597 break;
thse5febef2007-04-01 18:31:35 +00007598#endif
bellard31e31b82003-02-18 22:55:36 +00007599 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007600 /* NOTE: the flock constant seems to be the same for every
7601 Linux platform */
7602 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007603 break;
7604 case TARGET_NR_readv:
7605 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007606 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7607 if (vec != NULL) {
7608 ret = get_errno(readv(arg1, vec, arg3));
7609 unlock_iovec(vec, arg2, arg3, 1);
7610 } else {
7611 ret = -host_to_target_errno(errno);
7612 }
bellard31e31b82003-02-18 22:55:36 +00007613 }
7614 break;
7615 case TARGET_NR_writev:
7616 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007617 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7618 if (vec != NULL) {
7619 ret = get_errno(writev(arg1, vec, arg3));
7620 unlock_iovec(vec, arg2, arg3, 0);
7621 } else {
7622 ret = -host_to_target_errno(errno);
7623 }
bellard31e31b82003-02-18 22:55:36 +00007624 }
7625 break;
7626 case TARGET_NR_getsid:
7627 ret = get_errno(getsid(arg1));
7628 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007629#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007630 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007631 ret = get_errno(fdatasync(arg1));
7632 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007633#endif
bellard31e31b82003-02-18 22:55:36 +00007634 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007635 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007636 return value. */
ths0da46a62007-10-20 20:23:07 +00007637 ret = -TARGET_ENOTDIR;
7638 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007639 case TARGET_NR_sched_getaffinity:
7640 {
7641 unsigned int mask_size;
7642 unsigned long *mask;
7643
7644 /*
7645 * sched_getaffinity needs multiples of ulong, so need to take
7646 * care of mismatches between target ulong and host ulong sizes.
7647 */
7648 if (arg2 & (sizeof(abi_ulong) - 1)) {
7649 ret = -TARGET_EINVAL;
7650 break;
7651 }
7652 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7653
7654 mask = alloca(mask_size);
7655 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7656
7657 if (!is_error(ret)) {
Peter Maydellbe3bd282014-05-15 14:40:23 +01007658 if (ret > arg2) {
7659 /* More data returned than the caller's buffer will fit.
7660 * This only happens if sizeof(abi_long) < sizeof(long)
7661 * and the caller passed us a buffer holding an odd number
7662 * of abi_longs. If the host kernel is actually using the
7663 * extra 4 bytes then fail EINVAL; otherwise we can just
7664 * ignore them and only copy the interesting part.
7665 */
7666 int numcpus = sysconf(_SC_NPROCESSORS_CONF);
7667 if (numcpus > arg2 * 8) {
7668 ret = -TARGET_EINVAL;
7669 break;
7670 }
7671 ret = arg2;
7672 }
7673
Mike McCormackcd18f052011-04-18 14:43:36 +09007674 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007675 goto efault;
7676 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007677 }
7678 }
7679 break;
7680 case TARGET_NR_sched_setaffinity:
7681 {
7682 unsigned int mask_size;
7683 unsigned long *mask;
7684
7685 /*
7686 * sched_setaffinity needs multiples of ulong, so need to take
7687 * care of mismatches between target ulong and host ulong sizes.
7688 */
7689 if (arg2 & (sizeof(abi_ulong) - 1)) {
7690 ret = -TARGET_EINVAL;
7691 break;
7692 }
7693 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7694
7695 mask = alloca(mask_size);
7696 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7697 goto efault;
7698 }
7699 memcpy(mask, p, arg2);
7700 unlock_user_struct(p, arg2, 0);
7701
7702 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7703 }
7704 break;
bellard31e31b82003-02-18 22:55:36 +00007705 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007706 {
pbrook53a59602006-03-25 19:31:22 +00007707 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007708 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007709
bellard579a97f2007-11-11 14:26:47 +00007710 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7711 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007712 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007713 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007714 ret = get_errno(sched_setparam(arg1, &schp));
7715 }
7716 break;
bellard31e31b82003-02-18 22:55:36 +00007717 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007718 {
pbrook53a59602006-03-25 19:31:22 +00007719 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007720 struct sched_param schp;
7721 ret = get_errno(sched_getparam(arg1, &schp));
7722 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007723 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7724 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007725 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007726 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007727 }
7728 }
7729 break;
bellard31e31b82003-02-18 22:55:36 +00007730 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007731 {
pbrook53a59602006-03-25 19:31:22 +00007732 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007733 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007734 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7735 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007736 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007737 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007738 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7739 }
7740 break;
bellard31e31b82003-02-18 22:55:36 +00007741 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007742 ret = get_errno(sched_getscheduler(arg1));
7743 break;
bellard31e31b82003-02-18 22:55:36 +00007744 case TARGET_NR_sched_yield:
7745 ret = get_errno(sched_yield());
7746 break;
7747 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007748 ret = get_errno(sched_get_priority_max(arg1));
7749 break;
bellard31e31b82003-02-18 22:55:36 +00007750 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007751 ret = get_errno(sched_get_priority_min(arg1));
7752 break;
bellard31e31b82003-02-18 22:55:36 +00007753 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007754 {
bellard5cd43932003-03-29 16:54:36 +00007755 struct timespec ts;
7756 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7757 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007758 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007759 }
7760 }
7761 break;
bellard31e31b82003-02-18 22:55:36 +00007762 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007763 {
bellard1b6b0292003-03-22 17:31:38 +00007764 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007765 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007766 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007767 if (is_error(ret) && arg2) {
7768 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007769 }
7770 }
7771 break;
thse5febef2007-04-01 18:31:35 +00007772#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007773 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007774 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007775#endif
7776#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007777 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007778 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007779#endif
bellard31e31b82003-02-18 22:55:36 +00007780 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007781 switch (arg1) {
7782 case PR_GET_PDEATHSIG:
7783 {
7784 int deathsig;
7785 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7786 if (!is_error(ret) && arg2
7787 && put_user_ual(deathsig, arg2)) {
7788 goto efault;
thse5574482007-02-11 20:03:13 +00007789 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007790 break;
7791 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007792#ifdef PR_GET_NAME
7793 case PR_GET_NAME:
7794 {
7795 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7796 if (!name) {
7797 goto efault;
7798 }
7799 ret = get_errno(prctl(arg1, (unsigned long)name,
7800 arg3, arg4, arg5));
7801 unlock_user(name, arg2, 16);
7802 break;
7803 }
7804 case PR_SET_NAME:
7805 {
7806 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7807 if (!name) {
7808 goto efault;
7809 }
7810 ret = get_errno(prctl(arg1, (unsigned long)name,
7811 arg3, arg4, arg5));
7812 unlock_user(name, arg2, 0);
7813 break;
7814 }
7815#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007816 default:
7817 /* Most prctl options have no pointer arguments */
7818 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7819 break;
7820 }
ths39b9aae2007-02-11 18:36:44 +00007821 break;
bellardd2fd1af2007-11-14 18:08:56 +00007822#ifdef TARGET_NR_arch_prctl
7823 case TARGET_NR_arch_prctl:
7824#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7825 ret = do_arch_prctl(cpu_env, arg1, arg2);
7826 break;
7827#else
7828 goto unimplemented;
7829#endif
7830#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007831#ifdef TARGET_NR_pread64
7832 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007833 if (regpairs_aligned(cpu_env)) {
7834 arg4 = arg5;
7835 arg5 = arg6;
7836 }
aurel32f2c7ba12008-03-28 22:32:06 +00007837 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7838 goto efault;
7839 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7840 unlock_user(p, arg2, ret);
7841 break;
7842 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007843 if (regpairs_aligned(cpu_env)) {
7844 arg4 = arg5;
7845 arg5 = arg6;
7846 }
aurel32f2c7ba12008-03-28 22:32:06 +00007847 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7848 goto efault;
7849 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7850 unlock_user(p, arg2, 0);
7851 break;
7852#endif
bellard31e31b82003-02-18 22:55:36 +00007853 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007854 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7855 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007856 ret = get_errno(sys_getcwd1(p, arg2));
7857 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007858 break;
7859 case TARGET_NR_capget:
7860 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007861 {
7862 struct target_user_cap_header *target_header;
7863 struct target_user_cap_data *target_data = NULL;
7864 struct __user_cap_header_struct header;
7865 struct __user_cap_data_struct data[2];
7866 struct __user_cap_data_struct *dataptr = NULL;
7867 int i, target_datalen;
7868 int data_items = 1;
7869
7870 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7871 goto efault;
7872 }
7873 header.version = tswap32(target_header->version);
7874 header.pid = tswap32(target_header->pid);
7875
Peter Maydellec864872014-03-19 16:07:30 +00007876 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007877 /* Version 2 and up takes pointer to two user_data structs */
7878 data_items = 2;
7879 }
7880
7881 target_datalen = sizeof(*target_data) * data_items;
7882
7883 if (arg2) {
7884 if (num == TARGET_NR_capget) {
7885 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7886 } else {
7887 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7888 }
7889 if (!target_data) {
7890 unlock_user_struct(target_header, arg1, 0);
7891 goto efault;
7892 }
7893
7894 if (num == TARGET_NR_capset) {
7895 for (i = 0; i < data_items; i++) {
7896 data[i].effective = tswap32(target_data[i].effective);
7897 data[i].permitted = tswap32(target_data[i].permitted);
7898 data[i].inheritable = tswap32(target_data[i].inheritable);
7899 }
7900 }
7901
7902 dataptr = data;
7903 }
7904
7905 if (num == TARGET_NR_capget) {
7906 ret = get_errno(capget(&header, dataptr));
7907 } else {
7908 ret = get_errno(capset(&header, dataptr));
7909 }
7910
7911 /* The kernel always updates version for both capget and capset */
7912 target_header->version = tswap32(header.version);
7913 unlock_user_struct(target_header, arg1, 1);
7914
7915 if (arg2) {
7916 if (num == TARGET_NR_capget) {
7917 for (i = 0; i < data_items; i++) {
7918 target_data[i].effective = tswap32(data[i].effective);
7919 target_data[i].permitted = tswap32(data[i].permitted);
7920 target_data[i].inheritable = tswap32(data[i].inheritable);
7921 }
7922 unlock_user(target_data, arg2, target_datalen);
7923 } else {
7924 unlock_user(target_data, arg2, 0);
7925 }
7926 }
7927 break;
7928 }
bellard31e31b82003-02-18 22:55:36 +00007929 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007930#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007931 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007932 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007933 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007934 break;
7935#else
bellard5cd43932003-03-29 16:54:36 +00007936 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007937#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007938
7939#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007940 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007941 {
7942 off_t *offp = NULL;
7943 off_t off;
7944 if (arg3) {
7945 ret = get_user_sal(off, arg3);
7946 if (is_error(ret)) {
7947 break;
7948 }
7949 offp = &off;
7950 }
7951 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7952 if (!is_error(ret) && arg3) {
7953 abi_long ret2 = put_user_sal(off, arg3);
7954 if (is_error(ret2)) {
7955 ret = ret2;
7956 }
7957 }
7958 break;
7959 }
7960#ifdef TARGET_NR_sendfile64
7961 case TARGET_NR_sendfile64:
7962 {
7963 off_t *offp = NULL;
7964 off_t off;
7965 if (arg3) {
7966 ret = get_user_s64(off, arg3);
7967 if (is_error(ret)) {
7968 break;
7969 }
7970 offp = &off;
7971 }
7972 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7973 if (!is_error(ret) && arg3) {
7974 abi_long ret2 = put_user_s64(off, arg3);
7975 if (is_error(ret2)) {
7976 ret = ret2;
7977 }
7978 }
7979 break;
7980 }
7981#endif
7982#else
7983 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007984#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007985 case TARGET_NR_sendfile64:
7986#endif
bellard5cd43932003-03-29 16:54:36 +00007987 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007988#endif
7989
bellardebc05482003-09-30 21:08:41 +00007990#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007991 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007992 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007993#endif
7994#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007995 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007996 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007997#endif
bellard048f6b42005-11-26 18:47:20 +00007998#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007999 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00008000 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
8001 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00008002 break;
bellard048f6b42005-11-26 18:47:20 +00008003#endif
bellardebc05482003-09-30 21:08:41 +00008004#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00008005 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00008006 {
8007 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03008008 int resource = target_to_host_resource(arg1);
8009 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00008010 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00008011 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00008012 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
8013 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09008014 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
8015 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00008016 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00008017 }
8018 break;
8019 }
bellardebc05482003-09-30 21:08:41 +00008020#endif
bellarda315a142005-01-30 22:59:18 +00008021#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00008022 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00008023 if (!(p = lock_user_string(arg1)))
8024 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008025 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
8026 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00008027 break;
bellarda315a142005-01-30 22:59:18 +00008028#endif
8029#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00008030 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00008031 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00008032 break;
bellarda315a142005-01-30 22:59:18 +00008033#endif
8034#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00008035 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00008036 if (!(p = lock_user_string(arg1)))
8037 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008038 ret = get_errno(stat(path(p), &st));
8039 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008040 if (!is_error(ret))
8041 ret = host_to_target_stat64(cpu_env, arg2, &st);
8042 break;
bellarda315a142005-01-30 22:59:18 +00008043#endif
8044#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00008045 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00008046 if (!(p = lock_user_string(arg1)))
8047 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008048 ret = get_errno(lstat(path(p), &st));
8049 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00008050 if (!is_error(ret))
8051 ret = host_to_target_stat64(cpu_env, arg2, &st);
8052 break;
bellarda315a142005-01-30 22:59:18 +00008053#endif
8054#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00008055 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00008056 ret = get_errno(fstat(arg1, &st));
8057 if (!is_error(ret))
8058 ret = host_to_target_stat64(cpu_env, arg2, &st);
8059 break;
bellardec86b0f2003-04-11 00:15:04 +00008060#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01008061#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00008062#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00008063 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00008064#endif
8065#ifdef TARGET_NR_newfstatat
8066 case TARGET_NR_newfstatat:
8067#endif
balrog6a24a772008-09-20 02:23:36 +00008068 if (!(p = lock_user_string(arg2)))
8069 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008070 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00008071 if (!is_error(ret))
8072 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00008073 break;
bellarda315a142005-01-30 22:59:18 +00008074#endif
bellard67867302003-11-23 17:05:30 +00008075 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00008076 if (!(p = lock_user_string(arg1)))
8077 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008078 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
8079 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008080 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008081#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00008082 case TARGET_NR_getuid:
8083 ret = get_errno(high2lowuid(getuid()));
8084 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008085#endif
8086#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00008087 case TARGET_NR_getgid:
8088 ret = get_errno(high2lowgid(getgid()));
8089 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008090#endif
8091#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00008092 case TARGET_NR_geteuid:
8093 ret = get_errno(high2lowuid(geteuid()));
8094 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008095#endif
8096#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00008097 case TARGET_NR_getegid:
8098 ret = get_errno(high2lowgid(getegid()));
8099 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03008100#endif
bellard67867302003-11-23 17:05:30 +00008101 case TARGET_NR_setreuid:
8102 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
8103 break;
8104 case TARGET_NR_setregid:
8105 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
8106 break;
8107 case TARGET_NR_getgroups:
8108 {
8109 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008110 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00008111 gid_t *grouplist;
8112 int i;
8113
8114 grouplist = alloca(gidsetsize * sizeof(gid_t));
8115 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008116 if (gidsetsize == 0)
8117 break;
bellard67867302003-11-23 17:05:30 +00008118 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00008119 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00008120 if (!target_grouplist)
8121 goto efault;
balroga2155fc2008-09-20 02:12:08 +00008122 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03008123 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008124 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00008125 }
8126 }
8127 break;
8128 case TARGET_NR_setgroups:
8129 {
8130 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03008131 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008132 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00008133 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008134 if (gidsetsize) {
8135 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008136 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008137 if (!target_grouplist) {
8138 ret = -TARGET_EFAULT;
8139 goto fail;
8140 }
8141 for (i = 0; i < gidsetsize; i++) {
8142 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8143 }
8144 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008145 }
bellard67867302003-11-23 17:05:30 +00008146 ret = get_errno(setgroups(gidsetsize, grouplist));
8147 }
8148 break;
8149 case TARGET_NR_fchown:
8150 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8151 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008152#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008153 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008154 if (!(p = lock_user_string(arg2)))
8155 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008156 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8157 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008158 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008159 break;
8160#endif
bellard67867302003-11-23 17:05:30 +00008161#ifdef TARGET_NR_setresuid
8162 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008163 ret = get_errno(setresuid(low2highuid(arg1),
8164 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008165 low2highuid(arg3)));
8166 break;
8167#endif
8168#ifdef TARGET_NR_getresuid
8169 case TARGET_NR_getresuid:
8170 {
pbrook53a59602006-03-25 19:31:22 +00008171 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008172 ret = get_errno(getresuid(&ruid, &euid, &suid));
8173 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008174 if (put_user_id(high2lowuid(ruid), arg1)
8175 || put_user_id(high2lowuid(euid), arg2)
8176 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008177 goto efault;
bellard67867302003-11-23 17:05:30 +00008178 }
8179 }
8180 break;
8181#endif
8182#ifdef TARGET_NR_getresgid
8183 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008184 ret = get_errno(setresgid(low2highgid(arg1),
8185 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008186 low2highgid(arg3)));
8187 break;
8188#endif
8189#ifdef TARGET_NR_getresgid
8190 case TARGET_NR_getresgid:
8191 {
pbrook53a59602006-03-25 19:31:22 +00008192 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008193 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8194 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008195 if (put_user_id(high2lowgid(rgid), arg1)
8196 || put_user_id(high2lowgid(egid), arg2)
8197 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008198 goto efault;
bellard67867302003-11-23 17:05:30 +00008199 }
8200 }
8201 break;
8202#endif
8203 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008204 if (!(p = lock_user_string(arg1)))
8205 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008206 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8207 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008208 break;
8209 case TARGET_NR_setuid:
8210 ret = get_errno(setuid(low2highuid(arg1)));
8211 break;
8212 case TARGET_NR_setgid:
8213 ret = get_errno(setgid(low2highgid(arg1)));
8214 break;
8215 case TARGET_NR_setfsuid:
8216 ret = get_errno(setfsuid(arg1));
8217 break;
8218 case TARGET_NR_setfsgid:
8219 ret = get_errno(setfsgid(arg1));
8220 break;
bellard67867302003-11-23 17:05:30 +00008221
bellarda315a142005-01-30 22:59:18 +00008222#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008223 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008224 if (!(p = lock_user_string(arg1)))
8225 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008226 ret = get_errno(lchown(p, arg2, arg3));
8227 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008228 break;
bellarda315a142005-01-30 22:59:18 +00008229#endif
8230#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008231 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008232 ret = get_errno(getuid());
8233 break;
bellarda315a142005-01-30 22:59:18 +00008234#endif
aurel3264b4d282008-11-14 17:20:15 +00008235
8236#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8237 /* Alpha specific */
8238 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008239 {
8240 uid_t euid;
8241 euid=geteuid();
8242 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8243 }
aurel3264b4d282008-11-14 17:20:15 +00008244 ret = get_errno(getuid());
8245 break;
8246#endif
8247#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8248 /* Alpha specific */
8249 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008250 {
8251 uid_t egid;
8252 egid=getegid();
8253 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8254 }
aurel3264b4d282008-11-14 17:20:15 +00008255 ret = get_errno(getgid());
8256 break;
8257#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008258#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8259 /* Alpha specific */
8260 case TARGET_NR_osf_getsysinfo:
8261 ret = -TARGET_EOPNOTSUPP;
8262 switch (arg1) {
8263 case TARGET_GSI_IEEE_FP_CONTROL:
8264 {
8265 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8266
8267 /* Copied from linux ieee_fpcr_to_swcr. */
8268 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8269 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8270 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8271 | SWCR_TRAP_ENABLE_DZE
8272 | SWCR_TRAP_ENABLE_OVF);
8273 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8274 | SWCR_TRAP_ENABLE_INE);
8275 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8276 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8277
8278 if (put_user_u64 (swcr, arg2))
8279 goto efault;
8280 ret = 0;
8281 }
8282 break;
8283
8284 /* case GSI_IEEE_STATE_AT_SIGNAL:
8285 -- Not implemented in linux kernel.
8286 case GSI_UACPROC:
8287 -- Retrieves current unaligned access state; not much used.
8288 case GSI_PROC_TYPE:
8289 -- Retrieves implver information; surely not used.
8290 case GSI_GET_HWRPB:
8291 -- Grabs a copy of the HWRPB; surely not used.
8292 */
8293 }
8294 break;
8295#endif
8296#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8297 /* Alpha specific */
8298 case TARGET_NR_osf_setsysinfo:
8299 ret = -TARGET_EOPNOTSUPP;
8300 switch (arg1) {
8301 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008302 {
8303 uint64_t swcr, fpcr, orig_fpcr;
8304
Richard Henderson6e06d512012-06-01 09:08:21 -07008305 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008306 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008307 }
8308 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008309 fpcr = orig_fpcr & FPCR_DYN_MASK;
8310
8311 /* Copied from linux ieee_swcr_to_fpcr. */
8312 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8313 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8314 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8315 | SWCR_TRAP_ENABLE_DZE
8316 | SWCR_TRAP_ENABLE_OVF)) << 48;
8317 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8318 | SWCR_TRAP_ENABLE_INE)) << 57;
8319 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8320 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8321
Richard Henderson6e06d512012-06-01 09:08:21 -07008322 cpu_alpha_store_fpcr(cpu_env, fpcr);
8323 ret = 0;
8324 }
8325 break;
8326
8327 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8328 {
8329 uint64_t exc, fpcr, orig_fpcr;
8330 int si_code;
8331
8332 if (get_user_u64(exc, arg2)) {
8333 goto efault;
8334 }
8335
8336 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8337
8338 /* We only add to the exception status here. */
8339 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8340
8341 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008342 ret = 0;
8343
Richard Henderson6e06d512012-06-01 09:08:21 -07008344 /* Old exceptions are not signaled. */
8345 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008346
Richard Henderson6e06d512012-06-01 09:08:21 -07008347 /* If any exceptions set by this call,
8348 and are unmasked, send a signal. */
8349 si_code = 0;
8350 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8351 si_code = TARGET_FPE_FLTRES;
8352 }
8353 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8354 si_code = TARGET_FPE_FLTUND;
8355 }
8356 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8357 si_code = TARGET_FPE_FLTOVF;
8358 }
8359 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8360 si_code = TARGET_FPE_FLTDIV;
8361 }
8362 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8363 si_code = TARGET_FPE_FLTINV;
8364 }
8365 if (si_code != 0) {
8366 target_siginfo_t info;
8367 info.si_signo = SIGFPE;
8368 info.si_errno = 0;
8369 info.si_code = si_code;
8370 info._sifields._sigfault._addr
8371 = ((CPUArchState *)cpu_env)->pc;
8372 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008373 }
8374 }
8375 break;
8376
8377 /* case SSI_NVPAIRS:
8378 -- Used with SSIN_UACPROC to enable unaligned accesses.
8379 case SSI_IEEE_STATE_AT_SIGNAL:
8380 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8381 -- Not implemented in linux kernel
8382 */
8383 }
8384 break;
8385#endif
8386#ifdef TARGET_NR_osf_sigprocmask
8387 /* Alpha specific. */
8388 case TARGET_NR_osf_sigprocmask:
8389 {
8390 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008391 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008392 sigset_t set, oldset;
8393
8394 switch(arg1) {
8395 case TARGET_SIG_BLOCK:
8396 how = SIG_BLOCK;
8397 break;
8398 case TARGET_SIG_UNBLOCK:
8399 how = SIG_UNBLOCK;
8400 break;
8401 case TARGET_SIG_SETMASK:
8402 how = SIG_SETMASK;
8403 break;
8404 default:
8405 ret = -TARGET_EINVAL;
8406 goto fail;
8407 }
8408 mask = arg2;
8409 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008410 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008411 host_to_target_old_sigset(&mask, &oldset);
8412 ret = mask;
8413 }
8414 break;
8415#endif
aurel3264b4d282008-11-14 17:20:15 +00008416
bellarda315a142005-01-30 22:59:18 +00008417#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008418 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008419 ret = get_errno(getgid());
8420 break;
bellarda315a142005-01-30 22:59:18 +00008421#endif
8422#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008423 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008424 ret = get_errno(geteuid());
8425 break;
bellarda315a142005-01-30 22:59:18 +00008426#endif
8427#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008428 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008429 ret = get_errno(getegid());
8430 break;
bellarda315a142005-01-30 22:59:18 +00008431#endif
8432#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008433 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008434 ret = get_errno(setreuid(arg1, arg2));
8435 break;
bellarda315a142005-01-30 22:59:18 +00008436#endif
8437#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008438 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008439 ret = get_errno(setregid(arg1, arg2));
8440 break;
bellarda315a142005-01-30 22:59:18 +00008441#endif
8442#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008443 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008444 {
8445 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008446 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008447 gid_t *grouplist;
8448 int i;
8449
8450 grouplist = alloca(gidsetsize * sizeof(gid_t));
8451 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008452 if (gidsetsize == 0)
8453 break;
bellard99c475a2005-01-31 20:45:13 +00008454 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008455 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8456 if (!target_grouplist) {
8457 ret = -TARGET_EFAULT;
8458 goto fail;
8459 }
balroga2155fc2008-09-20 02:12:08 +00008460 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008461 target_grouplist[i] = tswap32(grouplist[i]);
8462 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008463 }
8464 }
8465 break;
bellarda315a142005-01-30 22:59:18 +00008466#endif
8467#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008468 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008469 {
8470 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008471 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008472 gid_t *grouplist;
8473 int i;
ths3b46e622007-09-17 08:09:54 +00008474
bellard99c475a2005-01-31 20:45:13 +00008475 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008476 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8477 if (!target_grouplist) {
8478 ret = -TARGET_EFAULT;
8479 goto fail;
8480 }
bellard99c475a2005-01-31 20:45:13 +00008481 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008482 grouplist[i] = tswap32(target_grouplist[i]);
8483 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008484 ret = get_errno(setgroups(gidsetsize, grouplist));
8485 }
8486 break;
bellarda315a142005-01-30 22:59:18 +00008487#endif
8488#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008489 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008490 ret = get_errno(fchown(arg1, arg2, arg3));
8491 break;
bellarda315a142005-01-30 22:59:18 +00008492#endif
8493#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008494 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008495 ret = get_errno(setresuid(arg1, arg2, arg3));
8496 break;
bellarda315a142005-01-30 22:59:18 +00008497#endif
8498#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008499 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008500 {
pbrook53a59602006-03-25 19:31:22 +00008501 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008502 ret = get_errno(getresuid(&ruid, &euid, &suid));
8503 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008504 if (put_user_u32(ruid, arg1)
8505 || put_user_u32(euid, arg2)
8506 || put_user_u32(suid, arg3))
8507 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008508 }
8509 }
8510 break;
bellarda315a142005-01-30 22:59:18 +00008511#endif
8512#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008513 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008514 ret = get_errno(setresgid(arg1, arg2, arg3));
8515 break;
bellarda315a142005-01-30 22:59:18 +00008516#endif
8517#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008518 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008519 {
pbrook53a59602006-03-25 19:31:22 +00008520 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008521 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8522 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008523 if (put_user_u32(rgid, arg1)
8524 || put_user_u32(egid, arg2)
8525 || put_user_u32(sgid, arg3))
8526 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008527 }
8528 }
8529 break;
bellarda315a142005-01-30 22:59:18 +00008530#endif
8531#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008532 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008533 if (!(p = lock_user_string(arg1)))
8534 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008535 ret = get_errno(chown(p, arg2, arg3));
8536 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008537 break;
bellarda315a142005-01-30 22:59:18 +00008538#endif
8539#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008540 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008541 ret = get_errno(setuid(arg1));
8542 break;
bellarda315a142005-01-30 22:59:18 +00008543#endif
8544#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008545 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008546 ret = get_errno(setgid(arg1));
8547 break;
bellarda315a142005-01-30 22:59:18 +00008548#endif
8549#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008550 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008551 ret = get_errno(setfsuid(arg1));
8552 break;
bellarda315a142005-01-30 22:59:18 +00008553#endif
8554#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008555 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008556 ret = get_errno(setfsgid(arg1));
8557 break;
bellarda315a142005-01-30 22:59:18 +00008558#endif
bellard67867302003-11-23 17:05:30 +00008559
bellard31e31b82003-02-18 22:55:36 +00008560 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008561 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008562#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008563 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008564 {
8565 void *a;
8566 ret = -TARGET_EFAULT;
8567 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8568 goto efault;
8569 if (!(p = lock_user_string(arg3)))
8570 goto mincore_fail;
8571 ret = get_errno(mincore(a, arg2, p));
8572 unlock_user(p, arg3, ret);
8573 mincore_fail:
8574 unlock_user(a, arg1, 0);
8575 }
8576 break;
bellardffa65c32004-01-04 23:57:22 +00008577#endif
aurel32408321b2008-10-01 21:46:32 +00008578#ifdef TARGET_NR_arm_fadvise64_64
8579 case TARGET_NR_arm_fadvise64_64:
8580 {
8581 /*
8582 * arm_fadvise64_64 looks like fadvise64_64 but
8583 * with different argument order
8584 */
8585 abi_long temp;
8586 temp = arg3;
8587 arg3 = arg4;
8588 arg4 = temp;
8589 }
8590#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008591#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008592#ifdef TARGET_NR_fadvise64_64
8593 case TARGET_NR_fadvise64_64:
8594#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008595#ifdef TARGET_NR_fadvise64
8596 case TARGET_NR_fadvise64:
8597#endif
8598#ifdef TARGET_S390X
8599 switch (arg4) {
8600 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8601 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8602 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8603 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8604 default: break;
8605 }
8606#endif
8607 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008608 break;
8609#endif
bellardffa65c32004-01-04 23:57:22 +00008610#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008611 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008612 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008613 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008614 This will break MADV_DONTNEED.
8615 This is a hint, so ignoring and returning success is ok. */
8616 ret = get_errno(0);
8617 break;
bellardffa65c32004-01-04 23:57:22 +00008618#endif
blueswir1992f48a2007-10-14 16:27:31 +00008619#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008620 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008621 {
thsb1e341e2007-03-20 21:50:52 +00008622 int cmd;
bellard77e46722003-04-29 20:39:06 +00008623 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008624 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008625#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008626 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008627#endif
bellard77e46722003-04-29 20:39:06 +00008628
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008629 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008630 if (cmd == -TARGET_EINVAL) {
8631 ret = cmd;
8632 break;
8633 }
thsb1e341e2007-03-20 21:50:52 +00008634
bellard60cd49d2003-03-16 22:53:56 +00008635 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008636 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008637#ifdef TARGET_ARM
8638 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008639 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8640 goto efault;
ths58134272007-03-31 18:59:32 +00008641 fl.l_type = tswap16(target_efl->l_type);
8642 fl.l_whence = tswap16(target_efl->l_whence);
8643 fl.l_start = tswap64(target_efl->l_start);
8644 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008645 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008646 unlock_user_struct(target_efl, arg3, 0);
8647 } else
8648#endif
8649 {
bellard9ee1fa22007-11-11 15:11:19 +00008650 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8651 goto efault;
ths58134272007-03-31 18:59:32 +00008652 fl.l_type = tswap16(target_fl->l_type);
8653 fl.l_whence = tswap16(target_fl->l_whence);
8654 fl.l_start = tswap64(target_fl->l_start);
8655 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008656 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008657 unlock_user_struct(target_fl, arg3, 0);
8658 }
thsb1e341e2007-03-20 21:50:52 +00008659 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008660 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008661#ifdef TARGET_ARM
8662 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008663 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8664 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008665 target_efl->l_type = tswap16(fl.l_type);
8666 target_efl->l_whence = tswap16(fl.l_whence);
8667 target_efl->l_start = tswap64(fl.l_start);
8668 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008669 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008670 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008671 } else
8672#endif
8673 {
bellard9ee1fa22007-11-11 15:11:19 +00008674 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8675 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008676 target_fl->l_type = tswap16(fl.l_type);
8677 target_fl->l_whence = tswap16(fl.l_whence);
8678 target_fl->l_start = tswap64(fl.l_start);
8679 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008680 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008681 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008682 }
bellard77e46722003-04-29 20:39:06 +00008683 }
8684 break;
8685
thsb1e341e2007-03-20 21:50:52 +00008686 case TARGET_F_SETLK64:
8687 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008688#ifdef TARGET_ARM
8689 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008690 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8691 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008692 fl.l_type = tswap16(target_efl->l_type);
8693 fl.l_whence = tswap16(target_efl->l_whence);
8694 fl.l_start = tswap64(target_efl->l_start);
8695 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008696 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008697 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008698 } else
8699#endif
8700 {
bellard9ee1fa22007-11-11 15:11:19 +00008701 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8702 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008703 fl.l_type = tswap16(target_fl->l_type);
8704 fl.l_whence = tswap16(target_fl->l_whence);
8705 fl.l_start = tswap64(target_fl->l_start);
8706 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008707 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008708 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008709 }
thsb1e341e2007-03-20 21:50:52 +00008710 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008711 break;
bellard60cd49d2003-03-16 22:53:56 +00008712 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008713 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008714 break;
8715 }
bellard77e46722003-04-29 20:39:06 +00008716 break;
8717 }
bellard60cd49d2003-03-16 22:53:56 +00008718#endif
ths7d600c82006-12-08 01:32:58 +00008719#ifdef TARGET_NR_cacheflush
8720 case TARGET_NR_cacheflush:
8721 /* self-modifying code is handled automatically, so nothing needed */
8722 ret = 0;
8723 break;
8724#endif
bellardebc05482003-09-30 21:08:41 +00008725#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008726 case TARGET_NR_security:
8727 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008728#endif
bellardc573ff62004-01-04 15:51:36 +00008729#ifdef TARGET_NR_getpagesize
8730 case TARGET_NR_getpagesize:
8731 ret = TARGET_PAGE_SIZE;
8732 break;
8733#endif
bellard31e31b82003-02-18 22:55:36 +00008734 case TARGET_NR_gettid:
8735 ret = get_errno(gettid());
8736 break;
thse5febef2007-04-01 18:31:35 +00008737#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008738 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008739#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008740 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008741 arg2 = arg3;
8742 arg3 = arg4;
8743 arg4 = arg5;
8744 }
aurel322054ac92008-10-13 21:08:07 +00008745 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8746#else
8747 ret = get_errno(readahead(arg1, arg2, arg3));
8748#endif
8749 break;
thse5febef2007-04-01 18:31:35 +00008750#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008751#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008752#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008753 case TARGET_NR_listxattr:
8754 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008755 {
8756 void *p, *b = 0;
8757 if (arg2) {
8758 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8759 if (!b) {
8760 ret = -TARGET_EFAULT;
8761 break;
8762 }
8763 }
8764 p = lock_user_string(arg1);
8765 if (p) {
8766 if (num == TARGET_NR_listxattr) {
8767 ret = get_errno(listxattr(p, b, arg3));
8768 } else {
8769 ret = get_errno(llistxattr(p, b, arg3));
8770 }
8771 } else {
8772 ret = -TARGET_EFAULT;
8773 }
8774 unlock_user(p, arg1, 0);
8775 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008776 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008777 }
8778 case TARGET_NR_flistxattr:
8779 {
8780 void *b = 0;
8781 if (arg2) {
8782 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8783 if (!b) {
8784 ret = -TARGET_EFAULT;
8785 break;
8786 }
8787 }
8788 ret = get_errno(flistxattr(arg1, b, arg3));
8789 unlock_user(b, arg2, arg3);
8790 break;
8791 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008792 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008793 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008794 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008795 void *p, *n, *v = 0;
8796 if (arg3) {
8797 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8798 if (!v) {
8799 ret = -TARGET_EFAULT;
8800 break;
8801 }
8802 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008803 p = lock_user_string(arg1);
8804 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008805 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008806 if (num == TARGET_NR_setxattr) {
8807 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8808 } else {
8809 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8810 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008811 } else {
8812 ret = -TARGET_EFAULT;
8813 }
8814 unlock_user(p, arg1, 0);
8815 unlock_user(n, arg2, 0);
8816 unlock_user(v, arg3, 0);
8817 }
8818 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008819 case TARGET_NR_fsetxattr:
8820 {
8821 void *n, *v = 0;
8822 if (arg3) {
8823 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8824 if (!v) {
8825 ret = -TARGET_EFAULT;
8826 break;
8827 }
8828 }
8829 n = lock_user_string(arg2);
8830 if (n) {
8831 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8832 } else {
8833 ret = -TARGET_EFAULT;
8834 }
8835 unlock_user(n, arg2, 0);
8836 unlock_user(v, arg3, 0);
8837 }
8838 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008839 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008840 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008841 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008842 void *p, *n, *v = 0;
8843 if (arg3) {
8844 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8845 if (!v) {
8846 ret = -TARGET_EFAULT;
8847 break;
8848 }
8849 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008850 p = lock_user_string(arg1);
8851 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008852 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008853 if (num == TARGET_NR_getxattr) {
8854 ret = get_errno(getxattr(p, n, v, arg4));
8855 } else {
8856 ret = get_errno(lgetxattr(p, n, v, arg4));
8857 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008858 } else {
8859 ret = -TARGET_EFAULT;
8860 }
8861 unlock_user(p, arg1, 0);
8862 unlock_user(n, arg2, 0);
8863 unlock_user(v, arg3, arg4);
8864 }
8865 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008866 case TARGET_NR_fgetxattr:
8867 {
8868 void *n, *v = 0;
8869 if (arg3) {
8870 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8871 if (!v) {
8872 ret = -TARGET_EFAULT;
8873 break;
8874 }
8875 }
8876 n = lock_user_string(arg2);
8877 if (n) {
8878 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8879 } else {
8880 ret = -TARGET_EFAULT;
8881 }
8882 unlock_user(n, arg2, 0);
8883 unlock_user(v, arg3, arg4);
8884 }
8885 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008886 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008887 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008888 {
8889 void *p, *n;
8890 p = lock_user_string(arg1);
8891 n = lock_user_string(arg2);
8892 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008893 if (num == TARGET_NR_removexattr) {
8894 ret = get_errno(removexattr(p, n));
8895 } else {
8896 ret = get_errno(lremovexattr(p, n));
8897 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008898 } else {
8899 ret = -TARGET_EFAULT;
8900 }
8901 unlock_user(p, arg1, 0);
8902 unlock_user(n, arg2, 0);
8903 }
8904 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008905 case TARGET_NR_fremovexattr:
8906 {
8907 void *n;
8908 n = lock_user_string(arg2);
8909 if (n) {
8910 ret = get_errno(fremovexattr(arg1, n));
8911 } else {
8912 ret = -TARGET_EFAULT;
8913 }
8914 unlock_user(n, arg2, 0);
8915 }
8916 break;
bellardebc05482003-09-30 21:08:41 +00008917#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008918#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008919#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008920 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008921#if defined(TARGET_MIPS)
Petar Jovanovicd2792792014-06-18 17:48:20 +02008922 ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
ths6f5b89a2007-03-02 20:48:00 +00008923 ret = 0;
8924 break;
edgar_iglef967792009-01-07 14:19:38 +00008925#elif defined(TARGET_CRIS)
8926 if (arg1 & 0xff)
8927 ret = -TARGET_EINVAL;
8928 else {
8929 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8930 ret = 0;
8931 }
8932 break;
bellard8d18e892007-11-14 15:18:40 +00008933#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8934 ret = do_set_thread_area(cpu_env, arg1);
8935 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008936#elif defined(TARGET_M68K)
8937 {
Andreas Färber0429a972013-08-26 18:14:44 +02008938 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008939 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008940 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008941 break;
8942 }
ths6f5b89a2007-03-02 20:48:00 +00008943#else
8944 goto unimplemented_nowarn;
8945#endif
8946#endif
8947#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008948 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008949#if defined(TARGET_I386) && defined(TARGET_ABI32)
8950 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008951 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008952#elif defined(TARGET_M68K)
8953 {
Andreas Färber0429a972013-08-26 18:14:44 +02008954 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008955 ret = ts->tp_value;
8956 break;
8957 }
bellard8d18e892007-11-14 15:18:40 +00008958#else
bellard5cd43932003-03-29 16:54:36 +00008959 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008960#endif
bellard8d18e892007-11-14 15:18:40 +00008961#endif
bellard48dc41e2006-06-21 18:15:50 +00008962#ifdef TARGET_NR_getdomainname
8963 case TARGET_NR_getdomainname:
8964 goto unimplemented_nowarn;
8965#endif
ths6f5b89a2007-03-02 20:48:00 +00008966
thsb5906f92007-03-19 13:32:45 +00008967#ifdef TARGET_NR_clock_gettime
8968 case TARGET_NR_clock_gettime:
8969 {
8970 struct timespec ts;
8971 ret = get_errno(clock_gettime(arg1, &ts));
8972 if (!is_error(ret)) {
8973 host_to_target_timespec(arg2, &ts);
8974 }
8975 break;
8976 }
8977#endif
8978#ifdef TARGET_NR_clock_getres
8979 case TARGET_NR_clock_getres:
8980 {
8981 struct timespec ts;
8982 ret = get_errno(clock_getres(arg1, &ts));
8983 if (!is_error(ret)) {
8984 host_to_target_timespec(arg2, &ts);
8985 }
8986 break;
8987 }
8988#endif
pbrook63d76512008-05-29 13:43:29 +00008989#ifdef TARGET_NR_clock_nanosleep
8990 case TARGET_NR_clock_nanosleep:
8991 {
8992 struct timespec ts;
8993 target_to_host_timespec(&ts, arg3);
8994 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8995 if (arg4)
8996 host_to_target_timespec(arg4, &ts);
8997 break;
8998 }
8999#endif
thsb5906f92007-03-19 13:32:45 +00009000
ths6f5b89a2007-03-02 20:48:00 +00009001#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
9002 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00009003 ret = get_errno(set_tid_address((int *)g2h(arg1)));
9004 break;
ths6f5b89a2007-03-02 20:48:00 +00009005#endif
9006
ths3ae43202007-09-16 21:39:48 +00009007#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00009008 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00009009 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00009010 break;
9011#endif
9012
ths3ae43202007-09-16 21:39:48 +00009013#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00009014 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00009015 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
9016 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00009017 break;
9018#endif
9019
ths4f2b1fe2007-06-21 21:57:12 +00009020#ifdef TARGET_NR_set_robust_list
9021 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00009022 case TARGET_NR_get_robust_list:
9023 /* The ABI for supporting robust futexes has userspace pass
9024 * the kernel a pointer to a linked list which is updated by
9025 * userspace after the syscall; the list is walked by the kernel
9026 * when the thread exits. Since the linked list in QEMU guest
9027 * memory isn't a valid linked list for the host and we have
9028 * no way to reliably intercept the thread-death event, we can't
9029 * support these. Silently return ENOSYS so that guest userspace
9030 * falls back to a non-robust futex implementation (which should
9031 * be OK except in the corner case of the guest crashing while
9032 * holding a mutex that is shared with another process via
9033 * shared memory).
9034 */
9035 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00009036#endif
9037
Peter Maydell1acae9f2013-07-02 14:04:12 +01009038#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00009039 case TARGET_NR_utimensat:
9040 {
Riku Voipioebc996f2009-04-21 15:01:51 +03009041 struct timespec *tsp, ts[2];
9042 if (!arg3) {
9043 tsp = NULL;
9044 } else {
9045 target_to_host_timespec(ts, arg3);
9046 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
9047 tsp = ts;
9048 }
ths9007f0e2007-09-25 17:50:37 +00009049 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03009050 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00009051 else {
bellard579a97f2007-11-11 14:26:47 +00009052 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00009053 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00009054 goto fail;
9055 }
Riku Voipioebc996f2009-04-21 15:01:51 +03009056 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00009057 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00009058 }
9059 }
9060 break;
9061#endif
pbrookbd0c5662008-05-29 14:34:11 +00009062 case TARGET_NR_futex:
9063 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
9064 break;
aurel32dbfe4c32009-04-08 21:29:30 +00009065#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00009066 case TARGET_NR_inotify_init:
9067 ret = get_errno(sys_inotify_init());
9068 break;
9069#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009070#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00009071#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
9072 case TARGET_NR_inotify_init1:
9073 ret = get_errno(sys_inotify_init1(arg1));
9074 break;
9075#endif
Stefan Weila1606b02010-03-28 11:44:41 +02009076#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009077#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00009078 case TARGET_NR_inotify_add_watch:
9079 p = lock_user_string(arg2);
9080 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
9081 unlock_user(p, arg2, 0);
9082 break;
9083#endif
aurel32dbfe4c32009-04-08 21:29:30 +00009084#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00009085 case TARGET_NR_inotify_rm_watch:
9086 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
9087 break;
9088#endif
ths9007f0e2007-09-25 17:50:37 +00009089
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07009090#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00009091 case TARGET_NR_mq_open:
9092 {
9093 struct mq_attr posix_mq_attr;
9094
9095 p = lock_user_string(arg1 - 1);
9096 if (arg4 != 0)
9097 copy_from_user_mq_attr (&posix_mq_attr, arg4);
9098 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
9099 unlock_user (p, arg1, 0);
9100 }
9101 break;
9102
9103 case TARGET_NR_mq_unlink:
9104 p = lock_user_string(arg1 - 1);
9105 ret = get_errno(mq_unlink(p));
9106 unlock_user (p, arg1, 0);
9107 break;
9108
9109 case TARGET_NR_mq_timedsend:
9110 {
9111 struct timespec ts;
9112
9113 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9114 if (arg5 != 0) {
9115 target_to_host_timespec(&ts, arg5);
9116 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
9117 host_to_target_timespec(arg5, &ts);
9118 }
9119 else
9120 ret = get_errno(mq_send(arg1, p, arg3, arg4));
9121 unlock_user (p, arg2, arg3);
9122 }
9123 break;
9124
9125 case TARGET_NR_mq_timedreceive:
9126 {
9127 struct timespec ts;
9128 unsigned int prio;
9129
9130 p = lock_user (VERIFY_READ, arg2, arg3, 1);
9131 if (arg5 != 0) {
9132 target_to_host_timespec(&ts, arg5);
9133 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
9134 host_to_target_timespec(arg5, &ts);
9135 }
9136 else
9137 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9138 unlock_user (p, arg2, arg3);
9139 if (arg4 != 0)
9140 put_user_u32(prio, arg4);
9141 }
9142 break;
9143
9144 /* Not implemented for now... */
9145/* case TARGET_NR_mq_notify: */
9146/* break; */
9147
9148 case TARGET_NR_mq_getsetattr:
9149 {
9150 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9151 ret = 0;
9152 if (arg3 != 0) {
9153 ret = mq_getattr(arg1, &posix_mq_attr_out);
9154 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9155 }
9156 if (arg2 != 0) {
9157 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9158 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9159 }
9160
9161 }
9162 break;
9163#endif
9164
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309165#ifdef CONFIG_SPLICE
9166#ifdef TARGET_NR_tee
9167 case TARGET_NR_tee:
9168 {
9169 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9170 }
9171 break;
9172#endif
9173#ifdef TARGET_NR_splice
9174 case TARGET_NR_splice:
9175 {
9176 loff_t loff_in, loff_out;
9177 loff_t *ploff_in = NULL, *ploff_out = NULL;
9178 if(arg2) {
9179 get_user_u64(loff_in, arg2);
9180 ploff_in = &loff_in;
9181 }
9182 if(arg4) {
9183 get_user_u64(loff_out, arg2);
9184 ploff_out = &loff_out;
9185 }
9186 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9187 }
9188 break;
9189#endif
9190#ifdef TARGET_NR_vmsplice
9191 case TARGET_NR_vmsplice:
9192 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009193 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9194 if (vec != NULL) {
9195 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9196 unlock_iovec(vec, arg2, arg3, 0);
9197 } else {
9198 ret = -host_to_target_errno(errno);
9199 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309200 }
9201 break;
9202#endif
9203#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009204#ifdef CONFIG_EVENTFD
9205#if defined(TARGET_NR_eventfd)
9206 case TARGET_NR_eventfd:
9207 ret = get_errno(eventfd(arg1, 0));
9208 break;
9209#endif
9210#if defined(TARGET_NR_eventfd2)
9211 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009212 {
9213 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9214 if (arg2 & TARGET_O_NONBLOCK) {
9215 host_flags |= O_NONBLOCK;
9216 }
9217 if (arg2 & TARGET_O_CLOEXEC) {
9218 host_flags |= O_CLOEXEC;
9219 }
9220 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009221 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009222 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009223#endif
9224#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009225#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9226 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009227#if TARGET_ABI_BITS == 32
9228 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9229 target_offset64(arg5, arg6)));
9230#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009231 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009232#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009233 break;
9234#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009235#if defined(CONFIG_SYNC_FILE_RANGE)
9236#if defined(TARGET_NR_sync_file_range)
9237 case TARGET_NR_sync_file_range:
9238#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009239#if defined(TARGET_MIPS)
9240 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9241 target_offset64(arg5, arg6), arg7));
9242#else
Peter Maydellc727f472011-01-06 11:05:10 +00009243 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9244 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009245#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009246#else
9247 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9248#endif
9249 break;
9250#endif
9251#if defined(TARGET_NR_sync_file_range2)
9252 case TARGET_NR_sync_file_range2:
9253 /* This is like sync_file_range but the arguments are reordered */
9254#if TARGET_ABI_BITS == 32
9255 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9256 target_offset64(arg5, arg6), arg2));
9257#else
9258 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9259#endif
9260 break;
9261#endif
9262#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009263#if defined(CONFIG_EPOLL)
9264#if defined(TARGET_NR_epoll_create)
9265 case TARGET_NR_epoll_create:
9266 ret = get_errno(epoll_create(arg1));
9267 break;
9268#endif
9269#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9270 case TARGET_NR_epoll_create1:
9271 ret = get_errno(epoll_create1(arg1));
9272 break;
9273#endif
9274#if defined(TARGET_NR_epoll_ctl)
9275 case TARGET_NR_epoll_ctl:
9276 {
9277 struct epoll_event ep;
9278 struct epoll_event *epp = 0;
9279 if (arg4) {
9280 struct target_epoll_event *target_ep;
9281 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9282 goto efault;
9283 }
9284 ep.events = tswap32(target_ep->events);
9285 /* The epoll_data_t union is just opaque data to the kernel,
9286 * so we transfer all 64 bits across and need not worry what
9287 * actual data type it is.
9288 */
9289 ep.data.u64 = tswap64(target_ep->data.u64);
9290 unlock_user_struct(target_ep, arg4, 0);
9291 epp = &ep;
9292 }
9293 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9294 break;
9295 }
9296#endif
9297
9298#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9299#define IMPLEMENT_EPOLL_PWAIT
9300#endif
9301#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9302#if defined(TARGET_NR_epoll_wait)
9303 case TARGET_NR_epoll_wait:
9304#endif
9305#if defined(IMPLEMENT_EPOLL_PWAIT)
9306 case TARGET_NR_epoll_pwait:
9307#endif
9308 {
9309 struct target_epoll_event *target_ep;
9310 struct epoll_event *ep;
9311 int epfd = arg1;
9312 int maxevents = arg3;
9313 int timeout = arg4;
9314
9315 target_ep = lock_user(VERIFY_WRITE, arg2,
9316 maxevents * sizeof(struct target_epoll_event), 1);
9317 if (!target_ep) {
9318 goto efault;
9319 }
9320
9321 ep = alloca(maxevents * sizeof(struct epoll_event));
9322
9323 switch (num) {
9324#if defined(IMPLEMENT_EPOLL_PWAIT)
9325 case TARGET_NR_epoll_pwait:
9326 {
9327 target_sigset_t *target_set;
9328 sigset_t _set, *set = &_set;
9329
9330 if (arg5) {
9331 target_set = lock_user(VERIFY_READ, arg5,
9332 sizeof(target_sigset_t), 1);
9333 if (!target_set) {
9334 unlock_user(target_ep, arg2, 0);
9335 goto efault;
9336 }
9337 target_to_host_sigset(set, target_set);
9338 unlock_user(target_set, arg5, 0);
9339 } else {
9340 set = NULL;
9341 }
9342
9343 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9344 break;
9345 }
9346#endif
9347#if defined(TARGET_NR_epoll_wait)
9348 case TARGET_NR_epoll_wait:
9349 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9350 break;
9351#endif
9352 default:
9353 ret = -TARGET_ENOSYS;
9354 }
9355 if (!is_error(ret)) {
9356 int i;
9357 for (i = 0; i < ret; i++) {
9358 target_ep[i].events = tswap32(ep[i].events);
9359 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9360 }
9361 }
9362 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9363 break;
9364 }
9365#endif
9366#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009367#ifdef TARGET_NR_prlimit64
9368 case TARGET_NR_prlimit64:
9369 {
9370 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9371 struct target_rlimit64 *target_rnew, *target_rold;
9372 struct host_rlimit64 rnew, rold, *rnewp = 0;
9373 if (arg3) {
9374 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9375 goto efault;
9376 }
9377 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9378 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9379 unlock_user_struct(target_rnew, arg3, 0);
9380 rnewp = &rnew;
9381 }
9382
9383 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9384 if (!is_error(ret) && arg4) {
9385 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9386 goto efault;
9387 }
9388 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9389 target_rold->rlim_max = tswap64(rold.rlim_max);
9390 unlock_user_struct(target_rold, arg4, 1);
9391 }
9392 break;
9393 }
9394#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009395#ifdef TARGET_NR_gethostname
9396 case TARGET_NR_gethostname:
9397 {
9398 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9399 if (name) {
9400 ret = get_errno(gethostname(name, arg2));
9401 unlock_user(name, arg1, arg2);
9402 } else {
9403 ret = -TARGET_EFAULT;
9404 }
9405 break;
9406 }
9407#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009408#ifdef TARGET_NR_atomic_cmpxchg_32
9409 case TARGET_NR_atomic_cmpxchg_32:
9410 {
9411 /* should use start_exclusive from main.c */
9412 abi_ulong mem_value;
9413 if (get_user_u32(mem_value, arg6)) {
9414 target_siginfo_t info;
9415 info.si_signo = SIGSEGV;
9416 info.si_errno = 0;
9417 info.si_code = TARGET_SEGV_MAPERR;
9418 info._sifields._sigfault._addr = arg6;
9419 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9420 ret = 0xdeadbeef;
9421
9422 }
9423 if (mem_value == arg2)
9424 put_user_u32(arg1, arg6);
9425 ret = mem_value;
9426 break;
9427 }
9428#endif
9429#ifdef TARGET_NR_atomic_barrier
9430 case TARGET_NR_atomic_barrier:
9431 {
9432 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009433 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009434 break;
9435 }
9436#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009437
9438#ifdef TARGET_NR_timer_create
9439 case TARGET_NR_timer_create:
9440 {
9441 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9442
9443 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009444 struct target_timer_t *ptarget_timer;
9445
9446 int clkid = arg1;
9447 int timer_index = next_free_host_timer();
9448
9449 if (timer_index < 0) {
9450 ret = -TARGET_EAGAIN;
9451 } else {
9452 timer_t *phtimer = g_posix_timers + timer_index;
9453
9454 if (arg2) {
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009455 phost_sevp = &host_sevp;
Peter Maydellc0659762014-08-09 15:42:32 +01009456 ret = target_to_host_sigevent(phost_sevp, arg2);
9457 if (ret != 0) {
9458 break;
9459 }
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009460 }
9461
9462 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9463 if (ret) {
9464 phtimer = NULL;
9465 } else {
9466 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9467 goto efault;
9468 }
9469 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9470 unlock_user_struct(ptarget_timer, arg3, 1);
9471 }
9472 }
9473 break;
9474 }
9475#endif
9476
9477#ifdef TARGET_NR_timer_settime
9478 case TARGET_NR_timer_settime:
9479 {
9480 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9481 * struct itimerspec * old_value */
9482 arg1 &= 0xffff;
9483 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9484 ret = -TARGET_EINVAL;
9485 } else {
9486 timer_t htimer = g_posix_timers[arg1];
9487 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9488
9489 target_to_host_itimerspec(&hspec_new, arg3);
9490 ret = get_errno(
9491 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9492 host_to_target_itimerspec(arg2, &hspec_old);
9493 }
9494 break;
9495 }
9496#endif
9497
9498#ifdef TARGET_NR_timer_gettime
9499 case TARGET_NR_timer_gettime:
9500 {
9501 /* args: timer_t timerid, struct itimerspec *curr_value */
9502 arg1 &= 0xffff;
9503 if (!arg2) {
9504 return -TARGET_EFAULT;
9505 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9506 ret = -TARGET_EINVAL;
9507 } else {
9508 timer_t htimer = g_posix_timers[arg1];
9509 struct itimerspec hspec;
9510 ret = get_errno(timer_gettime(htimer, &hspec));
9511
9512 if (host_to_target_itimerspec(arg2, &hspec)) {
9513 ret = -TARGET_EFAULT;
9514 }
9515 }
9516 break;
9517 }
9518#endif
9519
9520#ifdef TARGET_NR_timer_getoverrun
9521 case TARGET_NR_timer_getoverrun:
9522 {
9523 /* args: timer_t timerid */
9524 arg1 &= 0xffff;
9525 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9526 ret = -TARGET_EINVAL;
9527 } else {
9528 timer_t htimer = g_posix_timers[arg1];
9529 ret = get_errno(timer_getoverrun(htimer));
9530 }
9531 break;
9532 }
9533#endif
9534
9535#ifdef TARGET_NR_timer_delete
9536 case TARGET_NR_timer_delete:
9537 {
9538 /* args: timer_t timerid */
9539 arg1 &= 0xffff;
9540 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9541 ret = -TARGET_EINVAL;
9542 } else {
9543 timer_t htimer = g_posix_timers[arg1];
9544 ret = get_errno(timer_delete(htimer));
9545 g_posix_timers[arg1] = 0;
9546 }
9547 break;
9548 }
9549#endif
9550
Riku Voipio51834342014-06-22 11:25:42 +01009551#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
9552 case TARGET_NR_timerfd_create:
9553 ret = get_errno(timerfd_create(arg1,
9554 target_to_host_bitmask(arg2, fcntl_flags_tbl)));
9555 break;
9556#endif
9557
9558#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
9559 case TARGET_NR_timerfd_gettime:
9560 {
9561 struct itimerspec its_curr;
9562
9563 ret = get_errno(timerfd_gettime(arg1, &its_curr));
9564
9565 if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
9566 goto efault;
9567 }
9568 }
9569 break;
9570#endif
9571
9572#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
9573 case TARGET_NR_timerfd_settime:
9574 {
9575 struct itimerspec its_new, its_old, *p_new;
9576
9577 if (arg3) {
9578 if (target_to_host_itimerspec(&its_new, arg3)) {
9579 goto efault;
9580 }
9581 p_new = &its_new;
9582 } else {
9583 p_new = NULL;
9584 }
9585
9586 ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
9587
9588 if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
9589 goto efault;
9590 }
9591 }
9592 break;
9593#endif
9594
bellard31e31b82003-02-18 22:55:36 +00009595 default:
9596 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009597 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009598#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 +00009599 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009600#endif
ths0da46a62007-10-20 20:23:07 +00009601 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009602 break;
9603 }
bellard579a97f2007-11-11 14:26:47 +00009604fail:
bellardc573ff62004-01-04 15:51:36 +00009605#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009606 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009607#endif
thsb92c47c2007-11-01 00:07:38 +00009608 if(do_strace)
9609 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009610 return ret;
bellard579a97f2007-11-11 14:26:47 +00009611efault:
9612 ret = -TARGET_EFAULT;
9613 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009614}