blob: af0bb3565cecc8f6720f5adb593fc0e43b6223aa [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
2 * Linux syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Eduardo Habkostd5b3a9b2009-06-09 18:26:31 -030019#define _ATFILE_SOURCE
bellard31e31b82003-02-18 22:55:36 +000020#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <elf.h>
25#include <endian.h>
26#include <errno.h>
27#include <unistd.h>
28#include <fcntl.h>
bellard7854b052003-03-29 17:22:23 +000029#include <time.h>
pbrook82e671d2008-06-09 12:10:22 +000030#include <limits.h>
John Spencerc56dc772012-12-10 07:59:46 +010031#include <grp.h>
bellard31e31b82003-02-18 22:55:36 +000032#include <sys/types.h>
thsd08d3bb2007-03-19 13:09:22 +000033#include <sys/ipc.h>
34#include <sys/msg.h>
bellard31e31b82003-02-18 22:55:36 +000035#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/stat.h>
38#include <sys/mount.h>
John Spencer586b0be2012-12-26 00:49:49 +010039#include <sys/file.h>
40#include <sys/fsuid.h>
41#include <sys/personality.h>
ths39b9aae2007-02-11 18:36:44 +000042#include <sys/prctl.h>
bellard31e31b82003-02-18 22:55:36 +000043#include <sys/resource.h>
44#include <sys/mman.h>
45#include <sys/swap.h>
Peter Maydelle0eb2102014-03-17 12:15:35 +000046#include <linux/capability.h>
bellard31e31b82003-02-18 22:55:36 +000047#include <signal.h>
48#include <sched.h>
Aurelien Jarno60e99242010-03-29 02:12:51 +020049#ifdef __ia64__
50int __clone2(int (*fn)(void *), void *child_stack_base,
51 size_t stack_size, int flags, void *arg, ...);
52#endif
bellard31e31b82003-02-18 22:55:36 +000053#include <sys/socket.h>
aurel32607175e2009-04-15 16:11:59 +000054#include <sys/un.h>
bellard31e31b82003-02-18 22:55:36 +000055#include <sys/uio.h>
bellard9de5e442003-03-23 16:49:39 +000056#include <sys/poll.h>
bellard32f36bc2003-03-30 21:29:48 +000057#include <sys/times.h>
bellard8853f862004-02-22 14:57:26 +000058#include <sys/shm.h>
thsfa294812007-02-02 22:05:00 +000059#include <sys/sem.h>
bellard56c8f682005-11-28 22:28:41 +000060#include <sys/statfs.h>
bellardebc05482003-09-30 21:08:41 +000061#include <utime.h>
bellarda5448a72004-06-19 16:59:03 +000062#include <sys/sysinfo.h>
aurel323b3f24a2009-04-15 16:12:13 +000063#include <sys/utsname.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>
95#include <linux/utsname.h>
96#include <linux/cdrom.h>
97#include <linux/hdreg.h>
98#include <linux/soundcard.h>
bellard19b84f32003-05-08 15:41:49 +000099#include <linux/kd.h>
balrog8fbd6b52008-09-20 03:03:09 +0000100#include <linux/mtio.h>
Martin Mohring350d1772009-05-04 21:21:41 +0300101#include <linux/fs.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000102#if defined(CONFIG_FIEMAP)
Peter Maydell285da2b2011-01-06 15:04:18 +0000103#include <linux/fiemap.h>
Peter Maydelldace20d2011-01-10 13:11:24 +0000104#endif
Ulrich Hechtf7680a52009-10-16 17:00:44 +0200105#include <linux/fb.h>
106#include <linux/vt.h>
Alexander Graf56e904e2012-01-31 18:42:06 +0100107#include <linux/dm-ioctl.h>
Laurent Vivierc07ecc62013-01-07 11:40:06 +0000108#include <linux/reboot.h>
Laurent Vivier7ff7b662013-07-02 14:04:12 +0100109#include <linux/route.h>
Laurent Vivierf57d4192013-08-30 01:46:41 +0200110#include <linux/filter.h>
Andreas Färberfff8c532014-01-18 07:38:30 +0100111#include <linux/blkpg.h>
pbrookd7e40362008-05-23 16:06:43 +0000112#include "linux_loop.h"
Loïc Minierda790302009-12-29 22:06:13 +0100113#include "cpu-uname.h"
bellard31e31b82003-02-18 22:55:36 +0000114
bellard3ef693a2003-03-23 20:17:16 +0000115#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +0000116
pbrookd865bab2008-06-07 22:12:17 +0000117#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
118 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
pbrook30813ce2008-06-02 15:45:44 +0000119
bellard72f03902003-02-18 23:33:18 +0000120//#define DEBUG
bellard31e31b82003-02-18 22:55:36 +0000121
bellard1a9353d2003-03-16 20:28:50 +0000122//#include <linux/msdos_fs.h>
aurel326556a832008-10-13 21:08:17 +0000123#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
124#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
bellard1a9353d2003-03-16 20:28:50 +0000125
bellard70a194b2003-08-11 22:20:16 +0000126
bellard70a194b2003-08-11 22:20:16 +0000127#undef _syscall0
128#undef _syscall1
129#undef _syscall2
130#undef _syscall3
131#undef _syscall4
132#undef _syscall5
bellard83fcb512006-06-14 13:37:16 +0000133#undef _syscall6
bellard70a194b2003-08-11 22:20:16 +0000134
bellard83fcb512006-06-14 13:37:16 +0000135#define _syscall0(type,name) \
blueswir18fcd3692008-08-17 20:26:25 +0000136static type name (void) \
bellard83fcb512006-06-14 13:37:16 +0000137{ \
138 return syscall(__NR_##name); \
bellard70a194b2003-08-11 22:20:16 +0000139}
140
bellard83fcb512006-06-14 13:37:16 +0000141#define _syscall1(type,name,type1,arg1) \
blueswir18fcd3692008-08-17 20:26:25 +0000142static type name (type1 arg1) \
bellard83fcb512006-06-14 13:37:16 +0000143{ \
144 return syscall(__NR_##name, arg1); \
bellard70a194b2003-08-11 22:20:16 +0000145}
146
bellard83fcb512006-06-14 13:37:16 +0000147#define _syscall2(type,name,type1,arg1,type2,arg2) \
blueswir18fcd3692008-08-17 20:26:25 +0000148static type name (type1 arg1,type2 arg2) \
bellard83fcb512006-06-14 13:37:16 +0000149{ \
150 return syscall(__NR_##name, arg1, arg2); \
bellard70a194b2003-08-11 22:20:16 +0000151}
152
bellard83fcb512006-06-14 13:37:16 +0000153#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
blueswir18fcd3692008-08-17 20:26:25 +0000154static type name (type1 arg1,type2 arg2,type3 arg3) \
bellard83fcb512006-06-14 13:37:16 +0000155{ \
156 return syscall(__NR_##name, arg1, arg2, arg3); \
bellard70a194b2003-08-11 22:20:16 +0000157}
158
bellard83fcb512006-06-14 13:37:16 +0000159#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
blueswir18fcd3692008-08-17 20:26:25 +0000160static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
bellard83fcb512006-06-14 13:37:16 +0000161{ \
162 return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
bellard70a194b2003-08-11 22:20:16 +0000163}
164
bellard83fcb512006-06-14 13:37:16 +0000165#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
166 type5,arg5) \
blueswir18fcd3692008-08-17 20:26:25 +0000167static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
bellard83fcb512006-06-14 13:37:16 +0000168{ \
169 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
bellard70a194b2003-08-11 22:20:16 +0000170}
bellard83fcb512006-06-14 13:37:16 +0000171
172
173#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
174 type5,arg5,type6,arg6) \
blueswir18fcd3692008-08-17 20:26:25 +0000175static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
176 type6 arg6) \
bellard83fcb512006-06-14 13:37:16 +0000177{ \
178 return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
179}
180
bellard70a194b2003-08-11 22:20:16 +0000181
bellard31e31b82003-02-18 22:55:36 +0000182#define __NR_sys_uname __NR_uname
bellard72f03902003-02-18 23:33:18 +0000183#define __NR_sys_getcwd1 __NR_getcwd
bellard72f03902003-02-18 23:33:18 +0000184#define __NR_sys_getdents __NR_getdents
bellarddab2ed92003-03-22 15:23:14 +0000185#define __NR_sys_getdents64 __NR_getdents64
thsc6cda172007-10-09 03:42:34 +0000186#define __NR_sys_getpriority __NR_getpriority
bellard66fb9762003-03-23 01:06:05 +0000187#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
ths7494b0f2007-02-11 18:26:53 +0000188#define __NR_sys_syslog __NR_syslog
ths71455572007-06-21 21:45:30 +0000189#define __NR_sys_tgkill __NR_tgkill
ths4cae1d12007-07-12 11:06:53 +0000190#define __NR_sys_tkill __NR_tkill
pbrookbd0c5662008-05-29 14:34:11 +0000191#define __NR_sys_futex __NR_futex
aurel3239b59762008-10-01 21:46:50 +0000192#define __NR_sys_inotify_init __NR_inotify_init
193#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
194#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
bellard31e31b82003-02-18 22:55:36 +0000195
Alexander Graf42a39fb2011-04-15 17:32:45 +0200196#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
197 defined(__s390x__)
bellard9af9eaa2003-04-07 21:34:41 +0000198#define __NR__llseek __NR_lseek
199#endif
200
James Hogana29e5ba2014-03-25 21:51:08 +0000201/* Newer kernel ports have llseek() instead of _llseek() */
202#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
203#define TARGET_NR__llseek TARGET_NR_llseek
204#endif
205
bellard72f03902003-02-18 23:33:18 +0000206#ifdef __NR_gettid
bellard31e31b82003-02-18 22:55:36 +0000207_syscall0(int, gettid)
bellard72f03902003-02-18 23:33:18 +0000208#else
ths0da46a62007-10-20 20:23:07 +0000209/* This is a replacement for the host gettid() and must return a host
210 errno. */
bellard72f03902003-02-18 23:33:18 +0000211static int gettid(void) {
212 return -ENOSYS;
213}
214#endif
Peter Maydell3307e232013-06-12 16:20:21 +0100215#ifdef __NR_getdents
aurel323b3f24a2009-04-15 16:12:13 +0000216_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
Peter Maydell3307e232013-06-12 16:20:21 +0100217#endif
218#if !defined(__NR_getdents) || \
219 (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
aurel323b3f24a2009-04-15 16:12:13 +0000220_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
221#endif
Richard Hendersond35b2612010-06-04 12:14:10 -0700222#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
aurel323b3f24a2009-04-15 16:12:13 +0000223_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
224 loff_t *, res, uint, wh);
225#endif
226_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
227_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
228#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
229_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
230#endif
231#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
232_syscall2(int,sys_tkill,int,tid,int,sig)
233#endif
234#ifdef __NR_exit_group
235_syscall1(int,exit_group,int,error_code)
236#endif
237#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
238_syscall1(int,set_tid_address,int *,tidptr)
239#endif
aurel323b3f24a2009-04-15 16:12:13 +0000240#if defined(TARGET_NR_futex) && defined(__NR_futex)
241_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
242 const struct timespec *,timeout,int *,uaddr2,int,val3)
243#endif
Mike Frysinger737de1d2011-02-07 01:05:55 -0500244#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
245_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
246 unsigned long *, user_mask_ptr);
247#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
248_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
249 unsigned long *, user_mask_ptr);
Alexander Graf0f6b4d22011-09-27 14:39:42 +0200250_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
251 void *, arg);
Peter Maydelle0eb2102014-03-17 12:15:35 +0000252_syscall2(int, capget, struct __user_cap_header_struct *, header,
253 struct __user_cap_data_struct *, data);
254_syscall2(int, capset, struct __user_cap_header_struct *, header,
255 struct __user_cap_data_struct *, data);
aurel323b3f24a2009-04-15 16:12:13 +0000256
257static bitmask_transtbl fcntl_flags_tbl[] = {
258 { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
259 { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
260 { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
261 { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
262 { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
263 { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
264 { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
265 { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
Richard Hendersonafc87632012-07-25 14:30:34 -0700266 { TARGET_O_SYNC, TARGET_O_DSYNC, O_SYNC, O_DSYNC, },
aurel323b3f24a2009-04-15 16:12:13 +0000267 { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
268 { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
269 { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
270 { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
aurel323b3f24a2009-04-15 16:12:13 +0000271#if defined(O_DIRECT)
272 { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
273#endif
Richard Hendersonafc87632012-07-25 14:30:34 -0700274#if defined(O_NOATIME)
275 { TARGET_O_NOATIME, TARGET_O_NOATIME, O_NOATIME, O_NOATIME },
276#endif
277#if defined(O_CLOEXEC)
278 { TARGET_O_CLOEXEC, TARGET_O_CLOEXEC, O_CLOEXEC, O_CLOEXEC },
279#endif
280#if defined(O_PATH)
281 { TARGET_O_PATH, TARGET_O_PATH, O_PATH, O_PATH },
282#endif
283 /* Don't terminate the list prematurely on 64-bit host+guest. */
284#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
285 { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
286#endif
aurel323b3f24a2009-04-15 16:12:13 +0000287 { 0, 0, 0, 0 }
288};
289
290#define COPY_UTSNAME_FIELD(dest, src) \
291 do { \
292 /* __NEW_UTS_LEN doesn't include terminating null */ \
293 (void) strncpy((dest), (src), __NEW_UTS_LEN); \
294 (dest)[__NEW_UTS_LEN] = '\0'; \
295 } while (0)
296
297static int sys_uname(struct new_utsname *buf)
298{
299 struct utsname uts_buf;
300
301 if (uname(&uts_buf) < 0)
302 return (-1);
303
304 /*
305 * Just in case these have some differences, we
306 * translate utsname to new_utsname (which is the
307 * struct linux kernel uses).
308 */
309
Stefan Weil67bd9ed2011-05-07 22:32:25 +0200310 memset(buf, 0, sizeof(*buf));
aurel323b3f24a2009-04-15 16:12:13 +0000311 COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
312 COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
313 COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
314 COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
315 COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
316#ifdef _GNU_SOURCE
317 COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
318#endif
319 return (0);
320
321#undef COPY_UTSNAME_FIELD
322}
323
324static int sys_getcwd1(char *buf, size_t size)
325{
326 if (getcwd(buf, size) == NULL) {
327 /* getcwd() sets errno */
328 return (-1);
329 }
aurel32aaf4ad32009-04-16 14:17:14 +0000330 return strlen(buf)+1;
aurel323b3f24a2009-04-15 16:12:13 +0000331}
332
aurel323b3f24a2009-04-15 16:12:13 +0000333#ifdef TARGET_NR_openat
Alexander Graff4c69012011-09-25 06:25:35 +0200334static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
aurel323b3f24a2009-04-15 16:12:13 +0000335{
336 /*
337 * open(2) has extra parameter 'mode' when called with
338 * flag O_CREAT.
339 */
340 if ((flags & O_CREAT) != 0) {
aurel323b3f24a2009-04-15 16:12:13 +0000341 return (openat(dirfd, pathname, flags, mode));
342 }
343 return (openat(dirfd, pathname, flags));
344}
345#endif
Riku Voipioebc996f2009-04-21 15:01:51 +0300346
Peter Maydell1acae9f2013-07-02 14:04:12 +0100347#ifdef TARGET_NR_utimensat
Riku Voipioebc996f2009-04-21 15:01:51 +0300348#ifdef CONFIG_UTIMENSAT
349static int sys_utimensat(int dirfd, const char *pathname,
350 const struct timespec times[2], int flags)
351{
352 if (pathname == NULL)
353 return futimens(dirfd, times);
354 else
355 return utimensat(dirfd, pathname, times, flags);
356}
Peter Maydell1acae9f2013-07-02 14:04:12 +0100357#elif defined(__NR_utimensat)
358#define __NR_sys_utimensat __NR_utimensat
ths9007f0e2007-09-25 17:50:37 +0000359_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
360 const struct timespec *,tsp,int,flags)
Peter Maydell1acae9f2013-07-02 14:04:12 +0100361#else
362static int sys_utimensat(int dirfd, const char *pathname,
363 const struct timespec times[2], int flags)
364{
365 errno = ENOSYS;
366 return -1;
367}
ths9007f0e2007-09-25 17:50:37 +0000368#endif
Peter Maydell1acae9f2013-07-02 14:04:12 +0100369#endif /* TARGET_NR_utimensat */
aurel323b3f24a2009-04-15 16:12:13 +0000370
371#ifdef CONFIG_INOTIFY
aurel328690e422009-04-17 13:50:32 +0000372#include <sys/inotify.h>
aurel323b3f24a2009-04-15 16:12:13 +0000373
aurel3239b59762008-10-01 21:46:50 +0000374#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel323b3f24a2009-04-15 16:12:13 +0000375static int sys_inotify_init(void)
376{
377 return (inotify_init());
378}
aurel3239b59762008-10-01 21:46:50 +0000379#endif
380#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000381static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
382{
383 return (inotify_add_watch(fd, pathname, mask));
384}
aurel3239b59762008-10-01 21:46:50 +0000385#endif
386#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel323b3f24a2009-04-15 16:12:13 +0000387static int sys_inotify_rm_watch(int fd, int32_t wd)
388{
aurel328690e422009-04-17 13:50:32 +0000389 return (inotify_rm_watch(fd, wd));
aurel323b3f24a2009-04-15 16:12:13 +0000390}
aurel3239b59762008-10-01 21:46:50 +0000391#endif
Riku Voipioc05c7a72010-03-26 15:25:11 +0000392#ifdef CONFIG_INOTIFY1
393#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
394static int sys_inotify_init1(int flags)
395{
396 return (inotify_init1(flags));
397}
398#endif
399#endif
aurel323b3f24a2009-04-15 16:12:13 +0000400#else
401/* Userspace can usually survive runtime without inotify */
402#undef TARGET_NR_inotify_init
Riku Voipioc05c7a72010-03-26 15:25:11 +0000403#undef TARGET_NR_inotify_init1
aurel323b3f24a2009-04-15 16:12:13 +0000404#undef TARGET_NR_inotify_add_watch
405#undef TARGET_NR_inotify_rm_watch
406#endif /* CONFIG_INOTIFY */
407
Mike Frysingerd8035d42011-02-07 01:05:51 -0500408#if defined(TARGET_NR_ppoll)
409#ifndef __NR_ppoll
410# define __NR_ppoll -1
411#endif
412#define __NR_sys_ppoll __NR_ppoll
413_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
Natanael Copa34d60862014-04-29 13:11:20 +0200414 struct timespec *, timeout, const sigset_t *, sigmask,
Mike Frysingerd8035d42011-02-07 01:05:51 -0500415 size_t, sigsetsize)
416#endif
bellard66fb9762003-03-23 01:06:05 +0000417
Mike Frysinger055e0902011-06-03 17:01:49 -0400418#if defined(TARGET_NR_pselect6)
419#ifndef __NR_pselect6
420# define __NR_pselect6 -1
421#endif
422#define __NR_sys_pselect6 __NR_pselect6
423_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
424 fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
425#endif
426
Peter Maydell163a05a2011-06-27 17:44:52 +0100427#if defined(TARGET_NR_prlimit64)
428#ifndef __NR_prlimit64
429# define __NR_prlimit64 -1
430#endif
431#define __NR_sys_prlimit64 __NR_prlimit64
432/* The glibc rlimit structure may not be that used by the underlying syscall */
433struct host_rlimit64 {
434 uint64_t rlim_cur;
435 uint64_t rlim_max;
436};
437_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
438 const struct host_rlimit64 *, new_limit,
439 struct host_rlimit64 *, old_limit)
440#endif
441
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +1100442
443#if defined(TARGET_NR_timer_create)
444/* Maxiumum of 32 active POSIX timers allowed at any one time. */
445static timer_t g_posix_timers[32] = { 0, } ;
446
447static inline int next_free_host_timer(void)
448{
449 int k ;
450 /* FIXME: Does finding the next free slot require a lock? */
451 for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
452 if (g_posix_timers[k] == 0) {
453 g_posix_timers[k] = (timer_t) 1;
454 return k;
455 }
456 }
457 return -1;
458}
459#endif
460
Riku Voipio48e515d2011-07-12 15:40:51 +0300461/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
Alexander Graf4a1def42012-09-29 15:32:38 +0000462#ifdef TARGET_ARM
Riku Voipio48e515d2011-07-12 15:40:51 +0300463static inline int regpairs_aligned(void *cpu_env) {
464 return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
465}
466#elif defined(TARGET_MIPS)
467static inline int regpairs_aligned(void *cpu_env) { return 1; }
Alexander Graf4a1def42012-09-29 15:32:38 +0000468#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
469/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
470 * of registers which translates to the same as ARM/MIPS, because we start with
471 * r3 as arg1 */
472static inline int regpairs_aligned(void *cpu_env) { return 1; }
Riku Voipio48e515d2011-07-12 15:40:51 +0300473#else
474static inline int regpairs_aligned(void *cpu_env) { return 0; }
475#endif
476
thsb92c47c2007-11-01 00:07:38 +0000477#define ERRNO_TABLE_SIZE 1200
478
479/* target_to_host_errno_table[] is initialized from
480 * host_to_target_errno_table[] in syscall_init(). */
481static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
482};
483
ths637947f2007-06-01 12:09:19 +0000484/*
thsfe8f0962007-07-12 10:59:21 +0000485 * This list is the union of errno values overridden in asm-<arch>/errno.h
ths637947f2007-06-01 12:09:19 +0000486 * minus the errnos that are not actually generic to all archs.
487 */
thsb92c47c2007-11-01 00:07:38 +0000488static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
ths637947f2007-06-01 12:09:19 +0000489 [EIDRM] = TARGET_EIDRM,
490 [ECHRNG] = TARGET_ECHRNG,
491 [EL2NSYNC] = TARGET_EL2NSYNC,
492 [EL3HLT] = TARGET_EL3HLT,
493 [EL3RST] = TARGET_EL3RST,
494 [ELNRNG] = TARGET_ELNRNG,
495 [EUNATCH] = TARGET_EUNATCH,
496 [ENOCSI] = TARGET_ENOCSI,
497 [EL2HLT] = TARGET_EL2HLT,
498 [EDEADLK] = TARGET_EDEADLK,
499 [ENOLCK] = TARGET_ENOLCK,
500 [EBADE] = TARGET_EBADE,
501 [EBADR] = TARGET_EBADR,
502 [EXFULL] = TARGET_EXFULL,
503 [ENOANO] = TARGET_ENOANO,
504 [EBADRQC] = TARGET_EBADRQC,
505 [EBADSLT] = TARGET_EBADSLT,
506 [EBFONT] = TARGET_EBFONT,
507 [ENOSTR] = TARGET_ENOSTR,
508 [ENODATA] = TARGET_ENODATA,
509 [ETIME] = TARGET_ETIME,
510 [ENOSR] = TARGET_ENOSR,
511 [ENONET] = TARGET_ENONET,
512 [ENOPKG] = TARGET_ENOPKG,
513 [EREMOTE] = TARGET_EREMOTE,
514 [ENOLINK] = TARGET_ENOLINK,
515 [EADV] = TARGET_EADV,
516 [ESRMNT] = TARGET_ESRMNT,
517 [ECOMM] = TARGET_ECOMM,
518 [EPROTO] = TARGET_EPROTO,
519 [EDOTDOT] = TARGET_EDOTDOT,
520 [EMULTIHOP] = TARGET_EMULTIHOP,
521 [EBADMSG] = TARGET_EBADMSG,
522 [ENAMETOOLONG] = TARGET_ENAMETOOLONG,
523 [EOVERFLOW] = TARGET_EOVERFLOW,
524 [ENOTUNIQ] = TARGET_ENOTUNIQ,
525 [EBADFD] = TARGET_EBADFD,
526 [EREMCHG] = TARGET_EREMCHG,
527 [ELIBACC] = TARGET_ELIBACC,
528 [ELIBBAD] = TARGET_ELIBBAD,
529 [ELIBSCN] = TARGET_ELIBSCN,
530 [ELIBMAX] = TARGET_ELIBMAX,
531 [ELIBEXEC] = TARGET_ELIBEXEC,
532 [EILSEQ] = TARGET_EILSEQ,
533 [ENOSYS] = TARGET_ENOSYS,
534 [ELOOP] = TARGET_ELOOP,
535 [ERESTART] = TARGET_ERESTART,
536 [ESTRPIPE] = TARGET_ESTRPIPE,
537 [ENOTEMPTY] = TARGET_ENOTEMPTY,
538 [EUSERS] = TARGET_EUSERS,
539 [ENOTSOCK] = TARGET_ENOTSOCK,
540 [EDESTADDRREQ] = TARGET_EDESTADDRREQ,
541 [EMSGSIZE] = TARGET_EMSGSIZE,
542 [EPROTOTYPE] = TARGET_EPROTOTYPE,
543 [ENOPROTOOPT] = TARGET_ENOPROTOOPT,
544 [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT,
545 [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT,
546 [EOPNOTSUPP] = TARGET_EOPNOTSUPP,
547 [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT,
548 [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT,
549 [EADDRINUSE] = TARGET_EADDRINUSE,
550 [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL,
551 [ENETDOWN] = TARGET_ENETDOWN,
552 [ENETUNREACH] = TARGET_ENETUNREACH,
553 [ENETRESET] = TARGET_ENETRESET,
554 [ECONNABORTED] = TARGET_ECONNABORTED,
555 [ECONNRESET] = TARGET_ECONNRESET,
556 [ENOBUFS] = TARGET_ENOBUFS,
557 [EISCONN] = TARGET_EISCONN,
558 [ENOTCONN] = TARGET_ENOTCONN,
559 [EUCLEAN] = TARGET_EUCLEAN,
560 [ENOTNAM] = TARGET_ENOTNAM,
561 [ENAVAIL] = TARGET_ENAVAIL,
562 [EISNAM] = TARGET_EISNAM,
563 [EREMOTEIO] = TARGET_EREMOTEIO,
564 [ESHUTDOWN] = TARGET_ESHUTDOWN,
565 [ETOOMANYREFS] = TARGET_ETOOMANYREFS,
566 [ETIMEDOUT] = TARGET_ETIMEDOUT,
567 [ECONNREFUSED] = TARGET_ECONNREFUSED,
568 [EHOSTDOWN] = TARGET_EHOSTDOWN,
569 [EHOSTUNREACH] = TARGET_EHOSTUNREACH,
570 [EALREADY] = TARGET_EALREADY,
571 [EINPROGRESS] = TARGET_EINPROGRESS,
572 [ESTALE] = TARGET_ESTALE,
573 [ECANCELED] = TARGET_ECANCELED,
574 [ENOMEDIUM] = TARGET_ENOMEDIUM,
575 [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE,
thsb7fe5db2007-07-23 15:37:46 +0000576#ifdef ENOKEY
ths637947f2007-06-01 12:09:19 +0000577 [ENOKEY] = TARGET_ENOKEY,
thsb7fe5db2007-07-23 15:37:46 +0000578#endif
579#ifdef EKEYEXPIRED
ths637947f2007-06-01 12:09:19 +0000580 [EKEYEXPIRED] = TARGET_EKEYEXPIRED,
thsb7fe5db2007-07-23 15:37:46 +0000581#endif
582#ifdef EKEYREVOKED
ths637947f2007-06-01 12:09:19 +0000583 [EKEYREVOKED] = TARGET_EKEYREVOKED,
thsb7fe5db2007-07-23 15:37:46 +0000584#endif
585#ifdef EKEYREJECTED
ths637947f2007-06-01 12:09:19 +0000586 [EKEYREJECTED] = TARGET_EKEYREJECTED,
thsb7fe5db2007-07-23 15:37:46 +0000587#endif
588#ifdef EOWNERDEAD
ths637947f2007-06-01 12:09:19 +0000589 [EOWNERDEAD] = TARGET_EOWNERDEAD,
thsb7fe5db2007-07-23 15:37:46 +0000590#endif
591#ifdef ENOTRECOVERABLE
ths637947f2007-06-01 12:09:19 +0000592 [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE,
thsb7fe5db2007-07-23 15:37:46 +0000593#endif
thsb92c47c2007-11-01 00:07:38 +0000594};
ths637947f2007-06-01 12:09:19 +0000595
596static inline int host_to_target_errno(int err)
597{
598 if(host_to_target_errno_table[err])
599 return host_to_target_errno_table[err];
600 return err;
601}
602
thsb92c47c2007-11-01 00:07:38 +0000603static inline int target_to_host_errno(int err)
604{
605 if (target_to_host_errno_table[err])
606 return target_to_host_errno_table[err];
607 return err;
608}
609
blueswir1992f48a2007-10-14 16:27:31 +0000610static inline abi_long get_errno(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000611{
612 if (ret == -1)
ths637947f2007-06-01 12:09:19 +0000613 return -host_to_target_errno(errno);
bellard31e31b82003-02-18 22:55:36 +0000614 else
615 return ret;
616}
617
blueswir1992f48a2007-10-14 16:27:31 +0000618static inline int is_error(abi_long ret)
bellard31e31b82003-02-18 22:55:36 +0000619{
blueswir1992f48a2007-10-14 16:27:31 +0000620 return (abi_ulong)ret >= (abi_ulong)(-4096);
bellard31e31b82003-02-18 22:55:36 +0000621}
622
thsb92c47c2007-11-01 00:07:38 +0000623char *target_strerror(int err)
624{
Alexander Graf962b2892011-11-21 12:04:07 +0100625 if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
626 return NULL;
627 }
thsb92c47c2007-11-01 00:07:38 +0000628 return strerror(target_to_host_errno(err));
629}
630
blueswir1992f48a2007-10-14 16:27:31 +0000631static abi_ulong target_brk;
632static abi_ulong target_original_brk;
vincent4d1de872011-06-14 21:56:33 +0000633static abi_ulong brk_page;
bellard31e31b82003-02-18 22:55:36 +0000634
blueswir1992f48a2007-10-14 16:27:31 +0000635void target_set_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000636{
blueswir14c1de732007-07-07 20:45:44 +0000637 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
vincent4d1de872011-06-14 21:56:33 +0000638 brk_page = HOST_PAGE_ALIGN(target_brk);
bellard31e31b82003-02-18 22:55:36 +0000639}
640
vincent4d1de872011-06-14 21:56:33 +0000641//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
642#define DEBUGF_BRK(message, args...)
643
ths0da46a62007-10-20 20:23:07 +0000644/* do_brk() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000645abi_long do_brk(abi_ulong new_brk)
bellard31e31b82003-02-18 22:55:36 +0000646{
blueswir1992f48a2007-10-14 16:27:31 +0000647 abi_long mapped_addr;
bellard31e31b82003-02-18 22:55:36 +0000648 int new_alloc_size;
649
Paul Brook3a0c6c42012-02-09 19:04:27 +0000650 DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
ths3b46e622007-09-17 08:09:54 +0000651
vincent4d1de872011-06-14 21:56:33 +0000652 if (!new_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000653 DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000654 return target_brk;
655 }
656 if (new_brk < target_original_brk) {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000657 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
658 target_brk);
vincent4d1de872011-06-14 21:56:33 +0000659 return target_brk;
660 }
bellard31e31b82003-02-18 22:55:36 +0000661
vincent4d1de872011-06-14 21:56:33 +0000662 /* If the new brk is less than the highest page reserved to the
663 * target heap allocation, set it and we're almost done... */
664 if (new_brk <= brk_page) {
665 /* Heap contents are initialized to zero, as for anonymous
666 * mapped pages. */
667 if (new_brk > target_brk) {
668 memset(g2h(target_brk), 0, new_brk - target_brk);
669 }
bellard31e31b82003-02-18 22:55:36 +0000670 target_brk = new_brk;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000671 DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
pbrook53a59602006-03-25 19:31:22 +0000672 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000673 }
674
Peter Maydell00faf082011-04-18 16:34:24 +0100675 /* We need to allocate more memory after the brk... Note that
676 * we don't use MAP_FIXED because that will map over the top of
677 * any existing mapping (like the one with the host libc or qemu
678 * itself); instead we treat "mapped but at wrong address" as
679 * a failure and unmap again.
680 */
vincent4d1de872011-06-14 21:56:33 +0000681 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
ths5fafdf22007-09-16 21:08:06 +0000682 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
bellard54936002003-05-13 00:25:15 +0000683 PROT_READ|PROT_WRITE,
Peter Maydell00faf082011-04-18 16:34:24 +0100684 MAP_ANON|MAP_PRIVATE, 0, 0));
685
686 if (mapped_addr == brk_page) {
Cédric VINCENT70afc342011-08-26 10:56:50 +0200687 /* Heap contents are initialized to zero, as for anonymous
688 * mapped pages. Technically the new pages are already
689 * initialized to zero since they *are* anonymous mapped
690 * pages, however we have to take care with the contents that
691 * come from the remaining part of the previous page: it may
692 * contains garbage data due to a previous heap usage (grown
693 * then shrunken). */
694 memset(g2h(target_brk), 0, brk_page - target_brk);
695
Peter Maydell00faf082011-04-18 16:34:24 +0100696 target_brk = new_brk;
vincent4d1de872011-06-14 21:56:33 +0000697 brk_page = HOST_PAGE_ALIGN(target_brk);
Paul Brook3a0c6c42012-02-09 19:04:27 +0000698 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
699 target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100700 return target_brk;
701 } else if (mapped_addr != -1) {
702 /* Mapped but at wrong address, meaning there wasn't actually
703 * enough space for this brk.
704 */
705 target_munmap(mapped_addr, new_alloc_size);
706 mapped_addr = -1;
Paul Brook3a0c6c42012-02-09 19:04:27 +0000707 DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
vincent4d1de872011-06-14 21:56:33 +0000708 }
709 else {
Paul Brook3a0c6c42012-02-09 19:04:27 +0000710 DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
Peter Maydell00faf082011-04-18 16:34:24 +0100711 }
balrog7ab240a2008-04-26 12:17:34 +0000712
Richard Henderson7dd46c02010-05-03 10:07:49 -0700713#if defined(TARGET_ALPHA)
714 /* We (partially) emulate OSF/1 on Alpha, which requires we
715 return a proper errno, not an unchanged brk value. */
Peter Maydell00faf082011-04-18 16:34:24 +0100716 return -TARGET_ENOMEM;
Richard Henderson7dd46c02010-05-03 10:07:49 -0700717#endif
Peter Maydell00faf082011-04-18 16:34:24 +0100718 /* For everything else, return the previous break. */
balrog7ab240a2008-04-26 12:17:34 +0000719 return target_brk;
bellard31e31b82003-02-18 22:55:36 +0000720}
721
ths26edcf42007-12-09 02:25:24 +0000722static inline abi_long copy_from_user_fdset(fd_set *fds,
723 abi_ulong target_fds_addr,
724 int n)
bellard31e31b82003-02-18 22:55:36 +0000725{
ths26edcf42007-12-09 02:25:24 +0000726 int i, nw, j, k;
727 abi_ulong b, *target_fds;
728
729 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
730 if (!(target_fds = lock_user(VERIFY_READ,
731 target_fds_addr,
732 sizeof(abi_ulong) * nw,
733 1)))
734 return -TARGET_EFAULT;
735
736 FD_ZERO(fds);
737 k = 0;
738 for (i = 0; i < nw; i++) {
739 /* grab the abi_ulong */
740 __get_user(b, &target_fds[i]);
741 for (j = 0; j < TARGET_ABI_BITS; j++) {
742 /* check the bit inside the abi_ulong */
743 if ((b >> j) & 1)
744 FD_SET(k, fds);
745 k++;
bellard31e31b82003-02-18 22:55:36 +0000746 }
bellard31e31b82003-02-18 22:55:36 +0000747 }
ths26edcf42007-12-09 02:25:24 +0000748
749 unlock_user(target_fds, target_fds_addr, 0);
750
751 return 0;
bellard31e31b82003-02-18 22:55:36 +0000752}
753
Mike Frysinger055e0902011-06-03 17:01:49 -0400754static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
755 abi_ulong target_fds_addr,
756 int n)
757{
758 if (target_fds_addr) {
759 if (copy_from_user_fdset(fds, target_fds_addr, n))
760 return -TARGET_EFAULT;
761 *fds_ptr = fds;
762 } else {
763 *fds_ptr = NULL;
764 }
765 return 0;
766}
767
ths26edcf42007-12-09 02:25:24 +0000768static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
769 const fd_set *fds,
770 int n)
bellard31e31b82003-02-18 22:55:36 +0000771{
bellard31e31b82003-02-18 22:55:36 +0000772 int i, nw, j, k;
blueswir1992f48a2007-10-14 16:27:31 +0000773 abi_long v;
ths26edcf42007-12-09 02:25:24 +0000774 abi_ulong *target_fds;
bellard31e31b82003-02-18 22:55:36 +0000775
ths26edcf42007-12-09 02:25:24 +0000776 nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
777 if (!(target_fds = lock_user(VERIFY_WRITE,
778 target_fds_addr,
779 sizeof(abi_ulong) * nw,
780 0)))
781 return -TARGET_EFAULT;
782
783 k = 0;
784 for (i = 0; i < nw; i++) {
785 v = 0;
786 for (j = 0; j < TARGET_ABI_BITS; j++) {
Andreas Schwab9ab709b2013-04-09 01:02:34 +0000787 v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
ths26edcf42007-12-09 02:25:24 +0000788 k++;
bellard31e31b82003-02-18 22:55:36 +0000789 }
ths26edcf42007-12-09 02:25:24 +0000790 __put_user(v, &target_fds[i]);
bellard31e31b82003-02-18 22:55:36 +0000791 }
ths26edcf42007-12-09 02:25:24 +0000792
793 unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
794
795 return 0;
bellard31e31b82003-02-18 22:55:36 +0000796}
797
bellardc596ed12003-07-13 17:32:31 +0000798#if defined(__alpha__)
799#define HOST_HZ 1024
800#else
801#define HOST_HZ 100
802#endif
803
blueswir1992f48a2007-10-14 16:27:31 +0000804static inline abi_long host_to_target_clock_t(long ticks)
bellardc596ed12003-07-13 17:32:31 +0000805{
806#if HOST_HZ == TARGET_HZ
807 return ticks;
808#else
809 return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
810#endif
811}
812
bellard579a97f2007-11-11 14:26:47 +0000813static inline abi_long host_to_target_rusage(abi_ulong target_addr,
814 const struct rusage *rusage)
bellardb4091862003-05-16 15:39:34 +0000815{
pbrook53a59602006-03-25 19:31:22 +0000816 struct target_rusage *target_rusage;
817
bellard579a97f2007-11-11 14:26:47 +0000818 if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
819 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200820 target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
821 target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
822 target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
823 target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
824 target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
825 target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
826 target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
827 target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
828 target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
829 target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
830 target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
831 target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
832 target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
833 target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
834 target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
835 target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
836 target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
837 target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
pbrook53a59602006-03-25 19:31:22 +0000838 unlock_user_struct(target_rusage, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000839
840 return 0;
bellardb4091862003-05-16 15:39:34 +0000841}
842
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200843static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900844{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200845 abi_ulong target_rlim_swap;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300846 rlim_t result;
847
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200848 target_rlim_swap = tswapal(target_rlim);
849 if (target_rlim_swap == TARGET_RLIM_INFINITY)
850 return RLIM_INFINITY;
851
852 result = target_rlim_swap;
853 if (target_rlim_swap != (rlim_t)result)
854 return RLIM_INFINITY;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300855
856 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900857}
858
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200859static inline abi_ulong host_to_target_rlim(rlim_t rlim)
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900860{
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200861 abi_ulong target_rlim_swap;
862 abi_ulong result;
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300863
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200864 if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300865 target_rlim_swap = TARGET_RLIM_INFINITY;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900866 else
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300867 target_rlim_swap = rlim;
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200868 result = tswapal(target_rlim_swap);
Wesley W. Terpstra95b33b22011-07-12 14:38:22 +0300869
870 return result;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +0900871}
872
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +0300873static inline int target_to_host_resource(int code)
874{
875 switch (code) {
876 case TARGET_RLIMIT_AS:
877 return RLIMIT_AS;
878 case TARGET_RLIMIT_CORE:
879 return RLIMIT_CORE;
880 case TARGET_RLIMIT_CPU:
881 return RLIMIT_CPU;
882 case TARGET_RLIMIT_DATA:
883 return RLIMIT_DATA;
884 case TARGET_RLIMIT_FSIZE:
885 return RLIMIT_FSIZE;
886 case TARGET_RLIMIT_LOCKS:
887 return RLIMIT_LOCKS;
888 case TARGET_RLIMIT_MEMLOCK:
889 return RLIMIT_MEMLOCK;
890 case TARGET_RLIMIT_MSGQUEUE:
891 return RLIMIT_MSGQUEUE;
892 case TARGET_RLIMIT_NICE:
893 return RLIMIT_NICE;
894 case TARGET_RLIMIT_NOFILE:
895 return RLIMIT_NOFILE;
896 case TARGET_RLIMIT_NPROC:
897 return RLIMIT_NPROC;
898 case TARGET_RLIMIT_RSS:
899 return RLIMIT_RSS;
900 case TARGET_RLIMIT_RTPRIO:
901 return RLIMIT_RTPRIO;
902 case TARGET_RLIMIT_SIGPENDING:
903 return RLIMIT_SIGPENDING;
904 case TARGET_RLIMIT_STACK:
905 return RLIMIT_STACK;
906 default:
907 return code;
908 }
909}
910
ths788f5ec2007-12-09 02:37:05 +0000911static inline abi_long copy_from_user_timeval(struct timeval *tv,
912 abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000913{
pbrook53a59602006-03-25 19:31:22 +0000914 struct target_timeval *target_tv;
915
ths788f5ec2007-12-09 02:37:05 +0000916 if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
bellard579a97f2007-11-11 14:26:47 +0000917 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000918
919 __get_user(tv->tv_sec, &target_tv->tv_sec);
920 __get_user(tv->tv_usec, &target_tv->tv_usec);
921
922 unlock_user_struct(target_tv, target_tv_addr, 0);
bellard579a97f2007-11-11 14:26:47 +0000923
924 return 0;
bellard31e31b82003-02-18 22:55:36 +0000925}
926
ths788f5ec2007-12-09 02:37:05 +0000927static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
928 const struct timeval *tv)
bellard31e31b82003-02-18 22:55:36 +0000929{
pbrook53a59602006-03-25 19:31:22 +0000930 struct target_timeval *target_tv;
931
ths788f5ec2007-12-09 02:37:05 +0000932 if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
bellard579a97f2007-11-11 14:26:47 +0000933 return -TARGET_EFAULT;
ths788f5ec2007-12-09 02:37:05 +0000934
935 __put_user(tv->tv_sec, &target_tv->tv_sec);
936 __put_user(tv->tv_usec, &target_tv->tv_usec);
937
938 unlock_user_struct(target_tv, target_tv_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000939
940 return 0;
bellard31e31b82003-02-18 22:55:36 +0000941}
942
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700943#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
944#include <mqueue.h>
945
aurel3224e10032009-04-15 16:11:43 +0000946static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
947 abi_ulong target_mq_attr_addr)
948{
949 struct target_mq_attr *target_mq_attr;
950
951 if (!lock_user_struct(VERIFY_READ, target_mq_attr,
952 target_mq_attr_addr, 1))
953 return -TARGET_EFAULT;
954
955 __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
956 __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
957 __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
958 __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
959
960 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
961
962 return 0;
963}
964
965static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
966 const struct mq_attr *attr)
967{
968 struct target_mq_attr *target_mq_attr;
969
970 if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
971 target_mq_attr_addr, 0))
972 return -TARGET_EFAULT;
973
974 __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
975 __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
976 __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
977 __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
978
979 unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
980
981 return 0;
982}
Nathan Froyd8ec9cf82009-07-22 09:14:36 -0700983#endif
bellard31e31b82003-02-18 22:55:36 +0000984
Mike Frysinger055e0902011-06-03 17:01:49 -0400985#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
ths0da46a62007-10-20 20:23:07 +0000986/* do_select() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +0000987static abi_long do_select(int n,
ths26edcf42007-12-09 02:25:24 +0000988 abi_ulong rfd_addr, abi_ulong wfd_addr,
989 abi_ulong efd_addr, abi_ulong target_tv_addr)
bellard31e31b82003-02-18 22:55:36 +0000990{
991 fd_set rfds, wfds, efds;
992 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
993 struct timeval tv, *tv_ptr;
blueswir1992f48a2007-10-14 16:27:31 +0000994 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +0000995
Mike Frysinger055e0902011-06-03 17:01:49 -0400996 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
997 if (ret) {
998 return ret;
pbrook53a59602006-03-25 19:31:22 +0000999 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001000 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
1001 if (ret) {
1002 return ret;
pbrook53a59602006-03-25 19:31:22 +00001003 }
Mike Frysinger055e0902011-06-03 17:01:49 -04001004 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
1005 if (ret) {
1006 return ret;
pbrook53a59602006-03-25 19:31:22 +00001007 }
ths3b46e622007-09-17 08:09:54 +00001008
ths26edcf42007-12-09 02:25:24 +00001009 if (target_tv_addr) {
ths788f5ec2007-12-09 02:37:05 +00001010 if (copy_from_user_timeval(&tv, target_tv_addr))
1011 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001012 tv_ptr = &tv;
1013 } else {
1014 tv_ptr = NULL;
1015 }
ths26edcf42007-12-09 02:25:24 +00001016
bellard31e31b82003-02-18 22:55:36 +00001017 ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
pbrook53a59602006-03-25 19:31:22 +00001018
ths26edcf42007-12-09 02:25:24 +00001019 if (!is_error(ret)) {
1020 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
1021 return -TARGET_EFAULT;
1022 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
1023 return -TARGET_EFAULT;
1024 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1025 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001026
ths788f5ec2007-12-09 02:37:05 +00001027 if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
1028 return -TARGET_EFAULT;
bellard31e31b82003-02-18 22:55:36 +00001029 }
bellard579a97f2007-11-11 14:26:47 +00001030
bellard31e31b82003-02-18 22:55:36 +00001031 return ret;
1032}
Mike Frysinger055e0902011-06-03 17:01:49 -04001033#endif
bellard31e31b82003-02-18 22:55:36 +00001034
Riku Voipio099d6b02009-05-05 12:10:04 +03001035static abi_long do_pipe2(int host_pipe[], int flags)
1036{
1037#ifdef CONFIG_PIPE2
1038 return pipe2(host_pipe, flags);
1039#else
1040 return -ENOSYS;
1041#endif
1042}
1043
Richard Hendersonfb41a662010-05-03 10:07:52 -07001044static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
1045 int flags, int is_pipe2)
Riku Voipio099d6b02009-05-05 12:10:04 +03001046{
1047 int host_pipe[2];
1048 abi_long ret;
1049 ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
1050
1051 if (is_error(ret))
1052 return get_errno(ret);
Richard Hendersonfb41a662010-05-03 10:07:52 -07001053
1054 /* Several targets have special calling conventions for the original
1055 pipe syscall, but didn't replicate this into the pipe2 syscall. */
1056 if (!is_pipe2) {
1057#if defined(TARGET_ALPHA)
1058 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
1059 return host_pipe[0];
1060#elif defined(TARGET_MIPS)
1061 ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
1062 return host_pipe[0];
1063#elif defined(TARGET_SH4)
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001064 ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
Richard Hendersonfb41a662010-05-03 10:07:52 -07001065 return host_pipe[0];
Peter Maydell82f05b62013-07-06 17:39:48 +01001066#elif defined(TARGET_SPARC)
1067 ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
1068 return host_pipe[0];
takasi-y@ops.dti.ne.jp597c0212010-02-18 00:35:03 +09001069#endif
Richard Hendersonfb41a662010-05-03 10:07:52 -07001070 }
1071
Riku Voipio099d6b02009-05-05 12:10:04 +03001072 if (put_user_s32(host_pipe[0], pipedes)
1073 || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
1074 return -TARGET_EFAULT;
Riku Voipio099d6b02009-05-05 12:10:04 +03001075 return get_errno(ret);
1076}
1077
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001078static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
1079 abi_ulong target_addr,
1080 socklen_t len)
1081{
1082 struct target_ip_mreqn *target_smreqn;
1083
1084 target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
1085 if (!target_smreqn)
1086 return -TARGET_EFAULT;
1087 mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
1088 mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
1089 if (len == sizeof(struct target_ip_mreqn))
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001090 mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001091 unlock_user(target_smreqn, target_addr, 0);
1092
1093 return 0;
1094}
1095
bellard579a97f2007-11-11 14:26:47 +00001096static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
1097 abi_ulong target_addr,
1098 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001099{
aurel32607175e2009-04-15 16:11:59 +00001100 const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
1101 sa_family_t sa_family;
pbrook53a59602006-03-25 19:31:22 +00001102 struct target_sockaddr *target_saddr;
1103
bellard579a97f2007-11-11 14:26:47 +00001104 target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
1105 if (!target_saddr)
1106 return -TARGET_EFAULT;
aurel32607175e2009-04-15 16:11:59 +00001107
1108 sa_family = tswap16(target_saddr->sa_family);
1109
1110 /* Oops. The caller might send a incomplete sun_path; sun_path
1111 * must be terminated by \0 (see the manual page), but
1112 * unfortunately it is quite common to specify sockaddr_un
1113 * length as "strlen(x->sun_path)" while it should be
1114 * "strlen(...) + 1". We'll fix that here if needed.
1115 * Linux kernel has a similar feature.
1116 */
1117
1118 if (sa_family == AF_UNIX) {
1119 if (len < unix_maxlen && len > 0) {
1120 char *cp = (char*)target_saddr;
1121
1122 if ( cp[len-1] && !cp[len] )
1123 len++;
1124 }
1125 if (len > unix_maxlen)
1126 len = unix_maxlen;
1127 }
1128
pbrook53a59602006-03-25 19:31:22 +00001129 memcpy(addr, target_saddr, len);
aurel32607175e2009-04-15 16:11:59 +00001130 addr->sa_family = sa_family;
pbrook53a59602006-03-25 19:31:22 +00001131 unlock_user(target_saddr, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00001132
1133 return 0;
bellard7854b052003-03-29 17:22:23 +00001134}
1135
bellard579a97f2007-11-11 14:26:47 +00001136static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
1137 struct sockaddr *addr,
1138 socklen_t len)
bellard7854b052003-03-29 17:22:23 +00001139{
pbrook53a59602006-03-25 19:31:22 +00001140 struct target_sockaddr *target_saddr;
1141
bellard579a97f2007-11-11 14:26:47 +00001142 target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
1143 if (!target_saddr)
1144 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00001145 memcpy(target_saddr, addr, len);
1146 target_saddr->sa_family = tswap16(addr->sa_family);
1147 unlock_user(target_saddr, target_addr, len);
bellard579a97f2007-11-11 14:26:47 +00001148
1149 return 0;
bellard7854b052003-03-29 17:22:23 +00001150}
1151
bellard5a4a8982007-11-11 17:39:18 +00001152static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
1153 struct target_msghdr *target_msgh)
bellard7854b052003-03-29 17:22:23 +00001154{
1155 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001156 abi_long msg_controllen;
1157 abi_ulong target_cmsg_addr;
1158 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001159 socklen_t space = 0;
bellard5a4a8982007-11-11 17:39:18 +00001160
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001161 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001162 if (msg_controllen < sizeof (struct target_cmsghdr))
1163 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001164 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001165 target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
1166 if (!target_cmsg)
1167 return -TARGET_EFAULT;
bellard7854b052003-03-29 17:22:23 +00001168
1169 while (cmsg && target_cmsg) {
1170 void *data = CMSG_DATA(cmsg);
1171 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1172
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001173 int len = tswapal(target_cmsg->cmsg_len)
bellard7854b052003-03-29 17:22:23 +00001174 - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
1175
1176 space += CMSG_SPACE(len);
1177 if (space > msgh->msg_controllen) {
1178 space -= CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001179 gemu_log("Host cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001180 break;
1181 }
1182
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001183 if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
1184 cmsg->cmsg_level = SOL_SOCKET;
1185 } else {
1186 cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
1187 }
bellard7854b052003-03-29 17:22:23 +00001188 cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
1189 cmsg->cmsg_len = CMSG_LEN(len);
1190
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001191 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
bellard7854b052003-03-29 17:22:23 +00001192 gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
1193 memcpy(data, target_data, len);
1194 } else {
1195 int *fd = (int *)data;
1196 int *target_fd = (int *)target_data;
1197 int i, numfds = len / sizeof(int);
1198
1199 for (i = 0; i < numfds; i++)
1200 fd[i] = tswap32(target_fd[i]);
1201 }
1202
1203 cmsg = CMSG_NXTHDR(msgh, cmsg);
1204 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1205 }
bellard5a4a8982007-11-11 17:39:18 +00001206 unlock_user(target_cmsg, target_cmsg_addr, 0);
1207 the_end:
bellard7854b052003-03-29 17:22:23 +00001208 msgh->msg_controllen = space;
bellard5a4a8982007-11-11 17:39:18 +00001209 return 0;
bellard7854b052003-03-29 17:22:23 +00001210}
1211
bellard5a4a8982007-11-11 17:39:18 +00001212static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
1213 struct msghdr *msgh)
bellard7854b052003-03-29 17:22:23 +00001214{
1215 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
bellard5a4a8982007-11-11 17:39:18 +00001216 abi_long msg_controllen;
1217 abi_ulong target_cmsg_addr;
1218 struct target_cmsghdr *target_cmsg;
bellard7854b052003-03-29 17:22:23 +00001219 socklen_t space = 0;
1220
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001221 msg_controllen = tswapal(target_msgh->msg_controllen);
bellard5a4a8982007-11-11 17:39:18 +00001222 if (msg_controllen < sizeof (struct target_cmsghdr))
1223 goto the_end;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001224 target_cmsg_addr = tswapal(target_msgh->msg_control);
bellard5a4a8982007-11-11 17:39:18 +00001225 target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
1226 if (!target_cmsg)
1227 return -TARGET_EFAULT;
1228
bellard7854b052003-03-29 17:22:23 +00001229 while (cmsg && target_cmsg) {
1230 void *data = CMSG_DATA(cmsg);
1231 void *target_data = TARGET_CMSG_DATA(target_cmsg);
1232
1233 int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
1234
1235 space += TARGET_CMSG_SPACE(len);
bellard5a4a8982007-11-11 17:39:18 +00001236 if (space > msg_controllen) {
bellard7854b052003-03-29 17:22:23 +00001237 space -= TARGET_CMSG_SPACE(len);
bellard31febb72005-12-18 20:03:27 +00001238 gemu_log("Target cmsg overflow\n");
bellard7854b052003-03-29 17:22:23 +00001239 break;
1240 }
1241
Petar Jovanovicdbf4f792013-09-13 19:27:29 +02001242 if (cmsg->cmsg_level == SOL_SOCKET) {
1243 target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
1244 } else {
1245 target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
1246 }
bellard7854b052003-03-29 17:22:23 +00001247 target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001248 target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
bellard7854b052003-03-29 17:22:23 +00001249
Huw Davies52b65492014-04-17 14:02:47 +01001250 switch (cmsg->cmsg_level) {
1251 case SOL_SOCKET:
1252 switch (cmsg->cmsg_type) {
1253 case SCM_RIGHTS:
1254 {
1255 int *fd = (int *)data;
1256 int *target_fd = (int *)target_data;
1257 int i, numfds = len / sizeof(int);
bellard7854b052003-03-29 17:22:23 +00001258
Huw Davies52b65492014-04-17 14:02:47 +01001259 for (i = 0; i < numfds; i++)
1260 target_fd[i] = tswap32(fd[i]);
1261 break;
1262 }
1263 case SO_TIMESTAMP:
1264 {
1265 struct timeval *tv = (struct timeval *)data;
1266 struct target_timeval *target_tv =
1267 (struct target_timeval *)target_data;
Jing Huangaebf5bc2012-07-24 14:01:42 +00001268
Huw Davies52b65492014-04-17 14:02:47 +01001269 if (len != sizeof(struct timeval))
1270 goto unimplemented;
1271
1272 /* copy struct timeval to target */
1273 target_tv->tv_sec = tswapal(tv->tv_sec);
1274 target_tv->tv_usec = tswapal(tv->tv_usec);
1275 break;
1276 }
Huw Davies4bc29752014-04-17 14:02:48 +01001277 case SCM_CREDENTIALS:
1278 {
1279 struct ucred *cred = (struct ucred *)data;
1280 struct target_ucred *target_cred =
1281 (struct target_ucred *)target_data;
1282
1283 __put_user(cred->pid, &target_cred->pid);
1284 __put_user(cred->uid, &target_cred->uid);
1285 __put_user(cred->gid, &target_cred->gid);
1286 break;
1287 }
Huw Davies52b65492014-04-17 14:02:47 +01001288 default:
1289 goto unimplemented;
1290 }
1291 break;
1292
1293 default:
1294 unimplemented:
Jing Huangaebf5bc2012-07-24 14:01:42 +00001295 gemu_log("Unsupported ancillary data: %d/%d\n",
1296 cmsg->cmsg_level, cmsg->cmsg_type);
1297 memcpy(target_data, data, len);
bellard7854b052003-03-29 17:22:23 +00001298 }
1299
1300 cmsg = CMSG_NXTHDR(msgh, cmsg);
1301 target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
1302 }
bellard5a4a8982007-11-11 17:39:18 +00001303 unlock_user(target_cmsg, target_cmsg_addr, space);
1304 the_end:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001305 target_msgh->msg_controllen = tswapal(space);
bellard5a4a8982007-11-11 17:39:18 +00001306 return 0;
bellard7854b052003-03-29 17:22:23 +00001307}
1308
ths0da46a62007-10-20 20:23:07 +00001309/* do_setsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001310static abi_long do_setsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001311 abi_ulong optval_addr, socklen_t optlen)
bellard7854b052003-03-29 17:22:23 +00001312{
blueswir1992f48a2007-10-14 16:27:31 +00001313 abi_long ret;
j_mayer32407102007-09-26 23:01:49 +00001314 int val;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001315 struct ip_mreqn *ip_mreq;
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001316 struct ip_mreq_source *ip_mreq_source;
ths3b46e622007-09-17 08:09:54 +00001317
bellard8853f862004-02-22 14:57:26 +00001318 switch(level) {
1319 case SOL_TCP:
bellard7854b052003-03-29 17:22:23 +00001320 /* TCP options all take an 'int' value. */
bellard7854b052003-03-29 17:22:23 +00001321 if (optlen < sizeof(uint32_t))
ths0da46a62007-10-20 20:23:07 +00001322 return -TARGET_EINVAL;
ths3b46e622007-09-17 08:09:54 +00001323
bellard2f619692007-11-16 10:46:05 +00001324 if (get_user_u32(val, optval_addr))
1325 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001326 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1327 break;
1328 case SOL_IP:
1329 switch(optname) {
bellard2efbe912005-07-23 15:10:20 +00001330 case IP_TOS:
1331 case IP_TTL:
bellard8853f862004-02-22 14:57:26 +00001332 case IP_HDRINCL:
bellard2efbe912005-07-23 15:10:20 +00001333 case IP_ROUTER_ALERT:
1334 case IP_RECVOPTS:
1335 case IP_RETOPTS:
1336 case IP_PKTINFO:
1337 case IP_MTU_DISCOVER:
1338 case IP_RECVERR:
1339 case IP_RECVTOS:
1340#ifdef IP_FREEBIND
1341 case IP_FREEBIND:
1342#endif
1343 case IP_MULTICAST_TTL:
1344 case IP_MULTICAST_LOOP:
bellard8853f862004-02-22 14:57:26 +00001345 val = 0;
1346 if (optlen >= sizeof(uint32_t)) {
bellard2f619692007-11-16 10:46:05 +00001347 if (get_user_u32(val, optval_addr))
1348 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001349 } else if (optlen >= 1) {
bellard2f619692007-11-16 10:46:05 +00001350 if (get_user_u8(val, optval_addr))
1351 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001352 }
1353 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1354 break;
Lionel Landwerlinb975b832009-04-25 23:30:19 +02001355 case IP_ADD_MEMBERSHIP:
1356 case IP_DROP_MEMBERSHIP:
1357 if (optlen < sizeof (struct target_ip_mreq) ||
1358 optlen > sizeof (struct target_ip_mreqn))
1359 return -TARGET_EINVAL;
1360
1361 ip_mreq = (struct ip_mreqn *) alloca(optlen);
1362 target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
1363 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
1364 break;
1365
Lionel Landwerlin6e3cb582009-04-25 23:31:18 +02001366 case IP_BLOCK_SOURCE:
1367 case IP_UNBLOCK_SOURCE:
1368 case IP_ADD_SOURCE_MEMBERSHIP:
1369 case IP_DROP_SOURCE_MEMBERSHIP:
1370 if (optlen != sizeof (struct target_ip_mreq_source))
1371 return -TARGET_EINVAL;
1372
1373 ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
1374 ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
1375 unlock_user (ip_mreq_source, optval_addr, 0);
1376 break;
1377
bellard8853f862004-02-22 14:57:26 +00001378 default:
1379 goto unimplemented;
1380 }
1381 break;
Laurent Vivier0d78b3b2013-08-30 01:46:43 +02001382 case SOL_IPV6:
1383 switch (optname) {
1384 case IPV6_MTU_DISCOVER:
1385 case IPV6_MTU:
1386 case IPV6_V6ONLY:
1387 case IPV6_RECVPKTINFO:
1388 val = 0;
1389 if (optlen < sizeof(uint32_t)) {
1390 return -TARGET_EINVAL;
1391 }
1392 if (get_user_u32(val, optval_addr)) {
1393 return -TARGET_EFAULT;
1394 }
1395 ret = get_errno(setsockopt(sockfd, level, optname,
1396 &val, sizeof(val)));
1397 break;
1398 default:
1399 goto unimplemented;
1400 }
1401 break;
Jing Huang920394d2012-07-24 13:59:23 +00001402 case SOL_RAW:
1403 switch (optname) {
1404 case ICMP_FILTER:
1405 /* struct icmp_filter takes an u32 value */
1406 if (optlen < sizeof(uint32_t)) {
1407 return -TARGET_EINVAL;
1408 }
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
1417 default:
1418 goto unimplemented;
1419 }
1420 break;
bellard3532fa72006-06-24 15:06:03 +00001421 case TARGET_SOL_SOCKET:
bellard8853f862004-02-22 14:57:26 +00001422 switch (optname) {
Laurent Vivier1b09aeb2013-01-01 08:24:11 +00001423 case TARGET_SO_RCVTIMEO:
1424 {
1425 struct timeval tv;
1426
1427 optname = SO_RCVTIMEO;
1428
1429set_timeout:
1430 if (optlen != sizeof(struct target_timeval)) {
1431 return -TARGET_EINVAL;
1432 }
1433
1434 if (copy_from_user_timeval(&tv, optval_addr)) {
1435 return -TARGET_EFAULT;
1436 }
1437
1438 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname,
1439 &tv, sizeof(tv)));
1440 return ret;
1441 }
1442 case TARGET_SO_SNDTIMEO:
1443 optname = SO_SNDTIMEO;
1444 goto set_timeout;
Laurent Vivierf57d4192013-08-30 01:46:41 +02001445 case TARGET_SO_ATTACH_FILTER:
1446 {
1447 struct target_sock_fprog *tfprog;
1448 struct target_sock_filter *tfilter;
1449 struct sock_fprog fprog;
1450 struct sock_filter *filter;
1451 int i;
1452
1453 if (optlen != sizeof(*tfprog)) {
1454 return -TARGET_EINVAL;
1455 }
1456 if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
1457 return -TARGET_EFAULT;
1458 }
1459 if (!lock_user_struct(VERIFY_READ, tfilter,
1460 tswapal(tfprog->filter), 0)) {
1461 unlock_user_struct(tfprog, optval_addr, 1);
1462 return -TARGET_EFAULT;
1463 }
1464
1465 fprog.len = tswap16(tfprog->len);
1466 filter = malloc(fprog.len * sizeof(*filter));
1467 if (filter == NULL) {
1468 unlock_user_struct(tfilter, tfprog->filter, 1);
1469 unlock_user_struct(tfprog, optval_addr, 1);
1470 return -TARGET_ENOMEM;
1471 }
1472 for (i = 0; i < fprog.len; i++) {
1473 filter[i].code = tswap16(tfilter[i].code);
1474 filter[i].jt = tfilter[i].jt;
1475 filter[i].jf = tfilter[i].jf;
1476 filter[i].k = tswap32(tfilter[i].k);
1477 }
1478 fprog.filter = filter;
1479
1480 ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
1481 SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
1482 free(filter);
1483
1484 unlock_user_struct(tfilter, tfprog->filter, 1);
1485 unlock_user_struct(tfprog, optval_addr, 1);
1486 return ret;
1487 }
bellard8853f862004-02-22 14:57:26 +00001488 /* Options with 'int' argument. */
bellard3532fa72006-06-24 15:06:03 +00001489 case TARGET_SO_DEBUG:
1490 optname = SO_DEBUG;
1491 break;
1492 case TARGET_SO_REUSEADDR:
1493 optname = SO_REUSEADDR;
1494 break;
1495 case TARGET_SO_TYPE:
1496 optname = SO_TYPE;
1497 break;
1498 case TARGET_SO_ERROR:
1499 optname = SO_ERROR;
1500 break;
1501 case TARGET_SO_DONTROUTE:
1502 optname = SO_DONTROUTE;
1503 break;
1504 case TARGET_SO_BROADCAST:
1505 optname = SO_BROADCAST;
1506 break;
1507 case TARGET_SO_SNDBUF:
1508 optname = SO_SNDBUF;
1509 break;
1510 case TARGET_SO_RCVBUF:
1511 optname = SO_RCVBUF;
1512 break;
1513 case TARGET_SO_KEEPALIVE:
1514 optname = SO_KEEPALIVE;
1515 break;
1516 case TARGET_SO_OOBINLINE:
1517 optname = SO_OOBINLINE;
1518 break;
1519 case TARGET_SO_NO_CHECK:
1520 optname = SO_NO_CHECK;
1521 break;
1522 case TARGET_SO_PRIORITY:
1523 optname = SO_PRIORITY;
1524 break;
bellard5e83e8e2005-03-01 22:32:06 +00001525#ifdef SO_BSDCOMPAT
bellard3532fa72006-06-24 15:06:03 +00001526 case TARGET_SO_BSDCOMPAT:
1527 optname = SO_BSDCOMPAT;
1528 break;
bellard5e83e8e2005-03-01 22:32:06 +00001529#endif
bellard3532fa72006-06-24 15:06:03 +00001530 case TARGET_SO_PASSCRED:
1531 optname = SO_PASSCRED;
1532 break;
1533 case TARGET_SO_TIMESTAMP:
1534 optname = SO_TIMESTAMP;
1535 break;
1536 case TARGET_SO_RCVLOWAT:
1537 optname = SO_RCVLOWAT;
1538 break;
bellard8853f862004-02-22 14:57:26 +00001539 break;
1540 default:
1541 goto unimplemented;
1542 }
bellard3532fa72006-06-24 15:06:03 +00001543 if (optlen < sizeof(uint32_t))
bellard2f619692007-11-16 10:46:05 +00001544 return -TARGET_EINVAL;
bellard3532fa72006-06-24 15:06:03 +00001545
bellard2f619692007-11-16 10:46:05 +00001546 if (get_user_u32(val, optval_addr))
1547 return -TARGET_EFAULT;
bellard3532fa72006-06-24 15:06:03 +00001548 ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
bellard8853f862004-02-22 14:57:26 +00001549 break;
bellard7854b052003-03-29 17:22:23 +00001550 default:
bellard8853f862004-02-22 14:57:26 +00001551 unimplemented:
Stefan Weilb2bedb22011-09-12 22:33:01 +02001552 gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
ths6fa13c12007-12-18 02:41:04 +00001553 ret = -TARGET_ENOPROTOOPT;
bellard7854b052003-03-29 17:22:23 +00001554 }
bellard8853f862004-02-22 14:57:26 +00001555 return ret;
bellard7854b052003-03-29 17:22:23 +00001556}
1557
ths0da46a62007-10-20 20:23:07 +00001558/* do_getsockopt() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001559static abi_long do_getsockopt(int sockfd, int level, int optname,
bellard2f619692007-11-16 10:46:05 +00001560 abi_ulong optval_addr, abi_ulong optlen)
bellard7854b052003-03-29 17:22:23 +00001561{
blueswir1992f48a2007-10-14 16:27:31 +00001562 abi_long ret;
blueswir1b55266b2008-09-20 08:07:15 +00001563 int len, val;
1564 socklen_t lv;
bellard8853f862004-02-22 14:57:26 +00001565
1566 switch(level) {
bellard3532fa72006-06-24 15:06:03 +00001567 case TARGET_SOL_SOCKET:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001568 level = SOL_SOCKET;
1569 switch (optname) {
1570 /* These don't just return a single integer */
1571 case TARGET_SO_LINGER:
1572 case TARGET_SO_RCVTIMEO:
1573 case TARGET_SO_SNDTIMEO:
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001574 case TARGET_SO_PEERNAME:
1575 goto unimplemented;
Akos PASZTORY583359a2011-11-14 15:09:49 +02001576 case TARGET_SO_PEERCRED: {
1577 struct ucred cr;
1578 socklen_t crlen;
1579 struct target_ucred *tcr;
1580
1581 if (get_user_u32(len, optlen)) {
1582 return -TARGET_EFAULT;
1583 }
1584 if (len < 0) {
1585 return -TARGET_EINVAL;
1586 }
1587
1588 crlen = sizeof(cr);
1589 ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
1590 &cr, &crlen));
1591 if (ret < 0) {
1592 return ret;
1593 }
1594 if (len > crlen) {
1595 len = crlen;
1596 }
1597 if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
1598 return -TARGET_EFAULT;
1599 }
1600 __put_user(cr.pid, &tcr->pid);
1601 __put_user(cr.uid, &tcr->uid);
1602 __put_user(cr.gid, &tcr->gid);
1603 unlock_user_struct(tcr, optval_addr, 1);
1604 if (put_user_u32(len, optlen)) {
1605 return -TARGET_EFAULT;
1606 }
1607 break;
1608 }
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001609 /* Options with 'int' argument. */
1610 case TARGET_SO_DEBUG:
1611 optname = SO_DEBUG;
1612 goto int_case;
1613 case TARGET_SO_REUSEADDR:
1614 optname = SO_REUSEADDR;
1615 goto int_case;
1616 case TARGET_SO_TYPE:
1617 optname = SO_TYPE;
1618 goto int_case;
1619 case TARGET_SO_ERROR:
1620 optname = SO_ERROR;
1621 goto int_case;
1622 case TARGET_SO_DONTROUTE:
1623 optname = SO_DONTROUTE;
1624 goto int_case;
1625 case TARGET_SO_BROADCAST:
1626 optname = SO_BROADCAST;
1627 goto int_case;
1628 case TARGET_SO_SNDBUF:
1629 optname = SO_SNDBUF;
1630 goto int_case;
1631 case TARGET_SO_RCVBUF:
1632 optname = SO_RCVBUF;
1633 goto int_case;
1634 case TARGET_SO_KEEPALIVE:
1635 optname = SO_KEEPALIVE;
1636 goto int_case;
1637 case TARGET_SO_OOBINLINE:
1638 optname = SO_OOBINLINE;
1639 goto int_case;
1640 case TARGET_SO_NO_CHECK:
1641 optname = SO_NO_CHECK;
1642 goto int_case;
1643 case TARGET_SO_PRIORITY:
1644 optname = SO_PRIORITY;
1645 goto int_case;
1646#ifdef SO_BSDCOMPAT
1647 case TARGET_SO_BSDCOMPAT:
1648 optname = SO_BSDCOMPAT;
1649 goto int_case;
1650#endif
1651 case TARGET_SO_PASSCRED:
1652 optname = SO_PASSCRED;
1653 goto int_case;
1654 case TARGET_SO_TIMESTAMP:
1655 optname = SO_TIMESTAMP;
1656 goto int_case;
1657 case TARGET_SO_RCVLOWAT:
1658 optname = SO_RCVLOWAT;
1659 goto int_case;
bellard8853f862004-02-22 14:57:26 +00001660 default:
bellard2efbe912005-07-23 15:10:20 +00001661 goto int_case;
1662 }
1663 break;
1664 case SOL_TCP:
1665 /* TCP options all take an 'int' value. */
1666 int_case:
bellard2f619692007-11-16 10:46:05 +00001667 if (get_user_u32(len, optlen))
1668 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001669 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001670 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001671 lv = sizeof(lv);
bellard2efbe912005-07-23 15:10:20 +00001672 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1673 if (ret < 0)
1674 return ret;
bellard2efbe912005-07-23 15:10:20 +00001675 if (len > lv)
1676 len = lv;
bellard2f619692007-11-16 10:46:05 +00001677 if (len == 4) {
1678 if (put_user_u32(val, optval_addr))
1679 return -TARGET_EFAULT;
1680 } else {
1681 if (put_user_u8(val, optval_addr))
1682 return -TARGET_EFAULT;
Jamie Lentinf3b974c2010-11-26 15:04:08 +02001683 }
bellard2f619692007-11-16 10:46:05 +00001684 if (put_user_u32(len, optlen))
1685 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001686 break;
1687 case SOL_IP:
1688 switch(optname) {
1689 case IP_TOS:
1690 case IP_TTL:
1691 case IP_HDRINCL:
1692 case IP_ROUTER_ALERT:
1693 case IP_RECVOPTS:
1694 case IP_RETOPTS:
1695 case IP_PKTINFO:
1696 case IP_MTU_DISCOVER:
1697 case IP_RECVERR:
1698 case IP_RECVTOS:
1699#ifdef IP_FREEBIND
1700 case IP_FREEBIND:
1701#endif
1702 case IP_MULTICAST_TTL:
1703 case IP_MULTICAST_LOOP:
bellard2f619692007-11-16 10:46:05 +00001704 if (get_user_u32(len, optlen))
1705 return -TARGET_EFAULT;
bellard8853f862004-02-22 14:57:26 +00001706 if (len < 0)
ths0da46a62007-10-20 20:23:07 +00001707 return -TARGET_EINVAL;
Mike Frysinger73160d92011-02-07 01:05:49 -05001708 lv = sizeof(lv);
bellard8853f862004-02-22 14:57:26 +00001709 ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
1710 if (ret < 0)
1711 return ret;
bellard2efbe912005-07-23 15:10:20 +00001712 if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
bellard2efbe912005-07-23 15:10:20 +00001713 len = 1;
bellard2f619692007-11-16 10:46:05 +00001714 if (put_user_u32(len, optlen)
1715 || put_user_u8(val, optval_addr))
1716 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001717 } else {
bellard2efbe912005-07-23 15:10:20 +00001718 if (len > sizeof(int))
1719 len = sizeof(int);
bellard2f619692007-11-16 10:46:05 +00001720 if (put_user_u32(len, optlen)
1721 || put_user_u32(val, optval_addr))
1722 return -TARGET_EFAULT;
bellard2efbe912005-07-23 15:10:20 +00001723 }
bellard8853f862004-02-22 14:57:26 +00001724 break;
bellard2efbe912005-07-23 15:10:20 +00001725 default:
thsc02f4992007-12-18 02:39:59 +00001726 ret = -TARGET_ENOPROTOOPT;
1727 break;
bellard8853f862004-02-22 14:57:26 +00001728 }
1729 break;
1730 default:
1731 unimplemented:
1732 gemu_log("getsockopt level=%d optname=%d not yet supported\n",
1733 level, optname);
thsc02f4992007-12-18 02:39:59 +00001734 ret = -TARGET_EOPNOTSUPP;
bellard8853f862004-02-22 14:57:26 +00001735 break;
1736 }
1737 return ret;
bellard7854b052003-03-29 17:22:23 +00001738}
1739
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001740static struct iovec *lock_iovec(int type, abi_ulong target_addr,
1741 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001742{
1743 struct target_iovec *target_vec;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001744 struct iovec *vec;
1745 abi_ulong total_len, max_len;
balrogd732dcb2008-10-28 10:21:03 +00001746 int i;
Peter Maydell501bb4b2014-02-17 18:55:33 +00001747 int err = 0;
pbrook53a59602006-03-25 19:31:22 +00001748
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001749 if (count == 0) {
1750 errno = 0;
1751 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001752 }
Peter Maydelldfae8e02013-02-08 07:58:41 +00001753 if (count < 0 || count > IOV_MAX) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001754 errno = EINVAL;
1755 return NULL;
1756 }
1757
1758 vec = calloc(count, sizeof(struct iovec));
1759 if (vec == NULL) {
1760 errno = ENOMEM;
1761 return NULL;
1762 }
1763
1764 target_vec = lock_user(VERIFY_READ, target_addr,
1765 count * sizeof(struct target_iovec), 1);
1766 if (target_vec == NULL) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001767 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001768 goto fail2;
1769 }
1770
1771 /* ??? If host page size > target page size, this will result in a
1772 value larger than what we can actually support. */
1773 max_len = 0x7fffffff & TARGET_PAGE_MASK;
1774 total_len = 0;
1775
1776 for (i = 0; i < count; i++) {
1777 abi_ulong base = tswapal(target_vec[i].iov_base);
1778 abi_long len = tswapal(target_vec[i].iov_len);
1779
1780 if (len < 0) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001781 err = EINVAL;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001782 goto fail;
1783 } else if (len == 0) {
1784 /* Zero length pointer is ignored. */
1785 vec[i].iov_base = 0;
1786 } else {
1787 vec[i].iov_base = lock_user(type, base, len, copy);
1788 if (!vec[i].iov_base) {
Peter Maydell501bb4b2014-02-17 18:55:33 +00001789 err = EFAULT;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001790 goto fail;
1791 }
1792 if (len > max_len - total_len) {
1793 len = max_len - total_len;
1794 }
1795 }
1796 vec[i].iov_len = len;
1797 total_len += len;
1798 }
1799
1800 unlock_user(target_vec, target_addr, 0);
1801 return vec;
1802
1803 fail:
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001804 unlock_user(target_vec, target_addr, 0);
Peter Maydell501bb4b2014-02-17 18:55:33 +00001805 fail2:
1806 free(vec);
1807 errno = err;
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001808 return NULL;
pbrook53a59602006-03-25 19:31:22 +00001809}
1810
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001811static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
1812 int count, int copy)
pbrook53a59602006-03-25 19:31:22 +00001813{
1814 struct target_iovec *target_vec;
pbrook53a59602006-03-25 19:31:22 +00001815 int i;
1816
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001817 target_vec = lock_user(VERIFY_READ, target_addr,
1818 count * sizeof(struct target_iovec), 1);
1819 if (target_vec) {
1820 for (i = 0; i < count; i++) {
1821 abi_ulong base = tswapal(target_vec[i].iov_base);
1822 abi_long len = tswapal(target_vec[i].iov_base);
1823 if (len < 0) {
1824 break;
1825 }
balrogd732dcb2008-10-28 10:21:03 +00001826 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
1827 }
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001828 unlock_user(target_vec, target_addr, 0);
pbrook53a59602006-03-25 19:31:22 +00001829 }
bellard579a97f2007-11-11 14:26:47 +00001830
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001831 free(vec);
pbrook53a59602006-03-25 19:31:22 +00001832}
1833
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001834static inline int target_to_host_sock_type(int *type)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001835{
1836 int host_type = 0;
1837 int target_type = *type;
1838
1839 switch (target_type & TARGET_SOCK_TYPE_MASK) {
1840 case TARGET_SOCK_DGRAM:
1841 host_type = SOCK_DGRAM;
1842 break;
1843 case TARGET_SOCK_STREAM:
1844 host_type = SOCK_STREAM;
1845 break;
1846 default:
1847 host_type = target_type & TARGET_SOCK_TYPE_MASK;
1848 break;
1849 }
1850 if (target_type & TARGET_SOCK_CLOEXEC) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001851#if defined(SOCK_CLOEXEC)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001852 host_type |= SOCK_CLOEXEC;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001853#else
1854 return -TARGET_EINVAL;
1855#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001856 }
1857 if (target_type & TARGET_SOCK_NONBLOCK) {
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001858#if defined(SOCK_NONBLOCK)
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001859 host_type |= SOCK_NONBLOCK;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001860#elif !defined(O_NONBLOCK)
1861 return -TARGET_EINVAL;
1862#endif
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001863 }
1864 *type = host_type;
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001865 return 0;
1866}
1867
1868/* Try to emulate socket type flags after socket creation. */
1869static int sock_flags_fixup(int fd, int target_type)
1870{
1871#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
1872 if (target_type & TARGET_SOCK_NONBLOCK) {
1873 int flags = fcntl(fd, F_GETFL);
1874 if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
1875 close(fd);
1876 return -TARGET_EINVAL;
1877 }
1878 }
1879#endif
1880 return fd;
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001881}
1882
ths0da46a62007-10-20 20:23:07 +00001883/* do_socket() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001884static abi_long do_socket(int domain, int type, int protocol)
bellard3532fa72006-06-24 15:06:03 +00001885{
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001886 int target_type = type;
1887 int ret;
1888
1889 ret = target_to_host_sock_type(&type);
1890 if (ret) {
1891 return ret;
1892 }
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02001893
balrog12bc92a2007-10-30 21:06:14 +00001894 if (domain == PF_NETLINK)
1895 return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
Edgar E. Iglesias53d09b72013-09-23 14:11:53 +02001896 ret = get_errno(socket(domain, type, protocol));
1897 if (ret >= 0) {
1898 ret = sock_flags_fixup(ret, target_type);
1899 }
1900 return ret;
bellard3532fa72006-06-24 15:06:03 +00001901}
1902
ths0da46a62007-10-20 20:23:07 +00001903/* do_bind() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001904static abi_long do_bind(int sockfd, abi_ulong target_addr,
1905 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001906{
aurel328f7aeaf2009-01-30 19:47:57 +00001907 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001908 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001909
Blue Swirl38724252010-09-18 05:53:14 +00001910 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001911 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001912 }
aurel328f7aeaf2009-01-30 19:47:57 +00001913
aurel32607175e2009-04-15 16:11:59 +00001914 addr = alloca(addrlen+1);
ths3b46e622007-09-17 08:09:54 +00001915
Arnaud Patard917507b2009-06-19 10:44:45 +03001916 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1917 if (ret)
1918 return ret;
1919
bellard3532fa72006-06-24 15:06:03 +00001920 return get_errno(bind(sockfd, addr, addrlen));
1921}
1922
ths0da46a62007-10-20 20:23:07 +00001923/* do_connect() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00001924static abi_long do_connect(int sockfd, abi_ulong target_addr,
1925 socklen_t addrlen)
bellard3532fa72006-06-24 15:06:03 +00001926{
aurel328f7aeaf2009-01-30 19:47:57 +00001927 void *addr;
Arnaud Patard917507b2009-06-19 10:44:45 +03001928 abi_long ret;
aurel328f7aeaf2009-01-30 19:47:57 +00001929
Blue Swirl38724252010-09-18 05:53:14 +00001930 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00001931 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00001932 }
aurel328f7aeaf2009-01-30 19:47:57 +00001933
1934 addr = alloca(addrlen);
ths3b46e622007-09-17 08:09:54 +00001935
Arnaud Patard917507b2009-06-19 10:44:45 +03001936 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
1937 if (ret)
1938 return ret;
1939
bellard3532fa72006-06-24 15:06:03 +00001940 return get_errno(connect(sockfd, addr, addrlen));
1941}
1942
Alexander Graff19e00d2014-03-02 19:36:42 +00001943/* do_sendrecvmsg_locked() Must return target values and target errnos. */
1944static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
1945 int flags, int send)
bellard3532fa72006-06-24 15:06:03 +00001946{
balrog6de645c2008-10-28 10:26:29 +00001947 abi_long ret, len;
bellard3532fa72006-06-24 15:06:03 +00001948 struct msghdr msg;
1949 int count;
1950 struct iovec *vec;
blueswir1992f48a2007-10-14 16:27:31 +00001951 abi_ulong target_vec;
bellard3532fa72006-06-24 15:06:03 +00001952
bellard3532fa72006-06-24 15:06:03 +00001953 if (msgp->msg_name) {
1954 msg.msg_namelen = tswap32(msgp->msg_namelen);
1955 msg.msg_name = alloca(msg.msg_namelen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001956 ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
bellard3532fa72006-06-24 15:06:03 +00001957 msg.msg_namelen);
Arnaud Patard917507b2009-06-19 10:44:45 +03001958 if (ret) {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001959 goto out2;
Arnaud Patard917507b2009-06-19 10:44:45 +03001960 }
bellard3532fa72006-06-24 15:06:03 +00001961 } else {
1962 msg.msg_name = NULL;
1963 msg.msg_namelen = 0;
1964 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001965 msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
bellard3532fa72006-06-24 15:06:03 +00001966 msg.msg_control = alloca(msg.msg_controllen);
1967 msg.msg_flags = tswap32(msgp->msg_flags);
ths3b46e622007-09-17 08:09:54 +00001968
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001969 count = tswapal(msgp->msg_iovlen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02001970 target_vec = tswapal(msgp->msg_iov);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07001971 vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
1972 target_vec, count, send);
1973 if (vec == NULL) {
1974 ret = -host_to_target_errno(errno);
1975 goto out2;
1976 }
bellard3532fa72006-06-24 15:06:03 +00001977 msg.msg_iovlen = count;
1978 msg.msg_iov = vec;
ths3b46e622007-09-17 08:09:54 +00001979
bellard3532fa72006-06-24 15:06:03 +00001980 if (send) {
bellard5a4a8982007-11-11 17:39:18 +00001981 ret = target_to_host_cmsg(&msg, msgp);
1982 if (ret == 0)
1983 ret = get_errno(sendmsg(fd, &msg, flags));
bellard3532fa72006-06-24 15:06:03 +00001984 } else {
1985 ret = get_errno(recvmsg(fd, &msg, flags));
balrog6de645c2008-10-28 10:26:29 +00001986 if (!is_error(ret)) {
1987 len = ret;
bellard5a4a8982007-11-11 17:39:18 +00001988 ret = host_to_target_cmsg(msgp, &msg);
Jing Huangca619062012-07-24 13:58:02 +00001989 if (!is_error(ret)) {
1990 msgp->msg_namelen = tswap32(msg.msg_namelen);
1991 if (msg.msg_name != NULL) {
1992 ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
1993 msg.msg_name, msg.msg_namelen);
1994 if (ret) {
1995 goto out;
1996 }
1997 }
1998
balrog6de645c2008-10-28 10:26:29 +00001999 ret = len;
Jing Huangca619062012-07-24 13:58:02 +00002000 }
balrog6de645c2008-10-28 10:26:29 +00002001 }
bellard3532fa72006-06-24 15:06:03 +00002002 }
Jing Huangca619062012-07-24 13:58:02 +00002003
2004out:
bellard3532fa72006-06-24 15:06:03 +00002005 unlock_iovec(vec, target_vec, count, !send);
Richard Hendersonf287b2c2012-09-15 13:20:25 -07002006out2:
Alexander Graff19e00d2014-03-02 19:36:42 +00002007 return ret;
2008}
2009
2010static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
2011 int flags, int send)
2012{
2013 abi_long ret;
2014 struct target_msghdr *msgp;
2015
2016 if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
2017 msgp,
2018 target_msg,
2019 send ? 1 : 0)) {
2020 return -TARGET_EFAULT;
2021 }
2022 ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
bellard579a97f2007-11-11 14:26:47 +00002023 unlock_user_struct(msgp, target_msg, send ? 0 : 1);
bellard3532fa72006-06-24 15:06:03 +00002024 return ret;
2025}
2026
Alexander Graff19e00d2014-03-02 19:36:42 +00002027#ifdef TARGET_NR_sendmmsg
2028/* We don't rely on the C library to have sendmmsg/recvmmsg support,
2029 * so it might not have this *mmsg-specific flag either.
2030 */
2031#ifndef MSG_WAITFORONE
2032#define MSG_WAITFORONE 0x10000
2033#endif
2034
2035static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
2036 unsigned int vlen, unsigned int flags,
2037 int send)
2038{
2039 struct target_mmsghdr *mmsgp;
2040 abi_long ret = 0;
2041 int i;
2042
2043 if (vlen > UIO_MAXIOV) {
2044 vlen = UIO_MAXIOV;
2045 }
2046
2047 mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
2048 if (!mmsgp) {
2049 return -TARGET_EFAULT;
2050 }
2051
2052 for (i = 0; i < vlen; i++) {
2053 ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
2054 if (is_error(ret)) {
2055 break;
2056 }
2057 mmsgp[i].msg_len = tswap32(ret);
2058 /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
2059 if (flags & MSG_WAITFORONE) {
2060 flags |= MSG_DONTWAIT;
2061 }
2062 }
2063
2064 unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
2065
2066 /* Return number of datagrams sent if we sent any at all;
2067 * otherwise return the error.
2068 */
2069 if (i) {
2070 return i;
2071 }
2072 return ret;
2073}
2074#endif
2075
Peter Maydella94b4982013-02-08 04:35:04 +00002076/* If we don't have a system accept4() then just call accept.
2077 * The callsites to do_accept4() will ensure that they don't
2078 * pass a non-zero flags argument in this config.
2079 */
2080#ifndef CONFIG_ACCEPT4
2081static inline int accept4(int sockfd, struct sockaddr *addr,
2082 socklen_t *addrlen, int flags)
2083{
2084 assert(flags == 0);
2085 return accept(sockfd, addr, addrlen);
2086}
2087#endif
2088
2089/* do_accept4() Must return target values and target errnos. */
2090static abi_long do_accept4(int fd, abi_ulong target_addr,
2091 abi_ulong target_addrlen_addr, int flags)
pbrook1be9e1d2006-11-19 15:26:04 +00002092{
bellard2f619692007-11-16 10:46:05 +00002093 socklen_t addrlen;
2094 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002095 abi_long ret;
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002096 int host_flags;
2097
2098 host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
pbrook1be9e1d2006-11-19 15:26:04 +00002099
Peter Maydella94b4982013-02-08 04:35:04 +00002100 if (target_addr == 0) {
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002101 return get_errno(accept4(fd, NULL, NULL, host_flags));
Peter Maydella94b4982013-02-08 04:35:04 +00002102 }
Arnaud Patard917507b2009-06-19 10:44:45 +03002103
2104 /* linux returns EINVAL if addrlen pointer is invalid */
bellard2f619692007-11-16 10:46:05 +00002105 if (get_user_u32(addrlen, target_addrlen_addr))
Arnaud Patard917507b2009-06-19 10:44:45 +03002106 return -TARGET_EINVAL;
bellard2f619692007-11-16 10:46:05 +00002107
Blue Swirl38724252010-09-18 05:53:14 +00002108 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002109 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002110 }
aurel328f7aeaf2009-01-30 19:47:57 +00002111
Arnaud Patard917507b2009-06-19 10:44:45 +03002112 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2113 return -TARGET_EINVAL;
2114
bellard2f619692007-11-16 10:46:05 +00002115 addr = alloca(addrlen);
2116
Petar Jovanovicd25295d2014-03-31 17:41:23 +02002117 ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002118 if (!is_error(ret)) {
2119 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002120 if (put_user_u32(addrlen, target_addrlen_addr))
2121 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002122 }
2123 return ret;
2124}
2125
ths0da46a62007-10-20 20:23:07 +00002126/* do_getpeername() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002127static abi_long do_getpeername(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002128 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002129{
bellard2f619692007-11-16 10:46:05 +00002130 socklen_t addrlen;
2131 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002132 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002133
bellard2f619692007-11-16 10:46:05 +00002134 if (get_user_u32(addrlen, target_addrlen_addr))
2135 return -TARGET_EFAULT;
2136
Blue Swirl38724252010-09-18 05:53:14 +00002137 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002138 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002139 }
aurel328f7aeaf2009-01-30 19:47:57 +00002140
Arnaud Patard917507b2009-06-19 10:44:45 +03002141 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2142 return -TARGET_EFAULT;
2143
bellard2f619692007-11-16 10:46:05 +00002144 addr = alloca(addrlen);
2145
pbrook1be9e1d2006-11-19 15:26:04 +00002146 ret = get_errno(getpeername(fd, addr, &addrlen));
2147 if (!is_error(ret)) {
2148 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002149 if (put_user_u32(addrlen, target_addrlen_addr))
2150 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002151 }
2152 return ret;
2153}
2154
ths0da46a62007-10-20 20:23:07 +00002155/* do_getsockname() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002156static abi_long do_getsockname(int fd, abi_ulong target_addr,
bellard2f619692007-11-16 10:46:05 +00002157 abi_ulong target_addrlen_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002158{
bellard2f619692007-11-16 10:46:05 +00002159 socklen_t addrlen;
2160 void *addr;
blueswir1992f48a2007-10-14 16:27:31 +00002161 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002162
bellard2f619692007-11-16 10:46:05 +00002163 if (get_user_u32(addrlen, target_addrlen_addr))
2164 return -TARGET_EFAULT;
2165
Blue Swirl38724252010-09-18 05:53:14 +00002166 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002167 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002168 }
aurel328f7aeaf2009-01-30 19:47:57 +00002169
Arnaud Patard917507b2009-06-19 10:44:45 +03002170 if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
2171 return -TARGET_EFAULT;
2172
bellard2f619692007-11-16 10:46:05 +00002173 addr = alloca(addrlen);
2174
pbrook1be9e1d2006-11-19 15:26:04 +00002175 ret = get_errno(getsockname(fd, addr, &addrlen));
2176 if (!is_error(ret)) {
2177 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002178 if (put_user_u32(addrlen, target_addrlen_addr))
2179 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002180 }
2181 return ret;
2182}
2183
ths0da46a62007-10-20 20:23:07 +00002184/* do_socketpair() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002185static abi_long do_socketpair(int domain, int type, int protocol,
bellard2f619692007-11-16 10:46:05 +00002186 abi_ulong target_tab_addr)
pbrook1be9e1d2006-11-19 15:26:04 +00002187{
2188 int tab[2];
blueswir1992f48a2007-10-14 16:27:31 +00002189 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002190
Petar Jovanovicf651e6a2013-07-01 02:44:14 +02002191 target_to_host_sock_type(&type);
2192
pbrook1be9e1d2006-11-19 15:26:04 +00002193 ret = get_errno(socketpair(domain, type, protocol, tab));
2194 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00002195 if (put_user_s32(tab[0], target_tab_addr)
2196 || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
2197 ret = -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002198 }
2199 return ret;
2200}
2201
ths0da46a62007-10-20 20:23:07 +00002202/* do_sendto() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002203static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
2204 abi_ulong target_addr, socklen_t addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002205{
2206 void *addr;
2207 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002208 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002209
Blue Swirl38724252010-09-18 05:53:14 +00002210 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002211 return -TARGET_EINVAL;
Blue Swirl38724252010-09-18 05:53:14 +00002212 }
aurel328f7aeaf2009-01-30 19:47:57 +00002213
bellard579a97f2007-11-11 14:26:47 +00002214 host_msg = lock_user(VERIFY_READ, msg, len, 1);
2215 if (!host_msg)
2216 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002217 if (target_addr) {
2218 addr = alloca(addrlen);
Arnaud Patard917507b2009-06-19 10:44:45 +03002219 ret = target_to_host_sockaddr(addr, target_addr, addrlen);
2220 if (ret) {
2221 unlock_user(host_msg, msg, 0);
2222 return ret;
2223 }
pbrook1be9e1d2006-11-19 15:26:04 +00002224 ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
2225 } else {
2226 ret = get_errno(send(fd, host_msg, len, flags));
2227 }
2228 unlock_user(host_msg, msg, 0);
2229 return ret;
2230}
2231
ths0da46a62007-10-20 20:23:07 +00002232/* do_recvfrom() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002233static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
2234 abi_ulong target_addr,
2235 abi_ulong target_addrlen)
pbrook1be9e1d2006-11-19 15:26:04 +00002236{
2237 socklen_t addrlen;
2238 void *addr;
2239 void *host_msg;
blueswir1992f48a2007-10-14 16:27:31 +00002240 abi_long ret;
pbrook1be9e1d2006-11-19 15:26:04 +00002241
bellard579a97f2007-11-11 14:26:47 +00002242 host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
2243 if (!host_msg)
2244 return -TARGET_EFAULT;
pbrook1be9e1d2006-11-19 15:26:04 +00002245 if (target_addr) {
bellard2f619692007-11-16 10:46:05 +00002246 if (get_user_u32(addrlen, target_addrlen)) {
2247 ret = -TARGET_EFAULT;
2248 goto fail;
2249 }
Blue Swirl38724252010-09-18 05:53:14 +00002250 if ((int)addrlen < 0) {
aurel328f7aeaf2009-01-30 19:47:57 +00002251 ret = -TARGET_EINVAL;
2252 goto fail;
2253 }
pbrook1be9e1d2006-11-19 15:26:04 +00002254 addr = alloca(addrlen);
2255 ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
2256 } else {
2257 addr = NULL; /* To keep compiler quiet. */
Blue Swirl00aa0042011-07-23 20:04:29 +00002258 ret = get_errno(qemu_recv(fd, host_msg, len, flags));
pbrook1be9e1d2006-11-19 15:26:04 +00002259 }
2260 if (!is_error(ret)) {
2261 if (target_addr) {
2262 host_to_target_sockaddr(target_addr, addr, addrlen);
bellard2f619692007-11-16 10:46:05 +00002263 if (put_user_u32(addrlen, target_addrlen)) {
2264 ret = -TARGET_EFAULT;
2265 goto fail;
2266 }
pbrook1be9e1d2006-11-19 15:26:04 +00002267 }
2268 unlock_user(host_msg, msg, len);
2269 } else {
bellard2f619692007-11-16 10:46:05 +00002270fail:
pbrook1be9e1d2006-11-19 15:26:04 +00002271 unlock_user(host_msg, msg, 0);
2272 }
2273 return ret;
2274}
2275
j_mayer32407102007-09-26 23:01:49 +00002276#ifdef TARGET_NR_socketcall
ths0da46a62007-10-20 20:23:07 +00002277/* do_socketcall() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00002278static abi_long do_socketcall(int num, abi_ulong vptr)
bellard31e31b82003-02-18 22:55:36 +00002279{
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002280 static const unsigned ac[] = { /* number of arguments per call */
2281 [SOCKOP_socket] = 3, /* domain, type, protocol */
2282 [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
2283 [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
2284 [SOCKOP_listen] = 2, /* sockfd, backlog */
2285 [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
2286 [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
2287 [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
2288 [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
2289 [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
2290 [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
2291 [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
2292 [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2293 [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
2294 [SOCKOP_shutdown] = 2, /* sockfd, how */
2295 [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
2296 [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
2297 [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2298 [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
2299 };
2300 abi_long a[6]; /* max 6 args */
bellard31e31b82003-02-18 22:55:36 +00002301
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002302 /* first, collect the arguments in a[] according to ac[] */
2303 if (num >= 0 && num < ARRAY_SIZE(ac)) {
2304 unsigned i;
2305 assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
2306 for (i = 0; i < ac[num]; ++i) {
2307 if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
André Hentschelb9d36eb2014-01-06 20:18:52 +01002308 return -TARGET_EFAULT;
2309 }
André Hentschelb9d36eb2014-01-06 20:18:52 +01002310 }
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002311 }
bellard2f619692007-11-16 10:46:05 +00002312
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002313 /* now when we have the args, actually handle the call */
2314 switch (num) {
2315 case SOCKOP_socket: /* domain, type, protocol */
2316 return do_socket(a[0], a[1], a[2]);
2317 case SOCKOP_bind: /* sockfd, addr, addrlen */
2318 return do_bind(a[0], a[1], a[2]);
2319 case SOCKOP_connect: /* sockfd, addr, addrlen */
2320 return do_connect(a[0], a[1], a[2]);
2321 case SOCKOP_listen: /* sockfd, backlog */
2322 return get_errno(listen(a[0], a[1]));
2323 case SOCKOP_accept: /* sockfd, addr, addrlen */
2324 return do_accept4(a[0], a[1], a[2], 0);
2325 case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
2326 return do_accept4(a[0], a[1], a[2], a[3]);
2327 case SOCKOP_getsockname: /* sockfd, addr, addrlen */
2328 return do_getsockname(a[0], a[1], a[2]);
2329 case SOCKOP_getpeername: /* sockfd, addr, addrlen */
2330 return do_getpeername(a[0], a[1], a[2]);
2331 case SOCKOP_socketpair: /* domain, type, protocol, tab */
2332 return do_socketpair(a[0], a[1], a[2], a[3]);
2333 case SOCKOP_send: /* sockfd, msg, len, flags */
2334 return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
2335 case SOCKOP_recv: /* sockfd, msg, len, flags */
2336 return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
2337 case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
2338 return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
2339 case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
2340 return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
2341 case SOCKOP_shutdown: /* sockfd, how */
2342 return get_errno(shutdown(a[0], a[1]));
2343 case SOCKOP_sendmsg: /* sockfd, msg, flags */
2344 return do_sendrecvmsg(a[0], a[1], a[2], 1);
2345 case SOCKOP_recvmsg: /* sockfd, msg, flags */
2346 return do_sendrecvmsg(a[0], a[1], a[2], 0);
2347 case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
2348 return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
2349 case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
2350 return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
bellard31e31b82003-02-18 22:55:36 +00002351 default:
2352 gemu_log("Unsupported socketcall: %d\n", num);
Michael Tokarev62dc90c2014-01-17 14:23:51 +04002353 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00002354 }
bellard31e31b82003-02-18 22:55:36 +00002355}
j_mayer32407102007-09-26 23:01:49 +00002356#endif
bellard31e31b82003-02-18 22:55:36 +00002357
bellard8853f862004-02-22 14:57:26 +00002358#define N_SHM_REGIONS 32
2359
2360static struct shm_region {
bellard5a4a8982007-11-11 17:39:18 +00002361 abi_ulong start;
2362 abi_ulong size;
bellard8853f862004-02-22 14:57:26 +00002363} shm_regions[N_SHM_REGIONS];
2364
ths3eb6b042007-06-03 14:26:27 +00002365struct target_semid_ds
2366{
2367 struct target_ipc_perm sem_perm;
blueswir1992f48a2007-10-14 16:27:31 +00002368 abi_ulong sem_otime;
2369 abi_ulong __unused1;
2370 abi_ulong sem_ctime;
2371 abi_ulong __unused2;
2372 abi_ulong sem_nsems;
2373 abi_ulong __unused3;
2374 abi_ulong __unused4;
ths3eb6b042007-06-03 14:26:27 +00002375};
2376
bellard579a97f2007-11-11 14:26:47 +00002377static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
2378 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002379{
2380 struct target_ipc_perm *target_ip;
2381 struct target_semid_ds *target_sd;
2382
bellard579a97f2007-11-11 14:26:47 +00002383 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2384 return -TARGET_EFAULT;
Michael S. Tsirkine8bbe362009-09-30 18:56:44 +00002385 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002386 host_ip->__key = tswap32(target_ip->__key);
2387 host_ip->uid = tswap32(target_ip->uid);
2388 host_ip->gid = tswap32(target_ip->gid);
2389 host_ip->cuid = tswap32(target_ip->cuid);
2390 host_ip->cgid = tswap32(target_ip->cgid);
2391#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2392 host_ip->mode = tswap32(target_ip->mode);
2393#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002394 host_ip->mode = tswap16(target_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002395#endif
2396#if defined(TARGET_PPC)
2397 host_ip->__seq = tswap32(target_ip->__seq);
2398#else
2399 host_ip->__seq = tswap16(target_ip->__seq);
2400#endif
ths3eb6b042007-06-03 14:26:27 +00002401 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002402 return 0;
ths3eb6b042007-06-03 14:26:27 +00002403}
2404
bellard579a97f2007-11-11 14:26:47 +00002405static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
2406 struct ipc_perm *host_ip)
ths3eb6b042007-06-03 14:26:27 +00002407{
2408 struct target_ipc_perm *target_ip;
2409 struct target_semid_ds *target_sd;
2410
bellard579a97f2007-11-11 14:26:47 +00002411 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2412 return -TARGET_EFAULT;
ths3eb6b042007-06-03 14:26:27 +00002413 target_ip = &(target_sd->sem_perm);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002414 target_ip->__key = tswap32(host_ip->__key);
2415 target_ip->uid = tswap32(host_ip->uid);
2416 target_ip->gid = tswap32(host_ip->gid);
2417 target_ip->cuid = tswap32(host_ip->cuid);
2418 target_ip->cgid = tswap32(host_ip->cgid);
2419#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
2420 target_ip->mode = tswap32(host_ip->mode);
2421#else
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002422 target_ip->mode = tswap16(host_ip->mode);
Petar Jovanovic55a2b162013-10-30 14:46:31 +01002423#endif
2424#if defined(TARGET_PPC)
2425 target_ip->__seq = tswap32(host_ip->__seq);
2426#else
2427 target_ip->__seq = tswap16(host_ip->__seq);
2428#endif
ths3eb6b042007-06-03 14:26:27 +00002429 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002430 return 0;
ths3eb6b042007-06-03 14:26:27 +00002431}
2432
bellard579a97f2007-11-11 14:26:47 +00002433static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
2434 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002435{
2436 struct target_semid_ds *target_sd;
2437
bellard579a97f2007-11-11 14:26:47 +00002438 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2439 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002440 if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
2441 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002442 host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
2443 host_sd->sem_otime = tswapal(target_sd->sem_otime);
2444 host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002445 unlock_user_struct(target_sd, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002446 return 0;
ths3eb6b042007-06-03 14:26:27 +00002447}
2448
bellard579a97f2007-11-11 14:26:47 +00002449static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
2450 struct semid_ds *host_sd)
ths3eb6b042007-06-03 14:26:27 +00002451{
2452 struct target_semid_ds *target_sd;
2453
bellard579a97f2007-11-11 14:26:47 +00002454 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2455 return -TARGET_EFAULT;
aurel32e5289082009-04-18 16:16:12 +00002456 if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
Dong Xu Wang3a931132011-11-29 16:52:38 +08002457 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002458 target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
2459 target_sd->sem_otime = tswapal(host_sd->sem_otime);
2460 target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
ths3eb6b042007-06-03 14:26:27 +00002461 unlock_user_struct(target_sd, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002462 return 0;
ths3eb6b042007-06-03 14:26:27 +00002463}
2464
aurel32e5289082009-04-18 16:16:12 +00002465struct target_seminfo {
2466 int semmap;
2467 int semmni;
2468 int semmns;
2469 int semmnu;
2470 int semmsl;
2471 int semopm;
2472 int semume;
2473 int semusz;
2474 int semvmx;
2475 int semaem;
2476};
2477
2478static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
2479 struct seminfo *host_seminfo)
2480{
2481 struct target_seminfo *target_seminfo;
2482 if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
2483 return -TARGET_EFAULT;
2484 __put_user(host_seminfo->semmap, &target_seminfo->semmap);
2485 __put_user(host_seminfo->semmni, &target_seminfo->semmni);
2486 __put_user(host_seminfo->semmns, &target_seminfo->semmns);
2487 __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
2488 __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
2489 __put_user(host_seminfo->semopm, &target_seminfo->semopm);
2490 __put_user(host_seminfo->semume, &target_seminfo->semume);
2491 __put_user(host_seminfo->semusz, &target_seminfo->semusz);
2492 __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
2493 __put_user(host_seminfo->semaem, &target_seminfo->semaem);
2494 unlock_user_struct(target_seminfo, target_addr, 1);
2495 return 0;
2496}
2497
thsfa294812007-02-02 22:05:00 +00002498union semun {
2499 int val;
ths3eb6b042007-06-03 14:26:27 +00002500 struct semid_ds *buf;
thsfa294812007-02-02 22:05:00 +00002501 unsigned short *array;
aurel32e5289082009-04-18 16:16:12 +00002502 struct seminfo *__buf;
thsfa294812007-02-02 22:05:00 +00002503};
2504
ths3eb6b042007-06-03 14:26:27 +00002505union target_semun {
2506 int val;
aurel32e5289082009-04-18 16:16:12 +00002507 abi_ulong buf;
2508 abi_ulong array;
2509 abi_ulong __buf;
ths3eb6b042007-06-03 14:26:27 +00002510};
2511
aurel32e5289082009-04-18 16:16:12 +00002512static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
2513 abi_ulong target_addr)
ths3eb6b042007-06-03 14:26:27 +00002514{
aurel32e5289082009-04-18 16:16:12 +00002515 int nsems;
2516 unsigned short *array;
2517 union semun semun;
2518 struct semid_ds semid_ds;
2519 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002520
aurel32e5289082009-04-18 16:16:12 +00002521 semun.buf = &semid_ds;
2522
2523 ret = semctl(semid, 0, IPC_STAT, semun);
2524 if (ret == -1)
2525 return get_errno(ret);
2526
2527 nsems = semid_ds.sem_nsems;
2528
2529 *host_array = malloc(nsems*sizeof(unsigned short));
Peter Maydell69d4c702014-02-17 18:55:34 +00002530 if (!*host_array) {
2531 return -TARGET_ENOMEM;
2532 }
aurel32e5289082009-04-18 16:16:12 +00002533 array = lock_user(VERIFY_READ, target_addr,
2534 nsems*sizeof(unsigned short), 1);
Peter Maydell69d4c702014-02-17 18:55:34 +00002535 if (!array) {
2536 free(*host_array);
aurel32e5289082009-04-18 16:16:12 +00002537 return -TARGET_EFAULT;
Peter Maydell69d4c702014-02-17 18:55:34 +00002538 }
aurel32e5289082009-04-18 16:16:12 +00002539
2540 for(i=0; i<nsems; i++) {
2541 __get_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002542 }
aurel32e5289082009-04-18 16:16:12 +00002543 unlock_user(array, target_addr, 0);
2544
bellard579a97f2007-11-11 14:26:47 +00002545 return 0;
ths3eb6b042007-06-03 14:26:27 +00002546}
2547
aurel32e5289082009-04-18 16:16:12 +00002548static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
2549 unsigned short **host_array)
ths3eb6b042007-06-03 14:26:27 +00002550{
aurel32e5289082009-04-18 16:16:12 +00002551 int nsems;
2552 unsigned short *array;
2553 union semun semun;
2554 struct semid_ds semid_ds;
2555 int i, ret;
ths3eb6b042007-06-03 14:26:27 +00002556
aurel32e5289082009-04-18 16:16:12 +00002557 semun.buf = &semid_ds;
2558
2559 ret = semctl(semid, 0, IPC_STAT, semun);
2560 if (ret == -1)
2561 return get_errno(ret);
2562
2563 nsems = semid_ds.sem_nsems;
2564
2565 array = lock_user(VERIFY_WRITE, target_addr,
2566 nsems*sizeof(unsigned short), 0);
2567 if (!array)
2568 return -TARGET_EFAULT;
2569
2570 for(i=0; i<nsems; i++) {
2571 __put_user((*host_array)[i], &array[i]);
ths3eb6b042007-06-03 14:26:27 +00002572 }
aurel32e5289082009-04-18 16:16:12 +00002573 free(*host_array);
2574 unlock_user(array, target_addr, 1);
2575
bellard579a97f2007-11-11 14:26:47 +00002576 return 0;
ths3eb6b042007-06-03 14:26:27 +00002577}
2578
aurel32e5289082009-04-18 16:16:12 +00002579static inline abi_long do_semctl(int semid, int semnum, int cmd,
2580 union target_semun target_su)
ths3eb6b042007-06-03 14:26:27 +00002581{
2582 union semun arg;
2583 struct semid_ds dsarg;
vibi sreenivasan7b8118e2009-06-19 13:34:39 +05302584 unsigned short *array = NULL;
aurel32e5289082009-04-18 16:16:12 +00002585 struct seminfo seminfo;
2586 abi_long ret = -TARGET_EINVAL;
2587 abi_long err;
2588 cmd &= 0xff;
ths3eb6b042007-06-03 14:26:27 +00002589
2590 switch( cmd ) {
2591 case GETVAL:
ths3eb6b042007-06-03 14:26:27 +00002592 case SETVAL:
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002593 arg.val = tswap32(target_su.val);
aurel32e5289082009-04-18 16:16:12 +00002594 ret = get_errno(semctl(semid, semnum, cmd, arg));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002595 target_su.val = tswap32(arg.val);
ths3eb6b042007-06-03 14:26:27 +00002596 break;
2597 case GETALL:
ths3eb6b042007-06-03 14:26:27 +00002598 case SETALL:
aurel32e5289082009-04-18 16:16:12 +00002599 err = target_to_host_semarray(semid, &array, target_su.array);
2600 if (err)
2601 return err;
2602 arg.array = array;
2603 ret = get_errno(semctl(semid, semnum, cmd, arg));
2604 err = host_to_target_semarray(semid, target_su.array, &array);
2605 if (err)
2606 return err;
ths3eb6b042007-06-03 14:26:27 +00002607 break;
2608 case IPC_STAT:
ths3eb6b042007-06-03 14:26:27 +00002609 case IPC_SET:
aurel32e5289082009-04-18 16:16:12 +00002610 case SEM_STAT:
2611 err = target_to_host_semid_ds(&dsarg, target_su.buf);
2612 if (err)
2613 return err;
2614 arg.buf = &dsarg;
2615 ret = get_errno(semctl(semid, semnum, cmd, arg));
2616 err = host_to_target_semid_ds(target_su.buf, &dsarg);
2617 if (err)
2618 return err;
ths3eb6b042007-06-03 14:26:27 +00002619 break;
aurel32e5289082009-04-18 16:16:12 +00002620 case IPC_INFO:
2621 case SEM_INFO:
2622 arg.__buf = &seminfo;
2623 ret = get_errno(semctl(semid, semnum, cmd, arg));
2624 err = host_to_target_seminfo(target_su.__buf, &seminfo);
2625 if (err)
2626 return err;
2627 break;
2628 case IPC_RMID:
2629 case GETPID:
2630 case GETNCNT:
2631 case GETZCNT:
2632 ret = get_errno(semctl(semid, semnum, cmd, NULL));
2633 break;
ths3eb6b042007-06-03 14:26:27 +00002634 }
2635
2636 return ret;
2637}
2638
aurel32e5289082009-04-18 16:16:12 +00002639struct target_sembuf {
2640 unsigned short sem_num;
2641 short sem_op;
2642 short sem_flg;
2643};
2644
2645static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
2646 abi_ulong target_addr,
2647 unsigned nsops)
2648{
2649 struct target_sembuf *target_sembuf;
2650 int i;
2651
2652 target_sembuf = lock_user(VERIFY_READ, target_addr,
2653 nsops*sizeof(struct target_sembuf), 1);
2654 if (!target_sembuf)
2655 return -TARGET_EFAULT;
2656
2657 for(i=0; i<nsops; i++) {
2658 __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
2659 __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
2660 __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
2661 }
2662
2663 unlock_user(target_sembuf, target_addr, 0);
2664
2665 return 0;
2666}
2667
2668static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
2669{
2670 struct sembuf sops[nsops];
2671
2672 if (target_to_host_sembuf(sops, ptr, nsops))
2673 return -TARGET_EFAULT;
2674
Petar Jovanovicc7128c92013-03-21 07:57:36 +00002675 return get_errno(semop(semid, sops, nsops));
aurel32e5289082009-04-18 16:16:12 +00002676}
2677
ths1bc012f2007-06-03 14:27:49 +00002678struct target_msqid_ds
2679{
aurel321c54ff92008-10-13 21:08:44 +00002680 struct target_ipc_perm msg_perm;
2681 abi_ulong msg_stime;
2682#if TARGET_ABI_BITS == 32
2683 abi_ulong __unused1;
2684#endif
2685 abi_ulong msg_rtime;
2686#if TARGET_ABI_BITS == 32
2687 abi_ulong __unused2;
2688#endif
2689 abi_ulong msg_ctime;
2690#if TARGET_ABI_BITS == 32
2691 abi_ulong __unused3;
2692#endif
2693 abi_ulong __msg_cbytes;
2694 abi_ulong msg_qnum;
2695 abi_ulong msg_qbytes;
2696 abi_ulong msg_lspid;
2697 abi_ulong msg_lrpid;
2698 abi_ulong __unused4;
2699 abi_ulong __unused5;
ths1bc012f2007-06-03 14:27:49 +00002700};
2701
bellard579a97f2007-11-11 14:26:47 +00002702static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
2703 abi_ulong target_addr)
ths1bc012f2007-06-03 14:27:49 +00002704{
2705 struct target_msqid_ds *target_md;
2706
bellard579a97f2007-11-11 14:26:47 +00002707 if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
2708 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002709 if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
2710 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002711 host_md->msg_stime = tswapal(target_md->msg_stime);
2712 host_md->msg_rtime = tswapal(target_md->msg_rtime);
2713 host_md->msg_ctime = tswapal(target_md->msg_ctime);
2714 host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
2715 host_md->msg_qnum = tswapal(target_md->msg_qnum);
2716 host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
2717 host_md->msg_lspid = tswapal(target_md->msg_lspid);
2718 host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002719 unlock_user_struct(target_md, target_addr, 0);
bellard579a97f2007-11-11 14:26:47 +00002720 return 0;
ths1bc012f2007-06-03 14:27:49 +00002721}
2722
bellard579a97f2007-11-11 14:26:47 +00002723static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
2724 struct msqid_ds *host_md)
ths1bc012f2007-06-03 14:27:49 +00002725{
2726 struct target_msqid_ds *target_md;
2727
bellard579a97f2007-11-11 14:26:47 +00002728 if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
2729 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002730 if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
2731 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002732 target_md->msg_stime = tswapal(host_md->msg_stime);
2733 target_md->msg_rtime = tswapal(host_md->msg_rtime);
2734 target_md->msg_ctime = tswapal(host_md->msg_ctime);
2735 target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
2736 target_md->msg_qnum = tswapal(host_md->msg_qnum);
2737 target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
2738 target_md->msg_lspid = tswapal(host_md->msg_lspid);
2739 target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
ths1bc012f2007-06-03 14:27:49 +00002740 unlock_user_struct(target_md, target_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00002741 return 0;
ths1bc012f2007-06-03 14:27:49 +00002742}
2743
aurel321c54ff92008-10-13 21:08:44 +00002744struct target_msginfo {
2745 int msgpool;
2746 int msgmap;
2747 int msgmax;
2748 int msgmnb;
2749 int msgmni;
2750 int msgssz;
2751 int msgtql;
2752 unsigned short int msgseg;
2753};
2754
2755static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
2756 struct msginfo *host_msginfo)
2757{
2758 struct target_msginfo *target_msginfo;
2759 if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
2760 return -TARGET_EFAULT;
2761 __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
2762 __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
2763 __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
2764 __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
2765 __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
2766 __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
2767 __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
2768 __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
2769 unlock_user_struct(target_msginfo, target_addr, 1);
aurel3200b229a2008-10-24 13:12:52 +00002770 return 0;
aurel321c54ff92008-10-13 21:08:44 +00002771}
2772
2773static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
ths1bc012f2007-06-03 14:27:49 +00002774{
2775 struct msqid_ds dsarg;
aurel321c54ff92008-10-13 21:08:44 +00002776 struct msginfo msginfo;
2777 abi_long ret = -TARGET_EINVAL;
2778
2779 cmd &= 0xff;
2780
2781 switch (cmd) {
ths1bc012f2007-06-03 14:27:49 +00002782 case IPC_STAT:
2783 case IPC_SET:
aurel321c54ff92008-10-13 21:08:44 +00002784 case MSG_STAT:
2785 if (target_to_host_msqid_ds(&dsarg,ptr))
2786 return -TARGET_EFAULT;
2787 ret = get_errno(msgctl(msgid, cmd, &dsarg));
2788 if (host_to_target_msqid_ds(ptr,&dsarg))
2789 return -TARGET_EFAULT;
2790 break;
2791 case IPC_RMID:
2792 ret = get_errno(msgctl(msgid, cmd, NULL));
2793 break;
2794 case IPC_INFO:
2795 case MSG_INFO:
2796 ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
2797 if (host_to_target_msginfo(ptr, &msginfo))
2798 return -TARGET_EFAULT;
2799 break;
ths1bc012f2007-06-03 14:27:49 +00002800 }
aurel321c54ff92008-10-13 21:08:44 +00002801
ths1bc012f2007-06-03 14:27:49 +00002802 return ret;
2803}
2804
2805struct target_msgbuf {
aurel321c54ff92008-10-13 21:08:44 +00002806 abi_long mtype;
2807 char mtext[1];
ths1bc012f2007-06-03 14:27:49 +00002808};
2809
blueswir1992f48a2007-10-14 16:27:31 +00002810static inline abi_long do_msgsnd(int msqid, abi_long msgp,
2811 unsigned int msgsz, int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002812{
2813 struct target_msgbuf *target_mb;
2814 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002815 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002816
bellard579a97f2007-11-11 14:26:47 +00002817 if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
2818 return -TARGET_EFAULT;
ths1bc012f2007-06-03 14:27:49 +00002819 host_mb = malloc(msgsz+sizeof(long));
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002820 host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
aurel321c54ff92008-10-13 21:08:44 +00002821 memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ths1bc012f2007-06-03 14:27:49 +00002822 ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
2823 free(host_mb);
2824 unlock_user_struct(target_mb, msgp, 0);
2825
2826 return ret;
2827}
2828
blueswir1992f48a2007-10-14 16:27:31 +00002829static inline abi_long do_msgrcv(int msqid, abi_long msgp,
aurel321c54ff92008-10-13 21:08:44 +00002830 unsigned int msgsz, abi_long msgtyp,
blueswir1992f48a2007-10-14 16:27:31 +00002831 int msgflg)
ths1bc012f2007-06-03 14:27:49 +00002832{
2833 struct target_msgbuf *target_mb;
bellard579a97f2007-11-11 14:26:47 +00002834 char *target_mtext;
ths1bc012f2007-06-03 14:27:49 +00002835 struct msgbuf *host_mb;
blueswir1992f48a2007-10-14 16:27:31 +00002836 abi_long ret = 0;
ths1bc012f2007-06-03 14:27:49 +00002837
bellard579a97f2007-11-11 14:26:47 +00002838 if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
2839 return -TARGET_EFAULT;
aurel321c54ff92008-10-13 21:08:44 +00002840
Jim Meyering0d07fe42012-08-22 13:55:53 +02002841 host_mb = g_malloc(msgsz+sizeof(long));
Laurent Vivier79dd77d2012-12-20 11:00:11 +00002842 ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
aurel321c54ff92008-10-13 21:08:44 +00002843
bellard579a97f2007-11-11 14:26:47 +00002844 if (ret > 0) {
2845 abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
2846 target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
2847 if (!target_mtext) {
2848 ret = -TARGET_EFAULT;
2849 goto end;
2850 }
aurel321c54ff92008-10-13 21:08:44 +00002851 memcpy(target_mb->mtext, host_mb->mtext, ret);
bellard579a97f2007-11-11 14:26:47 +00002852 unlock_user(target_mtext, target_mtext_addr, ret);
2853 }
aurel321c54ff92008-10-13 21:08:44 +00002854
Matthias Brauncbb21ee2011-08-12 19:57:41 +02002855 target_mb->mtype = tswapal(host_mb->mtype);
ths1bc012f2007-06-03 14:27:49 +00002856
bellard579a97f2007-11-11 14:26:47 +00002857end:
2858 if (target_mb)
2859 unlock_user_struct(target_mb, msgp, 1);
Jim Meyering0d07fe42012-08-22 13:55:53 +02002860 g_free(host_mb);
ths1bc012f2007-06-03 14:27:49 +00002861 return ret;
2862}
2863
Riku Voipio88a8c982009-04-03 10:42:00 +03002864static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
2865 abi_ulong target_addr)
2866{
2867 struct target_shmid_ds *target_sd;
2868
2869 if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
2870 return -TARGET_EFAULT;
2871 if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
2872 return -TARGET_EFAULT;
2873 __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2874 __get_user(host_sd->shm_atime, &target_sd->shm_atime);
2875 __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2876 __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2877 __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2878 __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2879 __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2880 unlock_user_struct(target_sd, target_addr, 0);
2881 return 0;
2882}
2883
2884static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
2885 struct shmid_ds *host_sd)
2886{
2887 struct target_shmid_ds *target_sd;
2888
2889 if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
2890 return -TARGET_EFAULT;
2891 if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
2892 return -TARGET_EFAULT;
2893 __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
2894 __put_user(host_sd->shm_atime, &target_sd->shm_atime);
2895 __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
2896 __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
2897 __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
2898 __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
2899 __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
2900 unlock_user_struct(target_sd, target_addr, 1);
2901 return 0;
2902}
2903
2904struct target_shminfo {
2905 abi_ulong shmmax;
2906 abi_ulong shmmin;
2907 abi_ulong shmmni;
2908 abi_ulong shmseg;
2909 abi_ulong shmall;
2910};
2911
2912static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
2913 struct shminfo *host_shminfo)
2914{
2915 struct target_shminfo *target_shminfo;
2916 if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
2917 return -TARGET_EFAULT;
2918 __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
2919 __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
2920 __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
2921 __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
2922 __put_user(host_shminfo->shmall, &target_shminfo->shmall);
2923 unlock_user_struct(target_shminfo, target_addr, 1);
2924 return 0;
2925}
2926
2927struct target_shm_info {
2928 int used_ids;
2929 abi_ulong shm_tot;
2930 abi_ulong shm_rss;
2931 abi_ulong shm_swp;
2932 abi_ulong swap_attempts;
2933 abi_ulong swap_successes;
2934};
2935
2936static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
2937 struct shm_info *host_shm_info)
2938{
2939 struct target_shm_info *target_shm_info;
2940 if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
2941 return -TARGET_EFAULT;
2942 __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
2943 __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
2944 __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
2945 __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
2946 __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
2947 __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
2948 unlock_user_struct(target_shm_info, target_addr, 1);
2949 return 0;
2950}
2951
2952static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
2953{
2954 struct shmid_ds dsarg;
2955 struct shminfo shminfo;
2956 struct shm_info shm_info;
2957 abi_long ret = -TARGET_EINVAL;
2958
2959 cmd &= 0xff;
2960
2961 switch(cmd) {
2962 case IPC_STAT:
2963 case IPC_SET:
2964 case SHM_STAT:
2965 if (target_to_host_shmid_ds(&dsarg, buf))
2966 return -TARGET_EFAULT;
2967 ret = get_errno(shmctl(shmid, cmd, &dsarg));
2968 if (host_to_target_shmid_ds(buf, &dsarg))
2969 return -TARGET_EFAULT;
2970 break;
2971 case IPC_INFO:
2972 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
2973 if (host_to_target_shminfo(buf, &shminfo))
2974 return -TARGET_EFAULT;
2975 break;
2976 case SHM_INFO:
2977 ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
2978 if (host_to_target_shm_info(buf, &shm_info))
2979 return -TARGET_EFAULT;
2980 break;
2981 case IPC_RMID:
2982 case SHM_LOCK:
2983 case SHM_UNLOCK:
2984 ret = get_errno(shmctl(shmid, cmd, NULL));
2985 break;
2986 }
2987
2988 return ret;
2989}
2990
2991static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
2992{
2993 abi_long raddr;
2994 void *host_raddr;
2995 struct shmid_ds shm_info;
2996 int i,ret;
2997
2998 /* find out the length of the shared memory segment */
2999 ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
3000 if (is_error(ret)) {
3001 /* can't get length, bail out */
3002 return ret;
3003 }
3004
3005 mmap_lock();
3006
3007 if (shmaddr)
3008 host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
3009 else {
3010 abi_ulong mmap_start;
3011
3012 mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
3013
3014 if (mmap_start == -1) {
3015 errno = ENOMEM;
3016 host_raddr = (void *)-1;
3017 } else
3018 host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
3019 }
3020
3021 if (host_raddr == (void *)-1) {
3022 mmap_unlock();
3023 return get_errno((long)host_raddr);
3024 }
3025 raddr=h2g((unsigned long)host_raddr);
3026
3027 page_set_flags(raddr, raddr + shm_info.shm_segsz,
3028 PAGE_VALID | PAGE_READ |
3029 ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
3030
3031 for (i = 0; i < N_SHM_REGIONS; i++) {
3032 if (shm_regions[i].start == 0) {
3033 shm_regions[i].start = raddr;
3034 shm_regions[i].size = shm_info.shm_segsz;
3035 break;
3036 }
3037 }
3038
3039 mmap_unlock();
3040 return raddr;
3041
3042}
3043
3044static inline abi_long do_shmdt(abi_ulong shmaddr)
3045{
3046 int i;
3047
3048 for (i = 0; i < N_SHM_REGIONS; ++i) {
3049 if (shm_regions[i].start == shmaddr) {
3050 shm_regions[i].start = 0;
takasi-y@ops.dti.ne.jpe00ac242010-04-11 02:09:57 +09003051 page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
Riku Voipio88a8c982009-04-03 10:42:00 +03003052 break;
3053 }
3054 }
3055
3056 return get_errno(shmdt(g2h(shmaddr)));
3057}
3058
aurel321c54ff92008-10-13 21:08:44 +00003059#ifdef TARGET_NR_ipc
pbrook53a59602006-03-25 19:31:22 +00003060/* ??? This only works with linear mappings. */
ths0da46a62007-10-20 20:23:07 +00003061/* do_ipc() must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003062static abi_long do_ipc(unsigned int call, int first,
3063 int second, int third,
3064 abi_long ptr, abi_long fifth)
bellard8853f862004-02-22 14:57:26 +00003065{
3066 int version;
blueswir1992f48a2007-10-14 16:27:31 +00003067 abi_long ret = 0;
bellard8853f862004-02-22 14:57:26 +00003068
3069 version = call >> 16;
3070 call &= 0xffff;
3071
3072 switch (call) {
thsfa294812007-02-02 22:05:00 +00003073 case IPCOP_semop:
aurel32e5289082009-04-18 16:16:12 +00003074 ret = do_semop(first, ptr, second);
thsfa294812007-02-02 22:05:00 +00003075 break;
3076
3077 case IPCOP_semget:
3078 ret = get_errno(semget(first, second, third));
3079 break;
3080
3081 case IPCOP_semctl:
aurel32e5289082009-04-18 16:16:12 +00003082 ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
thsfa294812007-02-02 22:05:00 +00003083 break;
thsd96372e2007-02-02 22:05:44 +00003084
aurel321c54ff92008-10-13 21:08:44 +00003085 case IPCOP_msgget:
3086 ret = get_errno(msgget(first, second));
3087 break;
thsd96372e2007-02-02 22:05:44 +00003088
aurel321c54ff92008-10-13 21:08:44 +00003089 case IPCOP_msgsnd:
3090 ret = do_msgsnd(first, ptr, second, third);
3091 break;
thsd96372e2007-02-02 22:05:44 +00003092
aurel321c54ff92008-10-13 21:08:44 +00003093 case IPCOP_msgctl:
3094 ret = do_msgctl(first, second, ptr);
3095 break;
thsd96372e2007-02-02 22:05:44 +00003096
aurel321c54ff92008-10-13 21:08:44 +00003097 case IPCOP_msgrcv:
3098 switch (version) {
3099 case 0:
3100 {
3101 struct target_ipc_kludge {
3102 abi_long msgp;
3103 abi_long msgtyp;
3104 } *tmp;
thsd96372e2007-02-02 22:05:44 +00003105
aurel321c54ff92008-10-13 21:08:44 +00003106 if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
3107 ret = -TARGET_EFAULT;
3108 break;
ths1bc012f2007-06-03 14:27:49 +00003109 }
aurel321c54ff92008-10-13 21:08:44 +00003110
Laurent Vivier79dd77d2012-12-20 11:00:11 +00003111 ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
aurel321c54ff92008-10-13 21:08:44 +00003112
3113 unlock_user_struct(tmp, ptr, 0);
3114 break;
3115 }
3116 default:
3117 ret = do_msgrcv(first, ptr, second, fifth, third);
3118 }
3119 break;
thsd96372e2007-02-02 22:05:44 +00003120
bellard8853f862004-02-22 14:57:26 +00003121 case IPCOP_shmat:
Riku Voipio88a8c982009-04-03 10:42:00 +03003122 switch (version) {
3123 default:
bellard5a4a8982007-11-11 17:39:18 +00003124 {
3125 abi_ulong raddr;
Riku Voipio88a8c982009-04-03 10:42:00 +03003126 raddr = do_shmat(first, ptr, second);
3127 if (is_error(raddr))
3128 return get_errno(raddr);
bellard2f619692007-11-16 10:46:05 +00003129 if (put_user_ual(raddr, third))
bellard5a4a8982007-11-11 17:39:18 +00003130 return -TARGET_EFAULT;
Riku Voipio88a8c982009-04-03 10:42:00 +03003131 break;
3132 }
3133 case 1:
3134 ret = -TARGET_EINVAL;
3135 break;
bellard5a4a8982007-11-11 17:39:18 +00003136 }
bellard8853f862004-02-22 14:57:26 +00003137 break;
3138 case IPCOP_shmdt:
Riku Voipio88a8c982009-04-03 10:42:00 +03003139 ret = do_shmdt(ptr);
bellard8853f862004-02-22 14:57:26 +00003140 break;
3141
3142 case IPCOP_shmget:
3143 /* IPC_* flag values are the same on all linux platforms */
3144 ret = get_errno(shmget(first, second, third));
3145 break;
3146
3147 /* IPC_* and SHM_* command values are the same on all linux platforms */
3148 case IPCOP_shmctl:
Petar Jovanovica2926782013-10-30 14:46:32 +01003149 ret = do_shmctl(first, second, ptr);
bellard8853f862004-02-22 14:57:26 +00003150 break;
3151 default:
j_mayer32407102007-09-26 23:01:49 +00003152 gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
ths0da46a62007-10-20 20:23:07 +00003153 ret = -TARGET_ENOSYS;
bellard8853f862004-02-22 14:57:26 +00003154 break;
3155 }
3156 return ret;
3157}
j_mayer32407102007-09-26 23:01:49 +00003158#endif
bellard8853f862004-02-22 14:57:26 +00003159
bellard31e31b82003-02-18 22:55:36 +00003160/* kernel structure types definitions */
bellard31e31b82003-02-18 22:55:36 +00003161
Blue Swirl001faf32009-05-13 17:53:17 +00003162#define STRUCT(name, ...) STRUCT_ ## name,
bellard31e31b82003-02-18 22:55:36 +00003163#define STRUCT_SPECIAL(name) STRUCT_ ## name,
3164enum {
3165#include "syscall_types.h"
3166};
3167#undef STRUCT
3168#undef STRUCT_SPECIAL
3169
Blue Swirl001faf32009-05-13 17:53:17 +00003170#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
bellard31e31b82003-02-18 22:55:36 +00003171#define STRUCT_SPECIAL(name)
3172#include "syscall_types.h"
3173#undef STRUCT
3174#undef STRUCT_SPECIAL
3175
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003176typedef struct IOCTLEntry IOCTLEntry;
3177
3178typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
3179 int fd, abi_long cmd, abi_long arg);
3180
3181struct IOCTLEntry {
bellard2ab83ea2003-06-15 19:56:46 +00003182 unsigned int target_cmd;
3183 unsigned int host_cmd;
bellard31e31b82003-02-18 22:55:36 +00003184 const char *name;
3185 int access;
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003186 do_ioctl_fn *do_ioctl;
bellard1a9353d2003-03-16 20:28:50 +00003187 const argtype arg_type[5];
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003188};
bellard31e31b82003-02-18 22:55:36 +00003189
3190#define IOC_R 0x0001
3191#define IOC_W 0x0002
3192#define IOC_RW (IOC_R | IOC_W)
3193
3194#define MAX_STRUCT_SIZE 4096
3195
Peter Maydelldace20d2011-01-10 13:11:24 +00003196#ifdef CONFIG_FIEMAP
Peter Maydell285da2b2011-01-06 15:04:18 +00003197/* So fiemap access checks don't overflow on 32 bit systems.
3198 * This is very slightly smaller than the limit imposed by
3199 * the underlying kernel.
3200 */
3201#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
3202 / sizeof(struct fiemap_extent))
3203
3204static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
3205 int fd, abi_long cmd, abi_long arg)
3206{
3207 /* The parameter for this ioctl is a struct fiemap followed
3208 * by an array of struct fiemap_extent whose size is set
3209 * in fiemap->fm_extent_count. The array is filled in by the
3210 * ioctl.
3211 */
3212 int target_size_in, target_size_out;
3213 struct fiemap *fm;
3214 const argtype *arg_type = ie->arg_type;
3215 const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
3216 void *argptr, *p;
3217 abi_long ret;
3218 int i, extent_size = thunk_type_size(extent_arg_type, 0);
3219 uint32_t outbufsz;
3220 int free_fm = 0;
3221
3222 assert(arg_type[0] == TYPE_PTR);
3223 assert(ie->access == IOC_RW);
3224 arg_type++;
3225 target_size_in = thunk_type_size(arg_type, 0);
3226 argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
3227 if (!argptr) {
3228 return -TARGET_EFAULT;
3229 }
3230 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3231 unlock_user(argptr, arg, 0);
3232 fm = (struct fiemap *)buf_temp;
3233 if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
3234 return -TARGET_EINVAL;
3235 }
3236
3237 outbufsz = sizeof (*fm) +
3238 (sizeof(struct fiemap_extent) * fm->fm_extent_count);
3239
3240 if (outbufsz > MAX_STRUCT_SIZE) {
3241 /* We can't fit all the extents into the fixed size buffer.
3242 * Allocate one that is large enough and use it instead.
3243 */
3244 fm = malloc(outbufsz);
3245 if (!fm) {
3246 return -TARGET_ENOMEM;
3247 }
3248 memcpy(fm, buf_temp, sizeof(struct fiemap));
3249 free_fm = 1;
3250 }
3251 ret = get_errno(ioctl(fd, ie->host_cmd, fm));
3252 if (!is_error(ret)) {
3253 target_size_out = target_size_in;
3254 /* An extent_count of 0 means we were only counting the extents
3255 * so there are no structs to copy
3256 */
3257 if (fm->fm_extent_count != 0) {
3258 target_size_out += fm->fm_mapped_extents * extent_size;
3259 }
3260 argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
3261 if (!argptr) {
3262 ret = -TARGET_EFAULT;
3263 } else {
3264 /* Convert the struct fiemap */
3265 thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
3266 if (fm->fm_extent_count != 0) {
3267 p = argptr + target_size_in;
3268 /* ...and then all the struct fiemap_extents */
3269 for (i = 0; i < fm->fm_mapped_extents; i++) {
3270 thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
3271 THUNK_TARGET);
3272 p += extent_size;
3273 }
3274 }
3275 unlock_user(argptr, arg, target_size_out);
3276 }
3277 }
3278 if (free_fm) {
3279 free(fm);
3280 }
3281 return ret;
3282}
Peter Maydelldace20d2011-01-10 13:11:24 +00003283#endif
Peter Maydell285da2b2011-01-06 15:04:18 +00003284
Laurent Vivier059c2f22011-03-30 00:12:12 +02003285static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
3286 int fd, abi_long cmd, abi_long arg)
3287{
3288 const argtype *arg_type = ie->arg_type;
3289 int target_size;
3290 void *argptr;
3291 int ret;
3292 struct ifconf *host_ifconf;
3293 uint32_t outbufsz;
3294 const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
3295 int target_ifreq_size;
3296 int nb_ifreq;
3297 int free_buf = 0;
3298 int i;
3299 int target_ifc_len;
3300 abi_long target_ifc_buf;
3301 int host_ifc_len;
3302 char *host_ifc_buf;
3303
3304 assert(arg_type[0] == TYPE_PTR);
3305 assert(ie->access == IOC_RW);
3306
3307 arg_type++;
3308 target_size = thunk_type_size(arg_type, 0);
3309
3310 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3311 if (!argptr)
3312 return -TARGET_EFAULT;
3313 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3314 unlock_user(argptr, arg, 0);
3315
3316 host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
3317 target_ifc_len = host_ifconf->ifc_len;
3318 target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
3319
3320 target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
3321 nb_ifreq = target_ifc_len / target_ifreq_size;
3322 host_ifc_len = nb_ifreq * sizeof(struct ifreq);
3323
3324 outbufsz = sizeof(*host_ifconf) + host_ifc_len;
3325 if (outbufsz > MAX_STRUCT_SIZE) {
3326 /* We can't fit all the extents into the fixed size buffer.
3327 * Allocate one that is large enough and use it instead.
3328 */
3329 host_ifconf = malloc(outbufsz);
3330 if (!host_ifconf) {
3331 return -TARGET_ENOMEM;
3332 }
3333 memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
3334 free_buf = 1;
3335 }
3336 host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
3337
3338 host_ifconf->ifc_len = host_ifc_len;
3339 host_ifconf->ifc_buf = host_ifc_buf;
3340
3341 ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
3342 if (!is_error(ret)) {
3343 /* convert host ifc_len to target ifc_len */
3344
3345 nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
3346 target_ifc_len = nb_ifreq * target_ifreq_size;
3347 host_ifconf->ifc_len = target_ifc_len;
3348
3349 /* restore target ifc_buf */
3350
3351 host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
3352
3353 /* copy struct ifconf to target user */
3354
3355 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3356 if (!argptr)
3357 return -TARGET_EFAULT;
3358 thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
3359 unlock_user(argptr, arg, target_size);
3360
3361 /* copy ifreq[] to target user */
3362
3363 argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
3364 for (i = 0; i < nb_ifreq ; i++) {
3365 thunk_convert(argptr + i * target_ifreq_size,
3366 host_ifc_buf + i * sizeof(struct ifreq),
3367 ifreq_arg_type, THUNK_TARGET);
3368 }
3369 unlock_user(argptr, target_ifc_buf, target_ifc_len);
3370 }
3371
3372 if (free_buf) {
3373 free(host_ifconf);
3374 }
3375
3376 return ret;
3377}
3378
Alexander Graf56e904e2012-01-31 18:42:06 +01003379static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
3380 abi_long cmd, abi_long arg)
3381{
3382 void *argptr;
3383 struct dm_ioctl *host_dm;
3384 abi_long guest_data;
3385 uint32_t guest_data_size;
3386 int target_size;
3387 const argtype *arg_type = ie->arg_type;
3388 abi_long ret;
3389 void *big_buf = NULL;
3390 char *host_data;
3391
3392 arg_type++;
3393 target_size = thunk_type_size(arg_type, 0);
3394 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3395 if (!argptr) {
3396 ret = -TARGET_EFAULT;
3397 goto out;
3398 }
3399 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3400 unlock_user(argptr, arg, 0);
3401
3402 /* buf_temp is too small, so fetch things into a bigger buffer */
3403 big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
3404 memcpy(big_buf, buf_temp, target_size);
3405 buf_temp = big_buf;
3406 host_dm = big_buf;
3407
3408 guest_data = arg + host_dm->data_start;
3409 if ((guest_data - arg) < 0) {
3410 ret = -EINVAL;
3411 goto out;
3412 }
3413 guest_data_size = host_dm->data_size - host_dm->data_start;
3414 host_data = (char*)host_dm + host_dm->data_start;
3415
3416 argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
3417 switch (ie->host_cmd) {
3418 case DM_REMOVE_ALL:
3419 case DM_LIST_DEVICES:
3420 case DM_DEV_CREATE:
3421 case DM_DEV_REMOVE:
3422 case DM_DEV_SUSPEND:
3423 case DM_DEV_STATUS:
3424 case DM_DEV_WAIT:
3425 case DM_TABLE_STATUS:
3426 case DM_TABLE_CLEAR:
3427 case DM_TABLE_DEPS:
3428 case DM_LIST_VERSIONS:
3429 /* no input data */
3430 break;
3431 case DM_DEV_RENAME:
3432 case DM_DEV_SET_GEOMETRY:
3433 /* data contains only strings */
3434 memcpy(host_data, argptr, guest_data_size);
3435 break;
3436 case DM_TARGET_MSG:
3437 memcpy(host_data, argptr, guest_data_size);
3438 *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
3439 break;
3440 case DM_TABLE_LOAD:
3441 {
3442 void *gspec = argptr;
3443 void *cur_data = host_data;
3444 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3445 int spec_size = thunk_type_size(arg_type, 0);
3446 int i;
3447
3448 for (i = 0; i < host_dm->target_count; i++) {
3449 struct dm_target_spec *spec = cur_data;
3450 uint32_t next;
3451 int slen;
3452
3453 thunk_convert(spec, gspec, arg_type, THUNK_HOST);
3454 slen = strlen((char*)gspec + spec_size) + 1;
3455 next = spec->next;
3456 spec->next = sizeof(*spec) + slen;
3457 strcpy((char*)&spec[1], gspec + spec_size);
3458 gspec += next;
3459 cur_data += spec->next;
3460 }
3461 break;
3462 }
3463 default:
3464 ret = -TARGET_EINVAL;
3465 goto out;
3466 }
3467 unlock_user(argptr, guest_data, 0);
3468
3469 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3470 if (!is_error(ret)) {
3471 guest_data = arg + host_dm->data_start;
3472 guest_data_size = host_dm->data_size - host_dm->data_start;
3473 argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
3474 switch (ie->host_cmd) {
3475 case DM_REMOVE_ALL:
3476 case DM_DEV_CREATE:
3477 case DM_DEV_REMOVE:
3478 case DM_DEV_RENAME:
3479 case DM_DEV_SUSPEND:
3480 case DM_DEV_STATUS:
3481 case DM_TABLE_LOAD:
3482 case DM_TABLE_CLEAR:
3483 case DM_TARGET_MSG:
3484 case DM_DEV_SET_GEOMETRY:
3485 /* no return data */
3486 break;
3487 case DM_LIST_DEVICES:
3488 {
3489 struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
3490 uint32_t remaining_data = guest_data_size;
3491 void *cur_data = argptr;
3492 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
3493 int nl_size = 12; /* can't use thunk_size due to alignment */
3494
3495 while (1) {
3496 uint32_t next = nl->next;
3497 if (next) {
3498 nl->next = nl_size + (strlen(nl->name) + 1);
3499 }
3500 if (remaining_data < nl->next) {
3501 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3502 break;
3503 }
3504 thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
3505 strcpy(cur_data + nl_size, nl->name);
3506 cur_data += nl->next;
3507 remaining_data -= nl->next;
3508 if (!next) {
3509 break;
3510 }
3511 nl = (void*)nl + next;
3512 }
3513 break;
3514 }
3515 case DM_DEV_WAIT:
3516 case DM_TABLE_STATUS:
3517 {
3518 struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
3519 void *cur_data = argptr;
3520 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
3521 int spec_size = thunk_type_size(arg_type, 0);
3522 int i;
3523
3524 for (i = 0; i < host_dm->target_count; i++) {
3525 uint32_t next = spec->next;
3526 int slen = strlen((char*)&spec[1]) + 1;
3527 spec->next = (cur_data - argptr) + spec_size + slen;
3528 if (guest_data_size < spec->next) {
3529 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3530 break;
3531 }
3532 thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
3533 strcpy(cur_data + spec_size, (char*)&spec[1]);
3534 cur_data = argptr + spec->next;
3535 spec = (void*)host_dm + host_dm->data_start + next;
3536 }
3537 break;
3538 }
3539 case DM_TABLE_DEPS:
3540 {
3541 void *hdata = (void*)host_dm + host_dm->data_start;
3542 int count = *(uint32_t*)hdata;
3543 uint64_t *hdev = hdata + 8;
3544 uint64_t *gdev = argptr + 8;
3545 int i;
3546
3547 *(uint32_t*)argptr = tswap32(count);
3548 for (i = 0; i < count; i++) {
3549 *gdev = tswap64(*hdev);
3550 gdev++;
3551 hdev++;
3552 }
3553 break;
3554 }
3555 case DM_LIST_VERSIONS:
3556 {
3557 struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
3558 uint32_t remaining_data = guest_data_size;
3559 void *cur_data = argptr;
3560 const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
3561 int vers_size = thunk_type_size(arg_type, 0);
3562
3563 while (1) {
3564 uint32_t next = vers->next;
3565 if (next) {
3566 vers->next = vers_size + (strlen(vers->name) + 1);
3567 }
3568 if (remaining_data < vers->next) {
3569 host_dm->flags |= DM_BUFFER_FULL_FLAG;
3570 break;
3571 }
3572 thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
3573 strcpy(cur_data + vers_size, vers->name);
3574 cur_data += vers->next;
3575 remaining_data -= vers->next;
3576 if (!next) {
3577 break;
3578 }
3579 vers = (void*)vers + next;
3580 }
3581 break;
3582 }
3583 default:
3584 ret = -TARGET_EINVAL;
3585 goto out;
3586 }
3587 unlock_user(argptr, guest_data, guest_data_size);
3588
3589 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3590 if (!argptr) {
3591 ret = -TARGET_EFAULT;
3592 goto out;
3593 }
3594 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3595 unlock_user(argptr, arg, target_size);
3596 }
3597out:
Stefan Weilad11ad72012-09-04 22:14:19 +02003598 g_free(big_buf);
Alexander Graf56e904e2012-01-31 18:42:06 +01003599 return ret;
3600}
3601
Laurent Vivier7ff7b662013-07-02 14:04:12 +01003602static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
3603 int fd, abi_long cmd, abi_long arg)
3604{
3605 const argtype *arg_type = ie->arg_type;
3606 const StructEntry *se;
3607 const argtype *field_types;
3608 const int *dst_offsets, *src_offsets;
3609 int target_size;
3610 void *argptr;
3611 abi_ulong *target_rt_dev_ptr;
3612 unsigned long *host_rt_dev_ptr;
3613 abi_long ret;
3614 int i;
3615
3616 assert(ie->access == IOC_W);
3617 assert(*arg_type == TYPE_PTR);
3618 arg_type++;
3619 assert(*arg_type == TYPE_STRUCT);
3620 target_size = thunk_type_size(arg_type, 0);
3621 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3622 if (!argptr) {
3623 return -TARGET_EFAULT;
3624 }
3625 arg_type++;
3626 assert(*arg_type == (int)STRUCT_rtentry);
3627 se = struct_entries + *arg_type++;
3628 assert(se->convert[0] == NULL);
3629 /* convert struct here to be able to catch rt_dev string */
3630 field_types = se->field_types;
3631 dst_offsets = se->field_offsets[THUNK_HOST];
3632 src_offsets = se->field_offsets[THUNK_TARGET];
3633 for (i = 0; i < se->nb_fields; i++) {
3634 if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
3635 assert(*field_types == TYPE_PTRVOID);
3636 target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
3637 host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
3638 if (*target_rt_dev_ptr != 0) {
3639 *host_rt_dev_ptr = (unsigned long)lock_user_string(
3640 tswapal(*target_rt_dev_ptr));
3641 if (!*host_rt_dev_ptr) {
3642 unlock_user(argptr, arg, 0);
3643 return -TARGET_EFAULT;
3644 }
3645 } else {
3646 *host_rt_dev_ptr = 0;
3647 }
3648 field_types++;
3649 continue;
3650 }
3651 field_types = thunk_convert(buf_temp + dst_offsets[i],
3652 argptr + src_offsets[i],
3653 field_types, THUNK_HOST);
3654 }
3655 unlock_user(argptr, arg, 0);
3656
3657 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3658 if (*host_rt_dev_ptr != 0) {
3659 unlock_user((void *)*host_rt_dev_ptr,
3660 *target_rt_dev_ptr, 0);
3661 }
3662 return ret;
3663}
3664
blueswir19f106a72008-10-05 10:52:52 +00003665static IOCTLEntry ioctl_entries[] = {
Blue Swirl001faf32009-05-13 17:53:17 +00003666#define IOCTL(cmd, access, ...) \
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003667 { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
3668#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
3669 { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
bellard31e31b82003-02-18 22:55:36 +00003670#include "ioctls.h"
3671 { 0, 0, },
3672};
3673
pbrook53a59602006-03-25 19:31:22 +00003674/* ??? Implement proper locking for ioctls. */
ths0da46a62007-10-20 20:23:07 +00003675/* do_ioctl() Must return target values and target errnos. */
blueswir1992f48a2007-10-14 16:27:31 +00003676static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
bellard31e31b82003-02-18 22:55:36 +00003677{
3678 const IOCTLEntry *ie;
3679 const argtype *arg_type;
blueswir1992f48a2007-10-14 16:27:31 +00003680 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00003681 uint8_t buf_temp[MAX_STRUCT_SIZE];
pbrook53a59602006-03-25 19:31:22 +00003682 int target_size;
3683 void *argptr;
bellard31e31b82003-02-18 22:55:36 +00003684
3685 ie = ioctl_entries;
3686 for(;;) {
3687 if (ie->target_cmd == 0) {
j_mayer32407102007-09-26 23:01:49 +00003688 gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
ths0da46a62007-10-20 20:23:07 +00003689 return -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003690 }
3691 if (ie->target_cmd == cmd)
3692 break;
3693 ie++;
3694 }
3695 arg_type = ie->arg_type;
bellard9de5e442003-03-23 16:49:39 +00003696#if defined(DEBUG)
j_mayer32407102007-09-26 23:01:49 +00003697 gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
bellard72f03902003-02-18 23:33:18 +00003698#endif
Peter Maydelld2ef05b2011-01-06 15:04:17 +00003699 if (ie->do_ioctl) {
3700 return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
3701 }
3702
bellard31e31b82003-02-18 22:55:36 +00003703 switch(arg_type[0]) {
3704 case TYPE_NULL:
3705 /* no argument */
3706 ret = get_errno(ioctl(fd, ie->host_cmd));
3707 break;
3708 case TYPE_PTRVOID:
3709 case TYPE_INT:
3710 /* int argment */
3711 ret = get_errno(ioctl(fd, ie->host_cmd, arg));
3712 break;
3713 case TYPE_PTR:
3714 arg_type++;
pbrook53a59602006-03-25 19:31:22 +00003715 target_size = thunk_type_size(arg_type, 0);
bellard31e31b82003-02-18 22:55:36 +00003716 switch(ie->access) {
3717 case IOC_R:
3718 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3719 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003720 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3721 if (!argptr)
3722 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003723 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3724 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003725 }
3726 break;
3727 case IOC_W:
bellard579a97f2007-11-11 14:26:47 +00003728 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3729 if (!argptr)
3730 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003731 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3732 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003733 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3734 break;
3735 default:
3736 case IOC_RW:
bellard579a97f2007-11-11 14:26:47 +00003737 argptr = lock_user(VERIFY_READ, arg, target_size, 1);
3738 if (!argptr)
3739 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003740 thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
3741 unlock_user(argptr, arg, 0);
bellard31e31b82003-02-18 22:55:36 +00003742 ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
3743 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00003744 argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
3745 if (!argptr)
3746 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003747 thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
3748 unlock_user(argptr, arg, target_size);
bellard31e31b82003-02-18 22:55:36 +00003749 }
3750 break;
3751 }
3752 break;
3753 default:
j_mayer32407102007-09-26 23:01:49 +00003754 gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
3755 (long)cmd, arg_type[0]);
ths0da46a62007-10-20 20:23:07 +00003756 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00003757 break;
3758 }
3759 return ret;
3760}
3761
blueswir1b39bc502008-10-05 10:51:10 +00003762static const bitmask_transtbl iflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003763 { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
3764 { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
3765 { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
3766 { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
3767 { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
3768 { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
3769 { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
3770 { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
3771 { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
3772 { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
3773 { TARGET_IXON, TARGET_IXON, IXON, IXON },
3774 { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
3775 { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
3776 { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
3777 { 0, 0, 0, 0 }
3778};
3779
blueswir1b39bc502008-10-05 10:51:10 +00003780static const bitmask_transtbl oflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003781 { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
3782 { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
3783 { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
3784 { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
3785 { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
3786 { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
3787 { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
3788 { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
3789 { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
3790 { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
3791 { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
3792 { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
3793 { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
3794 { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
3795 { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
3796 { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
3797 { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
3798 { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
3799 { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
3800 { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
3801 { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
3802 { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
3803 { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
3804 { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
3805 { 0, 0, 0, 0 }
3806};
3807
blueswir1b39bc502008-10-05 10:51:10 +00003808static const bitmask_transtbl cflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003809 { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
3810 { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
3811 { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
3812 { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
3813 { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
3814 { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
3815 { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
3816 { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
3817 { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
3818 { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
3819 { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
3820 { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
3821 { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
3822 { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
3823 { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
3824 { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
3825 { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
3826 { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
3827 { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
3828 { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
3829 { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
3830 { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
3831 { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
3832 { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
3833 { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
3834 { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
3835 { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
3836 { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
3837 { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
3838 { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
3839 { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
3840 { 0, 0, 0, 0 }
3841};
3842
blueswir1b39bc502008-10-05 10:51:10 +00003843static const bitmask_transtbl lflag_tbl[] = {
bellard31e31b82003-02-18 22:55:36 +00003844 { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
3845 { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
3846 { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
3847 { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
3848 { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
3849 { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
3850 { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
3851 { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
3852 { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
3853 { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
3854 { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
3855 { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
3856 { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
3857 { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
3858 { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
3859 { 0, 0, 0, 0 }
3860};
3861
3862static void target_to_host_termios (void *dst, const void *src)
3863{
3864 struct host_termios *host = dst;
3865 const struct target_termios *target = src;
ths3b46e622007-09-17 08:09:54 +00003866
ths5fafdf22007-09-16 21:08:06 +00003867 host->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003868 target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003869 host->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003870 target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003871 host->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003872 target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
ths5fafdf22007-09-16 21:08:06 +00003873 host->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003874 target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
3875 host->c_line = target->c_line;
ths3b46e622007-09-17 08:09:54 +00003876
Arnaud Patard44607122009-04-21 17:39:08 +03003877 memset(host->c_cc, 0, sizeof(host->c_cc));
ths5fafdf22007-09-16 21:08:06 +00003878 host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
3879 host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
ths3b46e622007-09-17 08:09:54 +00003880 host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
ths5fafdf22007-09-16 21:08:06 +00003881 host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
ths3b46e622007-09-17 08:09:54 +00003882 host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
ths5fafdf22007-09-16 21:08:06 +00003883 host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
ths3b46e622007-09-17 08:09:54 +00003884 host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
ths5fafdf22007-09-16 21:08:06 +00003885 host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
ths3b46e622007-09-17 08:09:54 +00003886 host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
ths5fafdf22007-09-16 21:08:06 +00003887 host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
3888 host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
ths3b46e622007-09-17 08:09:54 +00003889 host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
3890 host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
3891 host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
3892 host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
3893 host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
ths5fafdf22007-09-16 21:08:06 +00003894 host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
bellard31e31b82003-02-18 22:55:36 +00003895}
ths3b46e622007-09-17 08:09:54 +00003896
bellard31e31b82003-02-18 22:55:36 +00003897static void host_to_target_termios (void *dst, const void *src)
3898{
3899 struct target_termios *target = dst;
3900 const struct host_termios *host = src;
3901
ths5fafdf22007-09-16 21:08:06 +00003902 target->c_iflag =
bellard31e31b82003-02-18 22:55:36 +00003903 tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003904 target->c_oflag =
bellard31e31b82003-02-18 22:55:36 +00003905 tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003906 target->c_cflag =
bellard31e31b82003-02-18 22:55:36 +00003907 tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
ths5fafdf22007-09-16 21:08:06 +00003908 target->c_lflag =
bellard31e31b82003-02-18 22:55:36 +00003909 tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
3910 target->c_line = host->c_line;
ths3b46e622007-09-17 08:09:54 +00003911
Arnaud Patard44607122009-04-21 17:39:08 +03003912 memset(target->c_cc, 0, sizeof(target->c_cc));
bellard31e31b82003-02-18 22:55:36 +00003913 target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
3914 target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
3915 target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
3916 target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
3917 target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
3918 target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
3919 target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
3920 target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
3921 target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
3922 target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
3923 target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
3924 target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
3925 target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
3926 target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
3927 target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
3928 target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
3929 target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
3930}
3931
blueswir18e853dc2008-10-05 10:49:32 +00003932static const StructEntry struct_termios_def = {
bellard31e31b82003-02-18 22:55:36 +00003933 .convert = { host_to_target_termios, target_to_host_termios },
3934 .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
3935 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
3936};
3937
bellard5286db72003-06-05 00:57:30 +00003938static bitmask_transtbl mmap_flags_tbl[] = {
3939 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
3940 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
3941 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
3942 { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
3943 { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
3944 { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
3945 { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
3946 { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
3947 { 0, 0, 0, 0 }
3948};
3949
bellard2ab83ea2003-06-15 19:56:46 +00003950#if defined(TARGET_I386)
bellard6dbad632003-03-16 18:05:05 +00003951
3952/* NOTE: there is really one LDT for all the threads */
blueswir1b1d8e522008-10-26 13:43:07 +00003953static uint8_t *ldt_table;
bellard6dbad632003-03-16 18:05:05 +00003954
bellard03acab62007-11-11 14:57:14 +00003955static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00003956{
3957 int size;
pbrook53a59602006-03-25 19:31:22 +00003958 void *p;
bellard6dbad632003-03-16 18:05:05 +00003959
3960 if (!ldt_table)
3961 return 0;
3962 size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
3963 if (size > bytecount)
3964 size = bytecount;
bellard579a97f2007-11-11 14:26:47 +00003965 p = lock_user(VERIFY_WRITE, ptr, size, 0);
3966 if (!p)
bellard03acab62007-11-11 14:57:14 +00003967 return -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00003968 /* ??? Should this by byteswapped? */
pbrook53a59602006-03-25 19:31:22 +00003969 memcpy(p, ldt_table, size);
3970 unlock_user(p, ptr, size);
bellard6dbad632003-03-16 18:05:05 +00003971 return size;
3972}
3973
3974/* XXX: add locking support */
bellard03acab62007-11-11 14:57:14 +00003975static abi_long write_ldt(CPUX86State *env,
3976 abi_ulong ptr, unsigned long bytecount, int oldmode)
bellard6dbad632003-03-16 18:05:05 +00003977{
3978 struct target_modify_ldt_ldt_s ldt_info;
pbrook53a59602006-03-25 19:31:22 +00003979 struct target_modify_ldt_ldt_s *target_ldt_info;
bellard6dbad632003-03-16 18:05:05 +00003980 int seg_32bit, contents, read_exec_only, limit_in_pages;
bellard8d18e892007-11-14 15:18:40 +00003981 int seg_not_present, useable, lm;
bellard6dbad632003-03-16 18:05:05 +00003982 uint32_t *lp, entry_1, entry_2;
3983
3984 if (bytecount != sizeof(ldt_info))
bellard03acab62007-11-11 14:57:14 +00003985 return -TARGET_EINVAL;
bellard579a97f2007-11-11 14:26:47 +00003986 if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
bellard03acab62007-11-11 14:57:14 +00003987 return -TARGET_EFAULT;
pbrook53a59602006-03-25 19:31:22 +00003988 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02003989 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
pbrook53a59602006-03-25 19:31:22 +00003990 ldt_info.limit = tswap32(target_ldt_info->limit);
3991 ldt_info.flags = tswap32(target_ldt_info->flags);
3992 unlock_user_struct(target_ldt_info, ptr, 0);
ths3b46e622007-09-17 08:09:54 +00003993
bellard6dbad632003-03-16 18:05:05 +00003994 if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
bellard03acab62007-11-11 14:57:14 +00003995 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00003996 seg_32bit = ldt_info.flags & 1;
3997 contents = (ldt_info.flags >> 1) & 3;
3998 read_exec_only = (ldt_info.flags >> 3) & 1;
3999 limit_in_pages = (ldt_info.flags >> 4) & 1;
4000 seg_not_present = (ldt_info.flags >> 5) & 1;
4001 useable = (ldt_info.flags >> 6) & 1;
bellard8d18e892007-11-14 15:18:40 +00004002#ifdef TARGET_ABI32
4003 lm = 0;
4004#else
4005 lm = (ldt_info.flags >> 7) & 1;
4006#endif
bellard6dbad632003-03-16 18:05:05 +00004007 if (contents == 3) {
4008 if (oldmode)
bellard03acab62007-11-11 14:57:14 +00004009 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004010 if (seg_not_present == 0)
bellard03acab62007-11-11 14:57:14 +00004011 return -TARGET_EINVAL;
bellard6dbad632003-03-16 18:05:05 +00004012 }
4013 /* allocate the LDT */
4014 if (!ldt_table) {
balroge4415702008-11-10 02:55:33 +00004015 env->ldt.base = target_mmap(0,
4016 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
4017 PROT_READ|PROT_WRITE,
4018 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4019 if (env->ldt.base == -1)
bellard03acab62007-11-11 14:57:14 +00004020 return -TARGET_ENOMEM;
balroge4415702008-11-10 02:55:33 +00004021 memset(g2h(env->ldt.base), 0,
4022 TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
bellard6dbad632003-03-16 18:05:05 +00004023 env->ldt.limit = 0xffff;
balroge4415702008-11-10 02:55:33 +00004024 ldt_table = g2h(env->ldt.base);
bellard6dbad632003-03-16 18:05:05 +00004025 }
4026
4027 /* NOTE: same code as Linux kernel */
4028 /* Allow LDTs to be cleared by the user. */
4029 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4030 if (oldmode ||
4031 (contents == 0 &&
4032 read_exec_only == 1 &&
4033 seg_32bit == 0 &&
4034 limit_in_pages == 0 &&
4035 seg_not_present == 1 &&
4036 useable == 0 )) {
4037 entry_1 = 0;
4038 entry_2 = 0;
4039 goto install;
4040 }
4041 }
ths3b46e622007-09-17 08:09:54 +00004042
bellard6dbad632003-03-16 18:05:05 +00004043 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4044 (ldt_info.limit & 0x0ffff);
4045 entry_2 = (ldt_info.base_addr & 0xff000000) |
4046 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4047 (ldt_info.limit & 0xf0000) |
4048 ((read_exec_only ^ 1) << 9) |
4049 (contents << 10) |
4050 ((seg_not_present ^ 1) << 15) |
4051 (seg_32bit << 22) |
4052 (limit_in_pages << 23) |
bellard8d18e892007-11-14 15:18:40 +00004053 (lm << 21) |
bellard6dbad632003-03-16 18:05:05 +00004054 0x7000;
4055 if (!oldmode)
4056 entry_2 |= (useable << 20);
bellard14ae3ba2003-05-27 23:25:06 +00004057
bellard6dbad632003-03-16 18:05:05 +00004058 /* Install the new entry ... */
4059install:
4060 lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
4061 lp[0] = tswap32(entry_1);
4062 lp[1] = tswap32(entry_2);
4063 return 0;
4064}
4065
4066/* specific and weird i386 syscalls */
blueswir18fcd3692008-08-17 20:26:25 +00004067static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
4068 unsigned long bytecount)
bellard6dbad632003-03-16 18:05:05 +00004069{
bellard03acab62007-11-11 14:57:14 +00004070 abi_long ret;
ths3b46e622007-09-17 08:09:54 +00004071
bellard6dbad632003-03-16 18:05:05 +00004072 switch (func) {
4073 case 0:
4074 ret = read_ldt(ptr, bytecount);
4075 break;
4076 case 1:
4077 ret = write_ldt(env, ptr, bytecount, 1);
4078 break;
4079 case 0x11:
4080 ret = write_ldt(env, ptr, bytecount, 0);
4081 break;
bellard03acab62007-11-11 14:57:14 +00004082 default:
4083 ret = -TARGET_ENOSYS;
4084 break;
bellard6dbad632003-03-16 18:05:05 +00004085 }
4086 return ret;
4087}
bellard1b6b0292003-03-22 17:31:38 +00004088
blueswir14583f582008-08-24 10:35:55 +00004089#if defined(TARGET_I386) && defined(TARGET_ABI32)
Alexander Grafbc22eb42013-07-16 18:44:58 +01004090abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004091{
4092 uint64_t *gdt_table = g2h(env->gdt.base);
4093 struct target_modify_ldt_ldt_s ldt_info;
4094 struct target_modify_ldt_ldt_s *target_ldt_info;
4095 int seg_32bit, contents, read_exec_only, limit_in_pages;
4096 int seg_not_present, useable, lm;
4097 uint32_t *lp, entry_1, entry_2;
4098 int i;
4099
4100 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4101 if (!target_ldt_info)
4102 return -TARGET_EFAULT;
4103 ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004104 ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
bellard8d18e892007-11-14 15:18:40 +00004105 ldt_info.limit = tswap32(target_ldt_info->limit);
4106 ldt_info.flags = tswap32(target_ldt_info->flags);
4107 if (ldt_info.entry_number == -1) {
4108 for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
4109 if (gdt_table[i] == 0) {
4110 ldt_info.entry_number = i;
4111 target_ldt_info->entry_number = tswap32(i);
4112 break;
4113 }
4114 }
4115 }
4116 unlock_user_struct(target_ldt_info, ptr, 1);
4117
4118 if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
4119 ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
4120 return -TARGET_EINVAL;
4121 seg_32bit = ldt_info.flags & 1;
4122 contents = (ldt_info.flags >> 1) & 3;
4123 read_exec_only = (ldt_info.flags >> 3) & 1;
4124 limit_in_pages = (ldt_info.flags >> 4) & 1;
4125 seg_not_present = (ldt_info.flags >> 5) & 1;
4126 useable = (ldt_info.flags >> 6) & 1;
4127#ifdef TARGET_ABI32
4128 lm = 0;
4129#else
4130 lm = (ldt_info.flags >> 7) & 1;
4131#endif
4132
4133 if (contents == 3) {
4134 if (seg_not_present == 0)
4135 return -TARGET_EINVAL;
4136 }
4137
4138 /* NOTE: same code as Linux kernel */
4139 /* Allow LDTs to be cleared by the user. */
4140 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
4141 if ((contents == 0 &&
4142 read_exec_only == 1 &&
4143 seg_32bit == 0 &&
4144 limit_in_pages == 0 &&
4145 seg_not_present == 1 &&
4146 useable == 0 )) {
4147 entry_1 = 0;
4148 entry_2 = 0;
4149 goto install;
4150 }
4151 }
4152
4153 entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
4154 (ldt_info.limit & 0x0ffff);
4155 entry_2 = (ldt_info.base_addr & 0xff000000) |
4156 ((ldt_info.base_addr & 0x00ff0000) >> 16) |
4157 (ldt_info.limit & 0xf0000) |
4158 ((read_exec_only ^ 1) << 9) |
4159 (contents << 10) |
4160 ((seg_not_present ^ 1) << 15) |
4161 (seg_32bit << 22) |
4162 (limit_in_pages << 23) |
4163 (useable << 20) |
4164 (lm << 21) |
4165 0x7000;
4166
4167 /* Install the new entry ... */
4168install:
4169 lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
4170 lp[0] = tswap32(entry_1);
4171 lp[1] = tswap32(entry_2);
4172 return 0;
4173}
4174
blueswir18fcd3692008-08-17 20:26:25 +00004175static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
bellard8d18e892007-11-14 15:18:40 +00004176{
4177 struct target_modify_ldt_ldt_s *target_ldt_info;
4178 uint64_t *gdt_table = g2h(env->gdt.base);
4179 uint32_t base_addr, limit, flags;
4180 int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
4181 int seg_not_present, useable, lm;
4182 uint32_t *lp, entry_1, entry_2;
4183
4184 lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
4185 if (!target_ldt_info)
4186 return -TARGET_EFAULT;
4187 idx = tswap32(target_ldt_info->entry_number);
4188 if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
4189 idx > TARGET_GDT_ENTRY_TLS_MAX) {
4190 unlock_user_struct(target_ldt_info, ptr, 1);
4191 return -TARGET_EINVAL;
4192 }
4193 lp = (uint32_t *)(gdt_table + idx);
4194 entry_1 = tswap32(lp[0]);
4195 entry_2 = tswap32(lp[1]);
4196
4197 read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
4198 contents = (entry_2 >> 10) & 3;
4199 seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
4200 seg_32bit = (entry_2 >> 22) & 1;
4201 limit_in_pages = (entry_2 >> 23) & 1;
4202 useable = (entry_2 >> 20) & 1;
4203#ifdef TARGET_ABI32
4204 lm = 0;
4205#else
4206 lm = (entry_2 >> 21) & 1;
4207#endif
4208 flags = (seg_32bit << 0) | (contents << 1) |
4209 (read_exec_only << 3) | (limit_in_pages << 4) |
4210 (seg_not_present << 5) | (useable << 6) | (lm << 7);
4211 limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
4212 base_addr = (entry_1 >> 16) |
4213 (entry_2 & 0xff000000) |
4214 ((entry_2 & 0xff) << 16);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004215 target_ldt_info->base_addr = tswapal(base_addr);
bellard8d18e892007-11-14 15:18:40 +00004216 target_ldt_info->limit = tswap32(limit);
4217 target_ldt_info->flags = tswap32(flags);
4218 unlock_user_struct(target_ldt_info, ptr, 1);
4219 return 0;
4220}
blueswir14583f582008-08-24 10:35:55 +00004221#endif /* TARGET_I386 && TARGET_ABI32 */
bellard8d18e892007-11-14 15:18:40 +00004222
bellardd2fd1af2007-11-14 18:08:56 +00004223#ifndef TARGET_ABI32
Peter Maydell2667e712013-07-16 18:44:59 +01004224abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
bellardd2fd1af2007-11-14 18:08:56 +00004225{
Juan Quintela1add8692011-06-16 17:37:09 +01004226 abi_long ret = 0;
bellardd2fd1af2007-11-14 18:08:56 +00004227 abi_ulong val;
4228 int idx;
Juan Quintela1add8692011-06-16 17:37:09 +01004229
bellardd2fd1af2007-11-14 18:08:56 +00004230 switch(code) {
4231 case TARGET_ARCH_SET_GS:
4232 case TARGET_ARCH_SET_FS:
4233 if (code == TARGET_ARCH_SET_GS)
4234 idx = R_GS;
4235 else
4236 idx = R_FS;
4237 cpu_x86_load_seg(env, idx, 0);
4238 env->segs[idx].base = addr;
4239 break;
4240 case TARGET_ARCH_GET_GS:
4241 case TARGET_ARCH_GET_FS:
4242 if (code == TARGET_ARCH_GET_GS)
4243 idx = R_GS;
4244 else
4245 idx = R_FS;
4246 val = env->segs[idx].base;
4247 if (put_user(val, addr, abi_ulong))
Juan Quintela1add8692011-06-16 17:37:09 +01004248 ret = -TARGET_EFAULT;
bellardd2fd1af2007-11-14 18:08:56 +00004249 break;
4250 default:
4251 ret = -TARGET_EINVAL;
4252 break;
4253 }
Juan Quintela1add8692011-06-16 17:37:09 +01004254 return ret;
bellardd2fd1af2007-11-14 18:08:56 +00004255}
4256#endif
4257
bellard2ab83ea2003-06-15 19:56:46 +00004258#endif /* defined(TARGET_I386) */
4259
Riku Voipio05098a92011-03-04 15:27:29 +02004260#define NEW_STACK_SIZE 0x40000
pbrookd865bab2008-06-07 22:12:17 +00004261
pbrookd865bab2008-06-07 22:12:17 +00004262
4263static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
4264typedef struct {
Andreas Färber9349b4f2012-03-14 01:38:32 +01004265 CPUArchState *env;
pbrookd865bab2008-06-07 22:12:17 +00004266 pthread_mutex_t mutex;
4267 pthread_cond_t cond;
4268 pthread_t thread;
4269 uint32_t tid;
4270 abi_ulong child_tidptr;
4271 abi_ulong parent_tidptr;
4272 sigset_t sigmask;
4273} new_thread_info;
4274
4275static void *clone_func(void *arg)
4276{
4277 new_thread_info *info = arg;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004278 CPUArchState *env;
Andreas Färber0d342822012-12-17 07:12:13 +01004279 CPUState *cpu;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004280 TaskState *ts;
pbrookd865bab2008-06-07 22:12:17 +00004281
4282 env = info->env;
Andreas Färber0d342822012-12-17 07:12:13 +01004283 cpu = ENV_GET_CPU(env);
Andreas Färbera2247f82013-06-09 19:47:04 +02004284 thread_cpu = cpu;
Andreas Färber0429a972013-08-26 18:14:44 +02004285 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004286 info->tid = gettid();
Andreas Färber0d342822012-12-17 07:12:13 +01004287 cpu->host_tid = info->tid;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004288 task_settid(ts);
pbrookd865bab2008-06-07 22:12:17 +00004289 if (info->child_tidptr)
4290 put_user_u32(info->tid, info->child_tidptr);
4291 if (info->parent_tidptr)
4292 put_user_u32(info->tid, info->parent_tidptr);
4293 /* Enable signals. */
4294 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
4295 /* Signal to the parent that we're ready. */
4296 pthread_mutex_lock(&info->mutex);
4297 pthread_cond_broadcast(&info->cond);
4298 pthread_mutex_unlock(&info->mutex);
4299 /* Wait until the parent has finshed initializing the tls state. */
4300 pthread_mutex_lock(&clone_lock);
4301 pthread_mutex_unlock(&clone_lock);
4302 cpu_loop(env);
4303 /* never exits */
4304 return NULL;
4305}
bellard1b6b0292003-03-22 17:31:38 +00004306
ths0da46a62007-10-20 20:23:07 +00004307/* do_fork() Must return host values and target errnos (unlike most
4308 do_*() functions). */
Andreas Färber9349b4f2012-03-14 01:38:32 +01004309static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pbrookd865bab2008-06-07 22:12:17 +00004310 abi_ulong parent_tidptr, target_ulong newtls,
4311 abi_ulong child_tidptr)
bellard1b6b0292003-03-22 17:31:38 +00004312{
Andreas Färber0429a972013-08-26 18:14:44 +02004313 CPUState *cpu = ENV_GET_CPU(env);
bellard1b6b0292003-03-22 17:31:38 +00004314 int ret;
bellard5cd43932003-03-29 16:54:36 +00004315 TaskState *ts;
Andreas Färber0429a972013-08-26 18:14:44 +02004316 CPUState *new_cpu;
Andreas Färber9349b4f2012-03-14 01:38:32 +01004317 CPUArchState *new_env;
pbrookd865bab2008-06-07 22:12:17 +00004318 unsigned int nptl_flags;
4319 sigset_t sigmask;
ths3b46e622007-09-17 08:09:54 +00004320
balrog436d1242008-09-21 02:39:45 +00004321 /* Emulate vfork() with fork() */
4322 if (flags & CLONE_VFORK)
4323 flags &= ~(CLONE_VFORK | CLONE_VM);
4324
bellard1b6b0292003-03-22 17:31:38 +00004325 if (flags & CLONE_VM) {
Andreas Färber0429a972013-08-26 18:14:44 +02004326 TaskState *parent_ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004327 new_thread_info info;
4328 pthread_attr_t attr;
Peter Maydell24cb36a2013-07-16 18:45:00 +01004329
Anthony Liguori7267c092011-08-20 22:09:37 -05004330 ts = g_malloc0(sizeof(TaskState));
pbrook624f7972008-05-31 16:11:38 +00004331 init_task_state(ts);
bellard1b6b0292003-03-22 17:31:38 +00004332 /* we create a new CPU instance. */
thsc5be9f02007-02-28 20:20:53 +00004333 new_env = cpu_copy(env);
pbrook6e68e072008-05-30 17:22:15 +00004334 /* Init regs that differ from the parent. */
4335 cpu_clone_regs(new_env, newsp);
Andreas Färber0429a972013-08-26 18:14:44 +02004336 new_cpu = ENV_GET_CPU(new_env);
4337 new_cpu->opaque = ts;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +03004338 ts->bprm = parent_ts->bprm;
4339 ts->info = parent_ts->info;
pbrookd865bab2008-06-07 22:12:17 +00004340 nptl_flags = flags;
4341 flags &= ~CLONE_NPTL_FLAGS2;
4342
pbrookc2764712009-03-07 15:24:59 +00004343 if (nptl_flags & CLONE_CHILD_CLEARTID) {
4344 ts->child_tidptr = child_tidptr;
4345 }
4346
pbrookd865bab2008-06-07 22:12:17 +00004347 if (nptl_flags & CLONE_SETTLS)
4348 cpu_set_tls (new_env, newtls);
4349
4350 /* Grab a mutex so that thread setup appears atomic. */
4351 pthread_mutex_lock(&clone_lock);
4352
4353 memset(&info, 0, sizeof(info));
4354 pthread_mutex_init(&info.mutex, NULL);
4355 pthread_mutex_lock(&info.mutex);
4356 pthread_cond_init(&info.cond, NULL);
4357 info.env = new_env;
4358 if (nptl_flags & CLONE_CHILD_SETTID)
4359 info.child_tidptr = child_tidptr;
4360 if (nptl_flags & CLONE_PARENT_SETTID)
4361 info.parent_tidptr = parent_tidptr;
4362
4363 ret = pthread_attr_init(&attr);
Nathan Froyd48e15fc2010-10-29 07:48:57 -07004364 ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
4365 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pbrookd865bab2008-06-07 22:12:17 +00004366 /* It is not safe to deliver signals until the child has finished
4367 initializing, so temporarily block all signals. */
4368 sigfillset(&sigmask);
4369 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
4370
4371 ret = pthread_create(&info.thread, &attr, clone_func, &info);
pbrookc2764712009-03-07 15:24:59 +00004372 /* TODO: Free new CPU state if thread creation failed. */
pbrookd865bab2008-06-07 22:12:17 +00004373
4374 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
4375 pthread_attr_destroy(&attr);
4376 if (ret == 0) {
4377 /* Wait for the child to initialize. */
4378 pthread_cond_wait(&info.cond, &info.mutex);
4379 ret = info.tid;
4380 if (flags & CLONE_PARENT_SETTID)
4381 put_user_u32(ret, parent_tidptr);
4382 } else {
4383 ret = -1;
4384 }
4385 pthread_mutex_unlock(&info.mutex);
4386 pthread_cond_destroy(&info.cond);
4387 pthread_mutex_destroy(&info.mutex);
4388 pthread_mutex_unlock(&clone_lock);
bellard1b6b0292003-03-22 17:31:38 +00004389 } else {
4390 /* if no CLONE_VM, we consider it is a fork */
pbrookd865bab2008-06-07 22:12:17 +00004391 if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
bellard1b6b0292003-03-22 17:31:38 +00004392 return -EINVAL;
pbrookd865bab2008-06-07 22:12:17 +00004393 fork_start();
bellard1b6b0292003-03-22 17:31:38 +00004394 ret = fork();
pbrookd865bab2008-06-07 22:12:17 +00004395 if (ret == 0) {
aurel322b1319c2008-12-18 22:44:04 +00004396 /* Child Process. */
pbrookd865bab2008-06-07 22:12:17 +00004397 cpu_clone_regs(env, newsp);
4398 fork_end(1);
aurel322b1319c2008-12-18 22:44:04 +00004399 /* There is a race condition here. The parent process could
4400 theoretically read the TID in the child process before the child
4401 tid is set. This would require using either ptrace
4402 (not implemented) or having *_tidptr to point at a shared memory
4403 mapping. We can't repeat the spinlock hack used above because
4404 the child process gets its own copy of the lock. */
pbrookd865bab2008-06-07 22:12:17 +00004405 if (flags & CLONE_CHILD_SETTID)
4406 put_user_u32(gettid(), child_tidptr);
4407 if (flags & CLONE_PARENT_SETTID)
4408 put_user_u32(gettid(), parent_tidptr);
Andreas Färber0429a972013-08-26 18:14:44 +02004409 ts = (TaskState *)cpu->opaque;
pbrookd865bab2008-06-07 22:12:17 +00004410 if (flags & CLONE_SETTLS)
4411 cpu_set_tls (env, newtls);
pbrookc2764712009-03-07 15:24:59 +00004412 if (flags & CLONE_CHILD_CLEARTID)
4413 ts->child_tidptr = child_tidptr;
pbrookd865bab2008-06-07 22:12:17 +00004414 } else {
4415 fork_end(0);
4416 }
bellard1b6b0292003-03-22 17:31:38 +00004417 }
4418 return ret;
4419}
4420
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004421/* warning : doesn't handle linux specific flags... */
4422static int target_to_host_fcntl_cmd(int cmd)
4423{
4424 switch(cmd) {
4425 case TARGET_F_DUPFD:
4426 case TARGET_F_GETFD:
4427 case TARGET_F_SETFD:
4428 case TARGET_F_GETFL:
4429 case TARGET_F_SETFL:
4430 return cmd;
4431 case TARGET_F_GETLK:
4432 return F_GETLK;
4433 case TARGET_F_SETLK:
4434 return F_SETLK;
4435 case TARGET_F_SETLKW:
4436 return F_SETLKW;
4437 case TARGET_F_GETOWN:
4438 return F_GETOWN;
4439 case TARGET_F_SETOWN:
4440 return F_SETOWN;
4441 case TARGET_F_GETSIG:
4442 return F_GETSIG;
4443 case TARGET_F_SETSIG:
4444 return F_SETSIG;
4445#if TARGET_ABI_BITS == 32
4446 case TARGET_F_GETLK64:
4447 return F_GETLK64;
4448 case TARGET_F_SETLK64:
4449 return F_SETLK64;
4450 case TARGET_F_SETLKW64:
4451 return F_SETLKW64;
4452#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004453 case TARGET_F_SETLEASE:
4454 return F_SETLEASE;
4455 case TARGET_F_GETLEASE:
4456 return F_GETLEASE;
malcfbd5de92009-09-06 06:31:59 +04004457#ifdef F_DUPFD_CLOEXEC
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004458 case TARGET_F_DUPFD_CLOEXEC:
4459 return F_DUPFD_CLOEXEC;
malcfbd5de92009-09-06 06:31:59 +04004460#endif
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004461 case TARGET_F_NOTIFY:
4462 return F_NOTIFY;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004463#ifdef F_GETOWN_EX
4464 case TARGET_F_GETOWN_EX:
4465 return F_GETOWN_EX;
4466#endif
4467#ifdef F_SETOWN_EX
4468 case TARGET_F_SETOWN_EX:
4469 return F_SETOWN_EX;
4470#endif
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004471 default:
4472 return -TARGET_EINVAL;
4473 }
4474 return -TARGET_EINVAL;
4475}
4476
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004477#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
4478static const bitmask_transtbl flock_tbl[] = {
4479 TRANSTBL_CONVERT(F_RDLCK),
4480 TRANSTBL_CONVERT(F_WRLCK),
4481 TRANSTBL_CONVERT(F_UNLCK),
4482 TRANSTBL_CONVERT(F_EXLCK),
4483 TRANSTBL_CONVERT(F_SHLCK),
4484 { 0, 0, 0, 0 }
4485};
4486
blueswir1992f48a2007-10-14 16:27:31 +00004487static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
bellard7775e9e2003-05-14 22:46:48 +00004488{
4489 struct flock fl;
pbrook53a59602006-03-25 19:31:22 +00004490 struct target_flock *target_fl;
ths43f238d2007-01-05 20:55:49 +00004491 struct flock64 fl64;
4492 struct target_flock64 *target_fl64;
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004493#ifdef F_GETOWN_EX
4494 struct f_owner_ex fox;
4495 struct target_f_owner_ex *target_fox;
4496#endif
blueswir1992f48a2007-10-14 16:27:31 +00004497 abi_long ret;
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004498 int host_cmd = target_to_host_fcntl_cmd(cmd);
4499
4500 if (host_cmd == -TARGET_EINVAL)
4501 return host_cmd;
pbrook53a59602006-03-25 19:31:22 +00004502
bellard7775e9e2003-05-14 22:46:48 +00004503 switch(cmd) {
4504 case TARGET_F_GETLK:
bellard579a97f2007-11-11 14:26:47 +00004505 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4506 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004507 fl.l_type =
4508 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
ths58134272007-03-31 18:59:32 +00004509 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004510 fl.l_start = tswapal(target_fl->l_start);
4511 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004512 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00004513 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004514 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004515 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004516 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
4517 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004518 target_fl->l_type =
4519 host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004520 target_fl->l_whence = tswap16(fl.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004521 target_fl->l_start = tswapal(fl.l_start);
4522 target_fl->l_len = tswapal(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004523 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00004524 unlock_user_struct(target_fl, arg, 1);
bellard7775e9e2003-05-14 22:46:48 +00004525 }
4526 break;
ths3b46e622007-09-17 08:09:54 +00004527
bellard7775e9e2003-05-14 22:46:48 +00004528 case TARGET_F_SETLK:
4529 case TARGET_F_SETLKW:
bellard579a97f2007-11-11 14:26:47 +00004530 if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
4531 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004532 fl.l_type =
4533 target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
bellard7775e9e2003-05-14 22:46:48 +00004534 fl.l_whence = tswap16(target_fl->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004535 fl.l_start = tswapal(target_fl->l_start);
4536 fl.l_len = tswapal(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004537 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00004538 unlock_user_struct(target_fl, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004539 ret = get_errno(fcntl(fd, host_cmd, &fl));
bellard7775e9e2003-05-14 22:46:48 +00004540 break;
ths3b46e622007-09-17 08:09:54 +00004541
bellard7775e9e2003-05-14 22:46:48 +00004542 case TARGET_F_GETLK64:
bellard579a97f2007-11-11 14:26:47 +00004543 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4544 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004545 fl64.l_type =
4546 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths58134272007-03-31 18:59:32 +00004547 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004548 fl64.l_start = tswap64(target_fl64->l_start);
4549 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004550 fl64.l_pid = tswap32(target_fl64->l_pid);
ths58134272007-03-31 18:59:32 +00004551 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004552 ret = get_errno(fcntl(fd, host_cmd, &fl64));
ths43f238d2007-01-05 20:55:49 +00004553 if (ret == 0) {
bellard579a97f2007-11-11 14:26:47 +00004554 if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
4555 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004556 target_fl64->l_type =
4557 host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004558 target_fl64->l_whence = tswap16(fl64.l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004559 target_fl64->l_start = tswap64(fl64.l_start);
4560 target_fl64->l_len = tswap64(fl64.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004561 target_fl64->l_pid = tswap32(fl64.l_pid);
ths43f238d2007-01-05 20:55:49 +00004562 unlock_user_struct(target_fl64, arg, 1);
4563 }
bellard9ee1fa22007-11-11 15:11:19 +00004564 break;
bellard7775e9e2003-05-14 22:46:48 +00004565 case TARGET_F_SETLK64:
4566 case TARGET_F_SETLKW64:
bellard579a97f2007-11-11 14:26:47 +00004567 if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
4568 return -TARGET_EFAULT;
Laurent Vivier2ba7f732013-01-10 21:42:48 +01004569 fl64.l_type =
4570 target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
ths43f238d2007-01-05 20:55:49 +00004571 fl64.l_whence = tswap16(target_fl64->l_whence);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004572 fl64.l_start = tswap64(target_fl64->l_start);
4573 fl64.l_len = tswap64(target_fl64->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004574 fl64.l_pid = tswap32(target_fl64->l_pid);
ths43f238d2007-01-05 20:55:49 +00004575 unlock_user_struct(target_fl64, arg, 0);
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004576 ret = get_errno(fcntl(fd, host_cmd, &fl64));
bellard7775e9e2003-05-14 22:46:48 +00004577 break;
4578
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004579 case TARGET_F_GETFL:
4580 ret = get_errno(fcntl(fd, host_cmd, arg));
bellard9ee1fa22007-11-11 15:11:19 +00004581 if (ret >= 0) {
4582 ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
4583 }
bellardffa65c32004-01-04 23:57:22 +00004584 break;
4585
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004586 case TARGET_F_SETFL:
4587 ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
4588 break;
4589
Andreas Schwab8d5d3002014-03-07 15:24:08 +01004590#ifdef F_GETOWN_EX
4591 case TARGET_F_GETOWN_EX:
4592 ret = get_errno(fcntl(fd, host_cmd, &fox));
4593 if (ret >= 0) {
4594 if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
4595 return -TARGET_EFAULT;
4596 target_fox->type = tswap32(fox.type);
4597 target_fox->pid = tswap32(fox.pid);
4598 unlock_user_struct(target_fox, arg, 1);
4599 }
4600 break;
4601#endif
4602
4603#ifdef F_SETOWN_EX
4604 case TARGET_F_SETOWN_EX:
4605 if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
4606 return -TARGET_EFAULT;
4607 fox.type = tswap32(target_fox->type);
4608 fox.pid = tswap32(target_fox->pid);
4609 unlock_user_struct(target_fox, arg, 0);
4610 ret = get_errno(fcntl(fd, host_cmd, &fox));
4611 break;
4612#endif
4613
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004614 case TARGET_F_SETOWN:
4615 case TARGET_F_GETOWN:
4616 case TARGET_F_SETSIG:
4617 case TARGET_F_GETSIG:
Ulrich Hecht7e22e542009-07-24 19:10:27 +02004618 case TARGET_F_SETLEASE:
4619 case TARGET_F_GETLEASE:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02004620 ret = get_errno(fcntl(fd, host_cmd, arg));
bellardffa65c32004-01-04 23:57:22 +00004621 break;
4622
bellard7775e9e2003-05-14 22:46:48 +00004623 default:
bellard9ee1fa22007-11-11 15:11:19 +00004624 ret = get_errno(fcntl(fd, cmd, arg));
bellard7775e9e2003-05-14 22:46:48 +00004625 break;
4626 }
4627 return ret;
4628}
4629
bellard67867302003-11-23 17:05:30 +00004630#ifdef USE_UID16
bellard7775e9e2003-05-14 22:46:48 +00004631
bellard67867302003-11-23 17:05:30 +00004632static inline int high2lowuid(int uid)
4633{
4634 if (uid > 65535)
4635 return 65534;
4636 else
4637 return uid;
4638}
4639
4640static inline int high2lowgid(int gid)
4641{
4642 if (gid > 65535)
4643 return 65534;
4644 else
4645 return gid;
4646}
4647
4648static inline int low2highuid(int uid)
4649{
4650 if ((int16_t)uid == -1)
4651 return -1;
4652 else
4653 return uid;
4654}
4655
4656static inline int low2highgid(int gid)
4657{
4658 if ((int16_t)gid == -1)
4659 return -1;
4660 else
4661 return gid;
4662}
Riku Voipio0c866a72011-04-18 15:23:06 +03004663static inline int tswapid(int id)
4664{
4665 return tswap16(id);
4666}
Peter Maydell76ca3102014-03-02 19:36:41 +00004667
4668#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
4669
Riku Voipio0c866a72011-04-18 15:23:06 +03004670#else /* !USE_UID16 */
4671static inline int high2lowuid(int uid)
4672{
4673 return uid;
4674}
4675static inline int high2lowgid(int gid)
4676{
4677 return gid;
4678}
4679static inline int low2highuid(int uid)
4680{
4681 return uid;
4682}
4683static inline int low2highgid(int gid)
4684{
4685 return gid;
4686}
4687static inline int tswapid(int id)
4688{
4689 return tswap32(id);
4690}
Peter Maydell76ca3102014-03-02 19:36:41 +00004691
4692#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
4693
bellard67867302003-11-23 17:05:30 +00004694#endif /* USE_UID16 */
bellard1b6b0292003-03-22 17:31:38 +00004695
bellard31e31b82003-02-18 22:55:36 +00004696void syscall_init(void)
4697{
bellard2ab83ea2003-06-15 19:56:46 +00004698 IOCTLEntry *ie;
4699 const argtype *arg_type;
4700 int size;
thsb92c47c2007-11-01 00:07:38 +00004701 int i;
bellard2ab83ea2003-06-15 19:56:46 +00004702
Blue Swirl001faf32009-05-13 17:53:17 +00004703#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
ths5fafdf22007-09-16 21:08:06 +00004704#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
bellard31e31b82003-02-18 22:55:36 +00004705#include "syscall_types.h"
4706#undef STRUCT
4707#undef STRUCT_SPECIAL
bellard2ab83ea2003-06-15 19:56:46 +00004708
Peter Maydelldd6e9572012-07-23 08:07:22 +00004709 /* Build target_to_host_errno_table[] table from
4710 * host_to_target_errno_table[]. */
4711 for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
4712 target_to_host_errno_table[host_to_target_errno_table[i]] = i;
4713 }
4714
bellard2ab83ea2003-06-15 19:56:46 +00004715 /* we patch the ioctl size if necessary. We rely on the fact that
4716 no ioctl has all the bits at '1' in the size field */
4717 ie = ioctl_entries;
4718 while (ie->target_cmd != 0) {
4719 if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
4720 TARGET_IOC_SIZEMASK) {
4721 arg_type = ie->arg_type;
4722 if (arg_type[0] != TYPE_PTR) {
ths5fafdf22007-09-16 21:08:06 +00004723 fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
bellard2ab83ea2003-06-15 19:56:46 +00004724 ie->target_cmd);
4725 exit(1);
4726 }
4727 arg_type++;
4728 size = thunk_type_size(arg_type, 0);
ths5fafdf22007-09-16 21:08:06 +00004729 ie->target_cmd = (ie->target_cmd &
bellard2ab83ea2003-06-15 19:56:46 +00004730 ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
4731 (size << TARGET_IOC_SIZESHIFT);
4732 }
thsb92c47c2007-11-01 00:07:38 +00004733
bellard2ab83ea2003-06-15 19:56:46 +00004734 /* automatic consistency check if same arch */
balrog872ea0c2008-09-21 02:31:19 +00004735#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
4736 (defined(__x86_64__) && defined(TARGET_X86_64))
4737 if (unlikely(ie->target_cmd != ie->host_cmd)) {
4738 fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
4739 ie->name, ie->target_cmd, ie->host_cmd);
bellard2ab83ea2003-06-15 19:56:46 +00004740 }
4741#endif
4742 ie++;
4743 }
bellard31e31b82003-02-18 22:55:36 +00004744}
bellardc573ff62004-01-04 15:51:36 +00004745
blueswir1992f48a2007-10-14 16:27:31 +00004746#if TARGET_ABI_BITS == 32
pbrookce4defa2006-02-09 16:49:55 +00004747static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
4748{
thsaf325d32008-06-10 15:29:15 +00004749#ifdef TARGET_WORDS_BIGENDIAN
pbrookce4defa2006-02-09 16:49:55 +00004750 return ((uint64_t)word0 << 32) | word1;
4751#else
4752 return ((uint64_t)word1 << 32) | word0;
4753#endif
4754}
blueswir1992f48a2007-10-14 16:27:31 +00004755#else /* TARGET_ABI_BITS == 32 */
j_mayer32407102007-09-26 23:01:49 +00004756static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
4757{
4758 return word0;
4759}
blueswir1992f48a2007-10-14 16:27:31 +00004760#endif /* TARGET_ABI_BITS != 32 */
pbrookce4defa2006-02-09 16:49:55 +00004761
4762#ifdef TARGET_NR_truncate64
blueswir1992f48a2007-10-14 16:27:31 +00004763static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
4764 abi_long arg2,
4765 abi_long arg3,
4766 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004767{
Riku Voipio48e515d2011-07-12 15:40:51 +03004768 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004769 arg2 = arg3;
4770 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004771 }
pbrookce4defa2006-02-09 16:49:55 +00004772 return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
4773}
4774#endif
4775
4776#ifdef TARGET_NR_ftruncate64
blueswir1992f48a2007-10-14 16:27:31 +00004777static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
4778 abi_long arg2,
4779 abi_long arg3,
4780 abi_long arg4)
pbrookce4defa2006-02-09 16:49:55 +00004781{
Riku Voipio48e515d2011-07-12 15:40:51 +03004782 if (regpairs_aligned(cpu_env)) {
pbrookce4defa2006-02-09 16:49:55 +00004783 arg2 = arg3;
4784 arg3 = arg4;
Riku Voipio48e515d2011-07-12 15:40:51 +03004785 }
pbrookce4defa2006-02-09 16:49:55 +00004786 return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
4787}
4788#endif
4789
bellard579a97f2007-11-11 14:26:47 +00004790static inline abi_long target_to_host_timespec(struct timespec *host_ts,
4791 abi_ulong target_addr)
pbrook53a59602006-03-25 19:31:22 +00004792{
4793 struct target_timespec *target_ts;
4794
bellard579a97f2007-11-11 14:26:47 +00004795 if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
4796 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004797 host_ts->tv_sec = tswapal(target_ts->tv_sec);
4798 host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004799 unlock_user_struct(target_ts, target_addr, 0);
bellardb255bfa2008-05-10 21:51:02 +00004800 return 0;
pbrook53a59602006-03-25 19:31:22 +00004801}
4802
bellard579a97f2007-11-11 14:26:47 +00004803static inline abi_long host_to_target_timespec(abi_ulong target_addr,
4804 struct timespec *host_ts)
pbrook53a59602006-03-25 19:31:22 +00004805{
4806 struct target_timespec *target_ts;
4807
bellard579a97f2007-11-11 14:26:47 +00004808 if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
4809 return -TARGET_EFAULT;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02004810 target_ts->tv_sec = tswapal(host_ts->tv_sec);
4811 target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
pbrook53a59602006-03-25 19:31:22 +00004812 unlock_user_struct(target_ts, target_addr, 1);
bellardb255bfa2008-05-10 21:51:02 +00004813 return 0;
pbrook53a59602006-03-25 19:31:22 +00004814}
4815
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11004816static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
4817 abi_ulong target_addr)
4818{
4819 struct target_itimerspec *target_itspec;
4820
4821 if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
4822 return -TARGET_EFAULT;
4823 }
4824
4825 host_itspec->it_interval.tv_sec =
4826 tswapal(target_itspec->it_interval.tv_sec);
4827 host_itspec->it_interval.tv_nsec =
4828 tswapal(target_itspec->it_interval.tv_nsec);
4829 host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
4830 host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
4831
4832 unlock_user_struct(target_itspec, target_addr, 1);
4833 return 0;
4834}
4835
4836static inline abi_long host_to_target_itimerspec(abi_ulong target_addr,
4837 struct itimerspec *host_its)
4838{
4839 struct target_itimerspec *target_itspec;
4840
4841 if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
4842 return -TARGET_EFAULT;
4843 }
4844
4845 target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
4846 target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
4847
4848 target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
4849 target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
4850
4851 unlock_user_struct(target_itspec, target_addr, 0);
4852 return 0;
4853}
4854
aurel329d33b762009-04-08 23:07:05 +00004855#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
balrog6a24a772008-09-20 02:23:36 +00004856static inline abi_long host_to_target_stat64(void *cpu_env,
4857 abi_ulong target_addr,
4858 struct stat *host_st)
4859{
Alexander Graf09701192013-09-03 20:12:15 +01004860#if defined(TARGET_ARM) && defined(TARGET_ABI32)
balrog6a24a772008-09-20 02:23:36 +00004861 if (((CPUARMState *)cpu_env)->eabi) {
4862 struct target_eabi_stat64 *target_st;
4863
4864 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4865 return -TARGET_EFAULT;
4866 memset(target_st, 0, sizeof(struct target_eabi_stat64));
4867 __put_user(host_st->st_dev, &target_st->st_dev);
4868 __put_user(host_st->st_ino, &target_st->st_ino);
4869#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4870 __put_user(host_st->st_ino, &target_st->__st_ino);
4871#endif
4872 __put_user(host_st->st_mode, &target_st->st_mode);
4873 __put_user(host_st->st_nlink, &target_st->st_nlink);
4874 __put_user(host_st->st_uid, &target_st->st_uid);
4875 __put_user(host_st->st_gid, &target_st->st_gid);
4876 __put_user(host_st->st_rdev, &target_st->st_rdev);
4877 __put_user(host_st->st_size, &target_st->st_size);
4878 __put_user(host_st->st_blksize, &target_st->st_blksize);
4879 __put_user(host_st->st_blocks, &target_st->st_blocks);
4880 __put_user(host_st->st_atime, &target_st->target_st_atime);
4881 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4882 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4883 unlock_user_struct(target_st, target_addr, 1);
4884 } else
4885#endif
4886 {
Stefan Weil20d155b2013-10-30 22:52:24 +01004887#if defined(TARGET_HAS_STRUCT_STAT64)
balrog6a24a772008-09-20 02:23:36 +00004888 struct target_stat64 *target_st;
Stefan Weil20d155b2013-10-30 22:52:24 +01004889#else
4890 struct target_stat *target_st;
aurel329d33b762009-04-08 23:07:05 +00004891#endif
balrog6a24a772008-09-20 02:23:36 +00004892
4893 if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
4894 return -TARGET_EFAULT;
aurel329d33b762009-04-08 23:07:05 +00004895 memset(target_st, 0, sizeof(*target_st));
balrog6a24a772008-09-20 02:23:36 +00004896 __put_user(host_st->st_dev, &target_st->st_dev);
4897 __put_user(host_st->st_ino, &target_st->st_ino);
4898#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
4899 __put_user(host_st->st_ino, &target_st->__st_ino);
4900#endif
4901 __put_user(host_st->st_mode, &target_st->st_mode);
4902 __put_user(host_st->st_nlink, &target_st->st_nlink);
4903 __put_user(host_st->st_uid, &target_st->st_uid);
4904 __put_user(host_st->st_gid, &target_st->st_gid);
4905 __put_user(host_st->st_rdev, &target_st->st_rdev);
4906 /* XXX: better use of kernel struct */
4907 __put_user(host_st->st_size, &target_st->st_size);
4908 __put_user(host_st->st_blksize, &target_st->st_blksize);
4909 __put_user(host_st->st_blocks, &target_st->st_blocks);
4910 __put_user(host_st->st_atime, &target_st->target_st_atime);
4911 __put_user(host_st->st_mtime, &target_st->target_st_mtime);
4912 __put_user(host_st->st_ctime, &target_st->target_st_ctime);
4913 unlock_user_struct(target_st, target_addr, 1);
4914 }
4915
4916 return 0;
4917}
4918#endif
4919
pbrookbd0c5662008-05-29 14:34:11 +00004920/* ??? Using host futex calls even when target atomic operations
4921 are not really atomic probably breaks things. However implementing
4922 futexes locally would make futexes shared between multiple processes
4923 tricky. However they're probably useless because guest atomic
4924 operations won't work either. */
blueswir18fcd3692008-08-17 20:26:25 +00004925static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
4926 target_ulong uaddr2, int val3)
pbrookbd0c5662008-05-29 14:34:11 +00004927{
4928 struct timespec ts, *pts;
Nathan Froyda16aae02009-08-03 08:43:29 -07004929 int base_op;
pbrookbd0c5662008-05-29 14:34:11 +00004930
4931 /* ??? We assume FUTEX_* constants are the same on both host
4932 and target. */
Martin Mohringa29ccd62009-05-04 21:34:56 +03004933#ifdef FUTEX_CMD_MASK
Nathan Froyda16aae02009-08-03 08:43:29 -07004934 base_op = op & FUTEX_CMD_MASK;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004935#else
Nathan Froyda16aae02009-08-03 08:43:29 -07004936 base_op = op;
Martin Mohringa29ccd62009-05-04 21:34:56 +03004937#endif
Nathan Froyda16aae02009-08-03 08:43:29 -07004938 switch (base_op) {
pbrookbd0c5662008-05-29 14:34:11 +00004939 case FUTEX_WAIT:
John Rigbycce246e2013-02-23 16:14:07 -07004940 case FUTEX_WAIT_BITSET:
pbrookbd0c5662008-05-29 14:34:11 +00004941 if (timeout) {
4942 pts = &ts;
4943 target_to_host_timespec(pts, timeout);
4944 } else {
4945 pts = NULL;
4946 }
Martin Mohringa29ccd62009-05-04 21:34:56 +03004947 return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
John Rigbycce246e2013-02-23 16:14:07 -07004948 pts, NULL, val3));
pbrookbd0c5662008-05-29 14:34:11 +00004949 case FUTEX_WAKE:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004950 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004951 case FUTEX_FD:
Martin Mohringa29ccd62009-05-04 21:34:56 +03004952 return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
pbrookbd0c5662008-05-29 14:34:11 +00004953 case FUTEX_REQUEUE:
pbrookbd0c5662008-05-29 14:34:11 +00004954 case FUTEX_CMP_REQUEUE:
Nathan Froyda16aae02009-08-03 08:43:29 -07004955 case FUTEX_WAKE_OP:
4956 /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
4957 TIMEOUT parameter is interpreted as a uint32_t by the kernel.
4958 But the prototype takes a `struct timespec *'; insert casts
4959 to satisfy the compiler. We do not need to tswap TIMEOUT
4960 since it's not compared to guest memory. */
4961 pts = (struct timespec *)(uintptr_t) timeout;
4962 return get_errno(sys_futex(g2h(uaddr), op, val, pts,
4963 g2h(uaddr2),
4964 (base_op == FUTEX_CMP_REQUEUE
4965 ? tswap32(val3)
4966 : val3)));
pbrookbd0c5662008-05-29 14:34:11 +00004967 default:
4968 return -TARGET_ENOSYS;
4969 }
4970}
pbrookbd0c5662008-05-29 14:34:11 +00004971
pbrook1d9d8b52009-04-16 15:17:02 +00004972/* Map host to target signal numbers for the wait family of syscalls.
4973 Assume all other status bits are the same. */
Richard Hendersona05c6402012-09-15 11:34:20 -07004974int host_to_target_waitstatus(int status)
pbrook1d9d8b52009-04-16 15:17:02 +00004975{
4976 if (WIFSIGNALED(status)) {
4977 return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
4978 }
4979 if (WIFSTOPPED(status)) {
4980 return (host_to_target_signal(WSTOPSIG(status)) << 8)
4981 | (status & 0xff);
4982 }
4983 return status;
4984}
4985
Peter Maydell4a24a752013-09-03 20:12:20 +01004986static int relstr_to_int(const char *s)
pbrooka745ec62008-05-06 15:36:17 +00004987{
Peter Maydell4a24a752013-09-03 20:12:20 +01004988 /* Convert a uname release string like "2.6.18" to an integer
4989 * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
4990 */
pbrooka745ec62008-05-06 15:36:17 +00004991 int i, n, tmp;
Peter Maydell4a24a752013-09-03 20:12:20 +01004992
pbrooka745ec62008-05-06 15:36:17 +00004993 tmp = 0;
4994 for (i = 0; i < 3; i++) {
4995 n = 0;
4996 while (*s >= '0' && *s <= '9') {
4997 n *= 10;
4998 n += *s - '0';
4999 s++;
5000 }
5001 tmp = (tmp << 8) + n;
Peter Maydell4a24a752013-09-03 20:12:20 +01005002 if (*s == '.') {
pbrooka745ec62008-05-06 15:36:17 +00005003 s++;
Peter Maydell4a24a752013-09-03 20:12:20 +01005004 }
pbrooka745ec62008-05-06 15:36:17 +00005005 }
Peter Maydell4a24a752013-09-03 20:12:20 +01005006 return tmp;
5007}
5008
5009int get_osversion(void)
5010{
5011 static int osversion;
5012 struct new_utsname buf;
5013 const char *s;
5014
5015 if (osversion)
5016 return osversion;
5017 if (qemu_uname_release && *qemu_uname_release) {
5018 s = qemu_uname_release;
5019 } else {
5020 if (sys_uname(&buf))
5021 return 0;
5022 s = buf.release;
5023 }
5024 osversion = relstr_to_int(s);
pbrooka745ec62008-05-06 15:36:17 +00005025 return osversion;
5026}
5027
Peter Maydell4a24a752013-09-03 20:12:20 +01005028void init_qemu_uname_release(void)
5029{
5030 /* Initialize qemu_uname_release for later use.
5031 * If the host kernel is too old and the user hasn't asked for
5032 * a specific fake version number, we might want to fake a minimum
5033 * target kernel version.
5034 */
5035#ifdef UNAME_MINIMUM_RELEASE
5036 struct new_utsname buf;
5037
5038 if (qemu_uname_release && *qemu_uname_release) {
5039 return;
5040 }
5041
5042 if (sys_uname(&buf)) {
5043 return;
5044 }
5045
5046 if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
5047 qemu_uname_release = UNAME_MINIMUM_RELEASE;
5048 }
5049#endif
5050}
Alexander Graf36c08d42011-11-02 20:23:24 +01005051
5052static int open_self_maps(void *cpu_env, int fd)
5053{
Alexander Graf1a49ef22012-05-01 16:30:28 +01005054#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Andreas Färber0429a972013-08-26 18:14:44 +02005055 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5056 TaskState *ts = cpu->opaque;
Alexander Graf1a49ef22012-05-01 16:30:28 +01005057#endif
5058 FILE *fp;
5059 char *line = NULL;
5060 size_t len = 0;
5061 ssize_t read;
Alexander Graf36c08d42011-11-02 20:23:24 +01005062
Alexander Graf1a49ef22012-05-01 16:30:28 +01005063 fp = fopen("/proc/self/maps", "r");
5064 if (fp == NULL) {
5065 return -EACCES;
5066 }
5067
5068 while ((read = getline(&line, &len, fp)) != -1) {
5069 int fields, dev_maj, dev_min, inode;
5070 uint64_t min, max, offset;
5071 char flag_r, flag_w, flag_x, flag_p;
5072 char path[512] = "";
5073 fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
5074 " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
5075 &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
5076
5077 if ((fields < 10) || (fields > 11)) {
5078 continue;
5079 }
5080 if (!strncmp(path, "[stack]", 7)) {
5081 continue;
5082 }
5083 if (h2g_valid(min) && h2g_valid(max)) {
5084 dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx
Christophe Lyone24fed42013-04-02 14:03:38 +02005085 " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
Alexander Graf1a49ef22012-05-01 16:30:28 +01005086 h2g(min), h2g(max), flag_r, flag_w,
5087 flag_x, flag_p, offset, dev_maj, dev_min, inode,
Christophe Lyone24fed42013-04-02 14:03:38 +02005088 path[0] ? " " : "", path);
Alexander Graf1a49ef22012-05-01 16:30:28 +01005089 }
5090 }
5091
5092 free(line);
5093 fclose(fp);
5094
5095#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
Alexander Graf36c08d42011-11-02 20:23:24 +01005096 dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
5097 (unsigned long long)ts->info->stack_limit,
Alexander Graf1bdd7c72012-05-30 14:45:21 +02005098 (unsigned long long)(ts->info->start_stack +
5099 (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK,
Alexander Graf1a49ef22012-05-01 16:30:28 +01005100 (unsigned long long)0);
5101#endif
Alexander Graf36c08d42011-11-02 20:23:24 +01005102
5103 return 0;
5104}
5105
Alexander Graf480b8e72011-11-02 20:23:25 +01005106static int open_self_stat(void *cpu_env, int fd)
5107{
Andreas Färber0429a972013-08-26 18:14:44 +02005108 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5109 TaskState *ts = cpu->opaque;
Alexander Graf480b8e72011-11-02 20:23:25 +01005110 abi_ulong start_stack = ts->info->start_stack;
5111 int i;
5112
5113 for (i = 0; i < 44; i++) {
5114 char buf[128];
5115 int len;
5116 uint64_t val = 0;
5117
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005118 if (i == 0) {
5119 /* pid */
5120 val = getpid();
5121 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5122 } else if (i == 1) {
5123 /* app name */
5124 snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
5125 } else if (i == 27) {
5126 /* stack bottom */
5127 val = start_stack;
5128 snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
5129 } else {
5130 /* for the rest, there is MasterCard */
5131 snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
Alexander Graf480b8e72011-11-02 20:23:25 +01005132 }
Fabio Erculianie0e65be2012-01-03 09:38:34 +00005133
Alexander Graf480b8e72011-11-02 20:23:25 +01005134 len = strlen(buf);
5135 if (write(fd, buf, len) != len) {
5136 return -1;
5137 }
5138 }
5139
5140 return 0;
5141}
5142
Alexander Graf257450e2011-11-02 20:23:26 +01005143static int open_self_auxv(void *cpu_env, int fd)
5144{
Andreas Färber0429a972013-08-26 18:14:44 +02005145 CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
5146 TaskState *ts = cpu->opaque;
Alexander Graf257450e2011-11-02 20:23:26 +01005147 abi_ulong auxv = ts->info->saved_auxv;
5148 abi_ulong len = ts->info->auxv_len;
5149 char *ptr;
5150
5151 /*
5152 * Auxiliary vector is stored in target process stack.
5153 * read in whole auxv vector and copy it to file
5154 */
5155 ptr = lock_user(VERIFY_READ, auxv, len, 0);
5156 if (ptr != NULL) {
5157 while (len > 0) {
5158 ssize_t r;
5159 r = write(fd, ptr, len);
5160 if (r <= 0) {
5161 break;
5162 }
5163 len -= r;
5164 ptr += r;
5165 }
5166 lseek(fd, 0, SEEK_SET);
5167 unlock_user(ptr, auxv, len);
5168 }
5169
5170 return 0;
5171}
5172
Andreas Schwab463d8e72013-07-02 14:04:12 +01005173static int is_proc_myself(const char *filename, const char *entry)
5174{
5175 if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
5176 filename += strlen("/proc/");
5177 if (!strncmp(filename, "self/", strlen("self/"))) {
5178 filename += strlen("self/");
5179 } else if (*filename >= '1' && *filename <= '9') {
5180 char myself[80];
5181 snprintf(myself, sizeof(myself), "%d/", getpid());
5182 if (!strncmp(filename, myself, strlen(myself))) {
5183 filename += strlen(myself);
5184 } else {
5185 return 0;
5186 }
5187 } else {
5188 return 0;
5189 }
5190 if (!strcmp(filename, entry)) {
5191 return 1;
5192 }
5193 }
5194 return 0;
5195}
5196
Laurent Vivierde6b9932013-08-30 01:46:40 +02005197#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5198static int is_proc(const char *filename, const char *entry)
5199{
5200 return strcmp(filename, entry) == 0;
5201}
5202
5203static int open_net_route(void *cpu_env, int fd)
5204{
5205 FILE *fp;
5206 char *line = NULL;
5207 size_t len = 0;
5208 ssize_t read;
5209
5210 fp = fopen("/proc/net/route", "r");
5211 if (fp == NULL) {
5212 return -EACCES;
5213 }
5214
5215 /* read header */
5216
5217 read = getline(&line, &len, fp);
5218 dprintf(fd, "%s", line);
5219
5220 /* read routes */
5221
5222 while ((read = getline(&line, &len, fp)) != -1) {
5223 char iface[16];
5224 uint32_t dest, gw, mask;
5225 unsigned int flags, refcnt, use, metric, mtu, window, irtt;
5226 sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5227 iface, &dest, &gw, &flags, &refcnt, &use, &metric,
5228 &mask, &mtu, &window, &irtt);
5229 dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
5230 iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
5231 metric, tswap32(mask), mtu, window, irtt);
5232 }
5233
5234 free(line);
5235 fclose(fp);
5236
5237 return 0;
5238}
5239#endif
5240
Alexander Graf3be14d02011-11-02 20:23:23 +01005241static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
5242{
5243 struct fake_open {
5244 const char *filename;
5245 int (*fill)(void *cpu_env, int fd);
Laurent Vivierde6b9932013-08-30 01:46:40 +02005246 int (*cmp)(const char *s1, const char *s2);
Alexander Graf3be14d02011-11-02 20:23:23 +01005247 };
5248 const struct fake_open *fake_open;
5249 static const struct fake_open fakes[] = {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005250 { "maps", open_self_maps, is_proc_myself },
5251 { "stat", open_self_stat, is_proc_myself },
5252 { "auxv", open_self_auxv, is_proc_myself },
5253#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
5254 { "/proc/net/route", open_net_route, is_proc },
5255#endif
5256 { NULL, NULL, NULL }
Alexander Graf3be14d02011-11-02 20:23:23 +01005257 };
5258
Maxim Ostapenkoaa07f5e2014-05-02 11:17:07 +03005259 if (is_proc_myself(pathname, "exe")) {
5260 int execfd = qemu_getauxval(AT_EXECFD);
5261 return execfd ? execfd : get_errno(open(exec_path, flags, mode));
5262 }
5263
Alexander Graf3be14d02011-11-02 20:23:23 +01005264 for (fake_open = fakes; fake_open->filename; fake_open++) {
Laurent Vivierde6b9932013-08-30 01:46:40 +02005265 if (fake_open->cmp(pathname, fake_open->filename)) {
Alexander Graf3be14d02011-11-02 20:23:23 +01005266 break;
5267 }
5268 }
5269
5270 if (fake_open->filename) {
5271 const char *tmpdir;
5272 char filename[PATH_MAX];
5273 int fd, r;
5274
5275 /* create temporary file to map stat to */
5276 tmpdir = getenv("TMPDIR");
5277 if (!tmpdir)
5278 tmpdir = "/tmp";
5279 snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
5280 fd = mkstemp(filename);
5281 if (fd < 0) {
5282 return fd;
5283 }
5284 unlink(filename);
5285
5286 if ((r = fake_open->fill(cpu_env, fd))) {
5287 close(fd);
5288 return r;
5289 }
5290 lseek(fd, 0, SEEK_SET);
5291
5292 return fd;
5293 }
5294
5295 return get_errno(open(path(pathname), flags, mode));
5296}
5297
ths0da46a62007-10-20 20:23:07 +00005298/* do_syscall() should always have a single exit point at the end so
5299 that actions, such as logging of syscall results, can be performed.
5300 All errnos that do_syscall() returns must be -TARGET_<errcode>. */
blueswir1992f48a2007-10-14 16:27:31 +00005301abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
5302 abi_long arg2, abi_long arg3, abi_long arg4,
Peter Maydell5945cfc2011-06-16 17:37:13 +01005303 abi_long arg5, abi_long arg6, abi_long arg7,
5304 abi_long arg8)
bellard31e31b82003-02-18 22:55:36 +00005305{
Andreas Färber182735e2013-05-29 22:29:20 +02005306 CPUState *cpu = ENV_GET_CPU(cpu_env);
blueswir1992f48a2007-10-14 16:27:31 +00005307 abi_long ret;
bellard31e31b82003-02-18 22:55:36 +00005308 struct stat st;
bellard56c8f682005-11-28 22:28:41 +00005309 struct statfs stfs;
pbrook53a59602006-03-25 19:31:22 +00005310 void *p;
ths3b46e622007-09-17 08:09:54 +00005311
bellard72f03902003-02-18 23:33:18 +00005312#ifdef DEBUG
bellardc573ff62004-01-04 15:51:36 +00005313 gemu_log("syscall %d", num);
bellard72f03902003-02-18 23:33:18 +00005314#endif
thsb92c47c2007-11-01 00:07:38 +00005315 if(do_strace)
5316 print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
5317
bellard31e31b82003-02-18 22:55:36 +00005318 switch(num) {
5319 case TARGET_NR_exit:
Andreas Färber9b056fc2013-06-24 23:53:10 +02005320 /* In old applications this may be used to implement _exit(2).
5321 However in threaded applictions it is used for thread termination,
5322 and _exit_group is used for application termination.
5323 Do thread termination if we have more then one thread. */
5324 /* FIXME: This probably breaks if a signal arrives. We should probably
5325 be disabling signals. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005326 if (CPU_NEXT(first_cpu)) {
Andreas Färber9b056fc2013-06-24 23:53:10 +02005327 TaskState *ts;
pbrookc2764712009-03-07 15:24:59 +00005328
Andreas Färber9b056fc2013-06-24 23:53:10 +02005329 cpu_list_lock();
Andreas Färber9b056fc2013-06-24 23:53:10 +02005330 /* Remove the CPU from the list. */
Andreas Färberbdc44642013-06-24 23:50:24 +02005331 QTAILQ_REMOVE(&cpus, cpu, node);
Andreas Färber9b056fc2013-06-24 23:53:10 +02005332 cpu_list_unlock();
Andreas Färber0429a972013-08-26 18:14:44 +02005333 ts = cpu->opaque;
Andreas Färber9b056fc2013-06-24 23:53:10 +02005334 if (ts->child_tidptr) {
5335 put_user_u32(0, ts->child_tidptr);
5336 sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
5337 NULL, NULL, 0);
5338 }
Andreas Färbera2247f82013-06-09 19:47:04 +02005339 thread_cpu = NULL;
Andreas Färber0429a972013-08-26 18:14:44 +02005340 object_unref(OBJECT(cpu));
Andreas Färber9b056fc2013-06-24 23:53:10 +02005341 g_free(ts);
5342 pthread_exit(NULL);
5343 }
Juan Quintela9788c9c2009-07-27 16:13:02 +02005344#ifdef TARGET_GPROF
bellard7d132992003-03-06 23:23:54 +00005345 _mcleanup();
5346#endif
bellarde9009672005-04-26 20:42:36 +00005347 gdb_exit(cpu_env, arg1);
pbrookc2764712009-03-07 15:24:59 +00005348 _exit(arg1);
bellard31e31b82003-02-18 22:55:36 +00005349 ret = 0; /* avoid warning */
5350 break;
5351 case TARGET_NR_read:
aurel3238d840e2009-01-30 19:48:17 +00005352 if (arg3 == 0)
5353 ret = 0;
5354 else {
5355 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
5356 goto efault;
5357 ret = get_errno(read(arg1, p, arg3));
5358 unlock_user(p, arg2, ret);
5359 }
bellard31e31b82003-02-18 22:55:36 +00005360 break;
5361 case TARGET_NR_write:
bellard579a97f2007-11-11 14:26:47 +00005362 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
5363 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005364 ret = get_errno(write(arg1, p, arg3));
5365 unlock_user(p, arg2, 0);
bellard31e31b82003-02-18 22:55:36 +00005366 break;
5367 case TARGET_NR_open:
bellard2f619692007-11-16 10:46:05 +00005368 if (!(p = lock_user_string(arg1)))
5369 goto efault;
Alexander Graf3be14d02011-11-02 20:23:23 +01005370 ret = get_errno(do_open(cpu_env, p,
5371 target_to_host_bitmask(arg2, fcntl_flags_tbl),
5372 arg3));
pbrook53a59602006-03-25 19:31:22 +00005373 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005374 break;
ths82424832007-09-24 09:21:55 +00005375#if defined(TARGET_NR_openat) && defined(__NR_openat)
5376 case TARGET_NR_openat:
bellard579a97f2007-11-11 14:26:47 +00005377 if (!(p = lock_user_string(arg2)))
5378 goto efault;
5379 ret = get_errno(sys_openat(arg1,
5380 path(p),
5381 target_to_host_bitmask(arg3, fcntl_flags_tbl),
5382 arg4));
5383 unlock_user(p, arg2, 0);
ths82424832007-09-24 09:21:55 +00005384 break;
5385#endif
bellard31e31b82003-02-18 22:55:36 +00005386 case TARGET_NR_close:
5387 ret = get_errno(close(arg1));
5388 break;
5389 case TARGET_NR_brk:
pbrook53a59602006-03-25 19:31:22 +00005390 ret = do_brk(arg1);
bellard31e31b82003-02-18 22:55:36 +00005391 break;
5392 case TARGET_NR_fork:
pbrookd865bab2008-06-07 22:12:17 +00005393 ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00005394 break;
thse5febef2007-04-01 18:31:35 +00005395#ifdef TARGET_NR_waitpid
bellard31e31b82003-02-18 22:55:36 +00005396 case TARGET_NR_waitpid:
5397 {
pbrook53a59602006-03-25 19:31:22 +00005398 int status;
5399 ret = get_errno(waitpid(arg1, &status, arg3));
Alexander Graf53795572011-11-24 00:44:43 +01005400 if (!is_error(ret) && arg2 && ret
pbrook1d9d8b52009-04-16 15:17:02 +00005401 && put_user_s32(host_to_target_waitstatus(status), arg2))
bellard2f619692007-11-16 10:46:05 +00005402 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005403 }
5404 break;
thse5febef2007-04-01 18:31:35 +00005405#endif
pbrookf0cbb612008-05-30 18:20:05 +00005406#ifdef TARGET_NR_waitid
5407 case TARGET_NR_waitid:
5408 {
5409 siginfo_t info;
5410 info.si_pid = 0;
5411 ret = get_errno(waitid(arg1, arg2, &info, arg4));
5412 if (!is_error(ret) && arg3 && info.si_pid != 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -05005413 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
pbrookf0cbb612008-05-30 18:20:05 +00005414 goto efault;
5415 host_to_target_siginfo(p, &info);
Anthony Liguoric227f092009-10-01 16:12:16 -05005416 unlock_user(p, arg3, sizeof(target_siginfo_t));
pbrookf0cbb612008-05-30 18:20:05 +00005417 }
5418 }
5419 break;
5420#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005421#ifdef TARGET_NR_creat /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005422 case TARGET_NR_creat:
bellard579a97f2007-11-11 14:26:47 +00005423 if (!(p = lock_user_string(arg1)))
5424 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005425 ret = get_errno(creat(p, arg2));
5426 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005427 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005428#endif
bellard31e31b82003-02-18 22:55:36 +00005429 case TARGET_NR_link:
pbrook53a59602006-03-25 19:31:22 +00005430 {
5431 void * p2;
5432 p = lock_user_string(arg1);
5433 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005434 if (!p || !p2)
5435 ret = -TARGET_EFAULT;
5436 else
5437 ret = get_errno(link(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005438 unlock_user(p2, arg2, 0);
5439 unlock_user(p, arg1, 0);
5440 }
bellard31e31b82003-02-18 22:55:36 +00005441 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005442#if defined(TARGET_NR_linkat)
ths64f0ce42007-09-24 09:25:06 +00005443 case TARGET_NR_linkat:
ths64f0ce42007-09-24 09:25:06 +00005444 {
5445 void * p2 = NULL;
bellard579a97f2007-11-11 14:26:47 +00005446 if (!arg2 || !arg4)
5447 goto efault;
ths64f0ce42007-09-24 09:25:06 +00005448 p = lock_user_string(arg2);
5449 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005450 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005451 ret = -TARGET_EFAULT;
ths64f0ce42007-09-24 09:25:06 +00005452 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005453 ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
bellard579a97f2007-11-11 14:26:47 +00005454 unlock_user(p, arg2, 0);
5455 unlock_user(p2, arg4, 0);
ths64f0ce42007-09-24 09:25:06 +00005456 }
5457 break;
5458#endif
bellard31e31b82003-02-18 22:55:36 +00005459 case TARGET_NR_unlink:
bellard579a97f2007-11-11 14:26:47 +00005460 if (!(p = lock_user_string(arg1)))
5461 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005462 ret = get_errno(unlink(p));
5463 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005464 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005465#if defined(TARGET_NR_unlinkat)
ths8170f562007-09-24 09:24:11 +00005466 case TARGET_NR_unlinkat:
bellard579a97f2007-11-11 14:26:47 +00005467 if (!(p = lock_user_string(arg2)))
5468 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005469 ret = get_errno(unlinkat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005470 unlock_user(p, arg2, 0);
balroged494d82007-12-11 23:23:52 +00005471 break;
balrogb7d35e62007-12-12 00:40:24 +00005472#endif
bellard31e31b82003-02-18 22:55:36 +00005473 case TARGET_NR_execve:
bellard7854b052003-03-29 17:22:23 +00005474 {
5475 char **argp, **envp;
bellardf7341ff2003-03-30 21:00:25 +00005476 int argc, envc;
blueswir1992f48a2007-10-14 16:27:31 +00005477 abi_ulong gp;
5478 abi_ulong guest_argp;
5479 abi_ulong guest_envp;
5480 abi_ulong addr;
bellard7854b052003-03-29 17:22:23 +00005481 char **q;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005482 int total_size = 0;
bellard7854b052003-03-29 17:22:23 +00005483
bellardf7341ff2003-03-30 21:00:25 +00005484 argc = 0;
pbrook53a59602006-03-25 19:31:22 +00005485 guest_argp = arg2;
pbrookda94d262008-05-30 18:24:00 +00005486 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005487 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005488 goto efault;
ths03aa1972007-12-02 06:28:08 +00005489 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005490 break;
bellard7854b052003-03-29 17:22:23 +00005491 argc++;
bellard2f619692007-11-16 10:46:05 +00005492 }
bellardf7341ff2003-03-30 21:00:25 +00005493 envc = 0;
pbrook53a59602006-03-25 19:31:22 +00005494 guest_envp = arg3;
pbrookda94d262008-05-30 18:24:00 +00005495 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
ths03aa1972007-12-02 06:28:08 +00005496 if (get_user_ual(addr, gp))
bellard2f619692007-11-16 10:46:05 +00005497 goto efault;
ths03aa1972007-12-02 06:28:08 +00005498 if (!addr)
bellard2f619692007-11-16 10:46:05 +00005499 break;
bellard7854b052003-03-29 17:22:23 +00005500 envc++;
bellard2f619692007-11-16 10:46:05 +00005501 }
bellard7854b052003-03-29 17:22:23 +00005502
bellardf7341ff2003-03-30 21:00:25 +00005503 argp = alloca((argc + 1) * sizeof(void *));
5504 envp = alloca((envc + 1) * sizeof(void *));
bellard7854b052003-03-29 17:22:23 +00005505
pbrookda94d262008-05-30 18:24:00 +00005506 for (gp = guest_argp, q = argp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005507 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005508 if (get_user_ual(addr, gp))
5509 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005510 if (!addr)
5511 break;
bellard2f619692007-11-16 10:46:05 +00005512 if (!(*q = lock_user_string(addr)))
5513 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005514 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005515 }
bellardf7341ff2003-03-30 21:00:25 +00005516 *q = NULL;
5517
pbrookda94d262008-05-30 18:24:00 +00005518 for (gp = guest_envp, q = envp; gp;
blueswir1992f48a2007-10-14 16:27:31 +00005519 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005520 if (get_user_ual(addr, gp))
5521 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005522 if (!addr)
5523 break;
bellard2f619692007-11-16 10:46:05 +00005524 if (!(*q = lock_user_string(addr)))
5525 goto execve_efault;
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005526 total_size += strlen(*q) + 1;
pbrook53a59602006-03-25 19:31:22 +00005527 }
bellardf7341ff2003-03-30 21:00:25 +00005528 *q = NULL;
bellard7854b052003-03-29 17:22:23 +00005529
Ulrich Hechta6f79cc2012-01-31 12:43:16 +01005530 /* This case will not be caught by the host's execve() if its
5531 page size is bigger than the target's. */
5532 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
5533 ret = -TARGET_E2BIG;
5534 goto execve_end;
5535 }
bellard2f619692007-11-16 10:46:05 +00005536 if (!(p = lock_user_string(arg1)))
5537 goto execve_efault;
pbrook53a59602006-03-25 19:31:22 +00005538 ret = get_errno(execve(p, argp, envp));
5539 unlock_user(p, arg1, 0);
5540
bellard2f619692007-11-16 10:46:05 +00005541 goto execve_end;
5542
5543 execve_efault:
5544 ret = -TARGET_EFAULT;
5545
5546 execve_end:
pbrook53a59602006-03-25 19:31:22 +00005547 for (gp = guest_argp, q = argp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005548 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005549 if (get_user_ual(addr, gp)
5550 || !addr)
5551 break;
pbrook53a59602006-03-25 19:31:22 +00005552 unlock_user(*q, addr, 0);
5553 }
5554 for (gp = guest_envp, q = envp; *q;
blueswir1992f48a2007-10-14 16:27:31 +00005555 gp += sizeof(abi_ulong), q++) {
bellard2f619692007-11-16 10:46:05 +00005556 if (get_user_ual(addr, gp)
5557 || !addr)
5558 break;
pbrook53a59602006-03-25 19:31:22 +00005559 unlock_user(*q, addr, 0);
5560 }
bellard7854b052003-03-29 17:22:23 +00005561 }
bellard31e31b82003-02-18 22:55:36 +00005562 break;
5563 case TARGET_NR_chdir:
bellard579a97f2007-11-11 14:26:47 +00005564 if (!(p = lock_user_string(arg1)))
5565 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005566 ret = get_errno(chdir(p));
5567 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005568 break;
bellarda315a142005-01-30 22:59:18 +00005569#ifdef TARGET_NR_time
bellard31e31b82003-02-18 22:55:36 +00005570 case TARGET_NR_time:
5571 {
pbrook53a59602006-03-25 19:31:22 +00005572 time_t host_time;
5573 ret = get_errno(time(&host_time));
bellard2f619692007-11-16 10:46:05 +00005574 if (!is_error(ret)
5575 && arg1
5576 && put_user_sal(host_time, arg1))
5577 goto efault;
bellard31e31b82003-02-18 22:55:36 +00005578 }
5579 break;
bellarda315a142005-01-30 22:59:18 +00005580#endif
bellard31e31b82003-02-18 22:55:36 +00005581 case TARGET_NR_mknod:
bellard579a97f2007-11-11 14:26:47 +00005582 if (!(p = lock_user_string(arg1)))
5583 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005584 ret = get_errno(mknod(p, arg2, arg3));
5585 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005586 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005587#if defined(TARGET_NR_mknodat)
ths75ac37a2007-09-24 09:23:05 +00005588 case TARGET_NR_mknodat:
bellard579a97f2007-11-11 14:26:47 +00005589 if (!(p = lock_user_string(arg2)))
5590 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005591 ret = get_errno(mknodat(arg1, p, arg3, arg4));
bellard579a97f2007-11-11 14:26:47 +00005592 unlock_user(p, arg2, 0);
ths75ac37a2007-09-24 09:23:05 +00005593 break;
5594#endif
bellard31e31b82003-02-18 22:55:36 +00005595 case TARGET_NR_chmod:
bellard579a97f2007-11-11 14:26:47 +00005596 if (!(p = lock_user_string(arg1)))
5597 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005598 ret = get_errno(chmod(p, arg2));
5599 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005600 break;
bellardebc05482003-09-30 21:08:41 +00005601#ifdef TARGET_NR_break
bellard31e31b82003-02-18 22:55:36 +00005602 case TARGET_NR_break:
5603 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005604#endif
5605#ifdef TARGET_NR_oldstat
bellard31e31b82003-02-18 22:55:36 +00005606 case TARGET_NR_oldstat:
5607 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005608#endif
bellard31e31b82003-02-18 22:55:36 +00005609 case TARGET_NR_lseek:
5610 ret = get_errno(lseek(arg1, arg2, arg3));
5611 break;
Richard Henderson92317332010-05-03 10:07:53 -07005612#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
5613 /* Alpha specific */
j_mayer7a3148a2007-04-05 07:13:51 +00005614 case TARGET_NR_getxpid:
Richard Henderson92317332010-05-03 10:07:53 -07005615 ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
bellard31e31b82003-02-18 22:55:36 +00005616 ret = get_errno(getpid());
5617 break;
Richard Henderson92317332010-05-03 10:07:53 -07005618#endif
5619#ifdef TARGET_NR_getpid
5620 case TARGET_NR_getpid:
5621 ret = get_errno(getpid());
5622 break;
5623#endif
bellard31e31b82003-02-18 22:55:36 +00005624 case TARGET_NR_mount:
ths80265912007-02-17 22:25:41 +00005625 {
5626 /* need to look at the data field */
5627 void *p2, *p3;
5628 p = lock_user_string(arg1);
5629 p2 = lock_user_string(arg2);
5630 p3 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00005631 if (!p || !p2 || !p3)
5632 ret = -TARGET_EFAULT;
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005633 else {
bellard579a97f2007-11-11 14:26:47 +00005634 /* FIXME - arg5 should be locked, but it isn't clear how to
5635 * do that since it's not guaranteed to be a NULL-terminated
5636 * string.
5637 */
Jan-Simon Möllerdab46402009-10-17 21:52:43 +03005638 if ( ! arg5 )
5639 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
5640 else
5641 ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
5642 }
bellard579a97f2007-11-11 14:26:47 +00005643 unlock_user(p, arg1, 0);
5644 unlock_user(p2, arg2, 0);
5645 unlock_user(p3, arg3, 0);
ths80265912007-02-17 22:25:41 +00005646 break;
5647 }
thse5febef2007-04-01 18:31:35 +00005648#ifdef TARGET_NR_umount
bellard31e31b82003-02-18 22:55:36 +00005649 case TARGET_NR_umount:
bellard579a97f2007-11-11 14:26:47 +00005650 if (!(p = lock_user_string(arg1)))
5651 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005652 ret = get_errno(umount(p));
5653 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005654 break;
thse5febef2007-04-01 18:31:35 +00005655#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005656#ifdef TARGET_NR_stime /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005657 case TARGET_NR_stime:
5658 {
pbrook53a59602006-03-25 19:31:22 +00005659 time_t host_time;
bellard2f619692007-11-16 10:46:05 +00005660 if (get_user_sal(host_time, arg1))
5661 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005662 ret = get_errno(stime(&host_time));
bellard31e31b82003-02-18 22:55:36 +00005663 }
5664 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005665#endif
bellard31e31b82003-02-18 22:55:36 +00005666 case TARGET_NR_ptrace:
5667 goto unimplemented;
j_mayer7a3148a2007-04-05 07:13:51 +00005668#ifdef TARGET_NR_alarm /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005669 case TARGET_NR_alarm:
5670 ret = alarm(arg1);
5671 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005672#endif
bellardebc05482003-09-30 21:08:41 +00005673#ifdef TARGET_NR_oldfstat
bellard31e31b82003-02-18 22:55:36 +00005674 case TARGET_NR_oldfstat:
5675 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005676#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005677#ifdef TARGET_NR_pause /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005678 case TARGET_NR_pause:
5679 ret = get_errno(pause());
5680 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005681#endif
thse5febef2007-04-01 18:31:35 +00005682#ifdef TARGET_NR_utime
bellard31e31b82003-02-18 22:55:36 +00005683 case TARGET_NR_utime:
bellardebc05482003-09-30 21:08:41 +00005684 {
pbrook53a59602006-03-25 19:31:22 +00005685 struct utimbuf tbuf, *host_tbuf;
5686 struct target_utimbuf *target_tbuf;
5687 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005688 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
5689 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005690 tbuf.actime = tswapal(target_tbuf->actime);
5691 tbuf.modtime = tswapal(target_tbuf->modtime);
pbrook53a59602006-03-25 19:31:22 +00005692 unlock_user_struct(target_tbuf, arg2, 0);
5693 host_tbuf = &tbuf;
bellardf72e8ff2004-05-03 19:23:07 +00005694 } else {
pbrook53a59602006-03-25 19:31:22 +00005695 host_tbuf = NULL;
bellardf72e8ff2004-05-03 19:23:07 +00005696 }
bellard579a97f2007-11-11 14:26:47 +00005697 if (!(p = lock_user_string(arg1)))
5698 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005699 ret = get_errno(utime(p, host_tbuf));
5700 unlock_user(p, arg1, 0);
bellardebc05482003-09-30 21:08:41 +00005701 }
5702 break;
thse5febef2007-04-01 18:31:35 +00005703#endif
bellard978a66f2004-12-06 22:58:05 +00005704 case TARGET_NR_utimes:
5705 {
bellard978a66f2004-12-06 22:58:05 +00005706 struct timeval *tvp, tv[2];
pbrook53a59602006-03-25 19:31:22 +00005707 if (arg2) {
ths788f5ec2007-12-09 02:37:05 +00005708 if (copy_from_user_timeval(&tv[0], arg2)
5709 || copy_from_user_timeval(&tv[1],
5710 arg2 + sizeof(struct target_timeval)))
5711 goto efault;
bellard978a66f2004-12-06 22:58:05 +00005712 tvp = tv;
5713 } else {
5714 tvp = NULL;
5715 }
bellard579a97f2007-11-11 14:26:47 +00005716 if (!(p = lock_user_string(arg1)))
5717 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005718 ret = get_errno(utimes(p, tvp));
5719 unlock_user(p, arg1, 0);
bellard978a66f2004-12-06 22:58:05 +00005720 }
5721 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005722#if defined(TARGET_NR_futimesat)
balrogac8a6552008-09-20 02:25:39 +00005723 case TARGET_NR_futimesat:
5724 {
5725 struct timeval *tvp, tv[2];
5726 if (arg3) {
5727 if (copy_from_user_timeval(&tv[0], arg3)
5728 || copy_from_user_timeval(&tv[1],
5729 arg3 + sizeof(struct target_timeval)))
5730 goto efault;
5731 tvp = tv;
5732 } else {
5733 tvp = NULL;
5734 }
5735 if (!(p = lock_user_string(arg2)))
5736 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005737 ret = get_errno(futimesat(arg1, path(p), tvp));
balrogac8a6552008-09-20 02:25:39 +00005738 unlock_user(p, arg2, 0);
5739 }
5740 break;
5741#endif
bellardebc05482003-09-30 21:08:41 +00005742#ifdef TARGET_NR_stty
bellard31e31b82003-02-18 22:55:36 +00005743 case TARGET_NR_stty:
5744 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005745#endif
5746#ifdef TARGET_NR_gtty
bellard31e31b82003-02-18 22:55:36 +00005747 case TARGET_NR_gtty:
5748 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005749#endif
bellard31e31b82003-02-18 22:55:36 +00005750 case TARGET_NR_access:
bellard579a97f2007-11-11 14:26:47 +00005751 if (!(p = lock_user_string(arg1)))
5752 goto efault;
Ulrich Hecht719f9082009-07-03 17:09:29 +02005753 ret = get_errno(access(path(p), arg2));
pbrook53a59602006-03-25 19:31:22 +00005754 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005755 break;
ths92a34c12007-09-24 09:27:49 +00005756#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
5757 case TARGET_NR_faccessat:
bellard579a97f2007-11-11 14:26:47 +00005758 if (!(p = lock_user_string(arg2)))
5759 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005760 ret = get_errno(faccessat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00005761 unlock_user(p, arg2, 0);
ths92a34c12007-09-24 09:27:49 +00005762 break;
5763#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005764#ifdef TARGET_NR_nice /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005765 case TARGET_NR_nice:
5766 ret = get_errno(nice(arg1));
5767 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005768#endif
bellardebc05482003-09-30 21:08:41 +00005769#ifdef TARGET_NR_ftime
bellard31e31b82003-02-18 22:55:36 +00005770 case TARGET_NR_ftime:
5771 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005772#endif
bellard31e31b82003-02-18 22:55:36 +00005773 case TARGET_NR_sync:
bellard04369ff2003-03-20 22:33:23 +00005774 sync();
5775 ret = 0;
bellard31e31b82003-02-18 22:55:36 +00005776 break;
5777 case TARGET_NR_kill:
pbrook4cb05962008-05-30 18:05:19 +00005778 ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
bellard31e31b82003-02-18 22:55:36 +00005779 break;
5780 case TARGET_NR_rename:
pbrook53a59602006-03-25 19:31:22 +00005781 {
5782 void *p2;
5783 p = lock_user_string(arg1);
5784 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00005785 if (!p || !p2)
5786 ret = -TARGET_EFAULT;
5787 else
5788 ret = get_errno(rename(p, p2));
pbrook53a59602006-03-25 19:31:22 +00005789 unlock_user(p2, arg2, 0);
5790 unlock_user(p, arg1, 0);
5791 }
bellard31e31b82003-02-18 22:55:36 +00005792 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005793#if defined(TARGET_NR_renameat)
ths722183f2007-09-24 09:24:37 +00005794 case TARGET_NR_renameat:
ths722183f2007-09-24 09:24:37 +00005795 {
bellard579a97f2007-11-11 14:26:47 +00005796 void *p2;
ths722183f2007-09-24 09:24:37 +00005797 p = lock_user_string(arg2);
5798 p2 = lock_user_string(arg4);
bellard579a97f2007-11-11 14:26:47 +00005799 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00005800 ret = -TARGET_EFAULT;
ths722183f2007-09-24 09:24:37 +00005801 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01005802 ret = get_errno(renameat(arg1, p, arg3, p2));
bellard579a97f2007-11-11 14:26:47 +00005803 unlock_user(p2, arg4, 0);
5804 unlock_user(p, arg2, 0);
ths722183f2007-09-24 09:24:37 +00005805 }
5806 break;
5807#endif
bellard31e31b82003-02-18 22:55:36 +00005808 case TARGET_NR_mkdir:
bellard579a97f2007-11-11 14:26:47 +00005809 if (!(p = lock_user_string(arg1)))
5810 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005811 ret = get_errno(mkdir(p, arg2));
5812 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005813 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005814#if defined(TARGET_NR_mkdirat)
ths4472ad02007-09-24 09:22:32 +00005815 case TARGET_NR_mkdirat:
bellard579a97f2007-11-11 14:26:47 +00005816 if (!(p = lock_user_string(arg2)))
5817 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01005818 ret = get_errno(mkdirat(arg1, p, arg3));
bellard579a97f2007-11-11 14:26:47 +00005819 unlock_user(p, arg2, 0);
ths4472ad02007-09-24 09:22:32 +00005820 break;
5821#endif
bellard31e31b82003-02-18 22:55:36 +00005822 case TARGET_NR_rmdir:
bellard579a97f2007-11-11 14:26:47 +00005823 if (!(p = lock_user_string(arg1)))
5824 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005825 ret = get_errno(rmdir(p));
5826 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005827 break;
5828 case TARGET_NR_dup:
5829 ret = get_errno(dup(arg1));
5830 break;
5831 case TARGET_NR_pipe:
Richard Hendersonfb41a662010-05-03 10:07:52 -07005832 ret = do_pipe(cpu_env, arg1, 0, 0);
bellard31e31b82003-02-18 22:55:36 +00005833 break;
Riku Voipio099d6b02009-05-05 12:10:04 +03005834#ifdef TARGET_NR_pipe2
5835 case TARGET_NR_pipe2:
Richard Hendersone7ea6cb2012-06-01 18:48:39 -07005836 ret = do_pipe(cpu_env, arg1,
5837 target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
Riku Voipio099d6b02009-05-05 12:10:04 +03005838 break;
5839#endif
bellard31e31b82003-02-18 22:55:36 +00005840 case TARGET_NR_times:
bellard32f36bc2003-03-30 21:29:48 +00005841 {
pbrook53a59602006-03-25 19:31:22 +00005842 struct target_tms *tmsp;
bellard32f36bc2003-03-30 21:29:48 +00005843 struct tms tms;
5844 ret = get_errno(times(&tms));
pbrook53a59602006-03-25 19:31:22 +00005845 if (arg1) {
bellard579a97f2007-11-11 14:26:47 +00005846 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
5847 if (!tmsp)
5848 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02005849 tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
5850 tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
5851 tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
5852 tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
bellard32f36bc2003-03-30 21:29:48 +00005853 }
bellardc596ed12003-07-13 17:32:31 +00005854 if (!is_error(ret))
5855 ret = host_to_target_clock_t(ret);
bellard32f36bc2003-03-30 21:29:48 +00005856 }
5857 break;
bellardebc05482003-09-30 21:08:41 +00005858#ifdef TARGET_NR_prof
bellard31e31b82003-02-18 22:55:36 +00005859 case TARGET_NR_prof:
5860 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005861#endif
thse5febef2007-04-01 18:31:35 +00005862#ifdef TARGET_NR_signal
bellard31e31b82003-02-18 22:55:36 +00005863 case TARGET_NR_signal:
5864 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00005865#endif
bellard31e31b82003-02-18 22:55:36 +00005866 case TARGET_NR_acct:
aurel3238d840e2009-01-30 19:48:17 +00005867 if (arg1 == 0) {
5868 ret = get_errno(acct(NULL));
5869 } else {
5870 if (!(p = lock_user_string(arg1)))
5871 goto efault;
5872 ret = get_errno(acct(path(p)));
5873 unlock_user(p, arg1, 0);
5874 }
pbrook24836682006-04-16 14:14:53 +00005875 break;
Richard Henderson8070e7b2013-07-24 09:50:00 -10005876#ifdef TARGET_NR_umount2
bellard31e31b82003-02-18 22:55:36 +00005877 case TARGET_NR_umount2:
bellard579a97f2007-11-11 14:26:47 +00005878 if (!(p = lock_user_string(arg1)))
5879 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005880 ret = get_errno(umount2(p, arg2));
5881 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005882 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005883#endif
bellardebc05482003-09-30 21:08:41 +00005884#ifdef TARGET_NR_lock
bellard31e31b82003-02-18 22:55:36 +00005885 case TARGET_NR_lock:
5886 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005887#endif
bellard31e31b82003-02-18 22:55:36 +00005888 case TARGET_NR_ioctl:
5889 ret = do_ioctl(arg1, arg2, arg3);
5890 break;
5891 case TARGET_NR_fcntl:
bellard9ee1fa22007-11-11 15:11:19 +00005892 ret = do_fcntl(arg1, arg2, arg3);
bellard31e31b82003-02-18 22:55:36 +00005893 break;
bellardebc05482003-09-30 21:08:41 +00005894#ifdef TARGET_NR_mpx
bellard31e31b82003-02-18 22:55:36 +00005895 case TARGET_NR_mpx:
5896 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005897#endif
bellard31e31b82003-02-18 22:55:36 +00005898 case TARGET_NR_setpgid:
5899 ret = get_errno(setpgid(arg1, arg2));
5900 break;
bellardebc05482003-09-30 21:08:41 +00005901#ifdef TARGET_NR_ulimit
bellard31e31b82003-02-18 22:55:36 +00005902 case TARGET_NR_ulimit:
5903 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005904#endif
5905#ifdef TARGET_NR_oldolduname
bellard31e31b82003-02-18 22:55:36 +00005906 case TARGET_NR_oldolduname:
5907 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00005908#endif
bellard31e31b82003-02-18 22:55:36 +00005909 case TARGET_NR_umask:
5910 ret = get_errno(umask(arg1));
5911 break;
5912 case TARGET_NR_chroot:
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(chroot(p));
5916 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00005917 break;
5918 case TARGET_NR_ustat:
5919 goto unimplemented;
5920 case TARGET_NR_dup2:
5921 ret = get_errno(dup2(arg1, arg2));
5922 break;
Ulrich Hechtd0927932009-09-17 20:22:14 +03005923#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
5924 case TARGET_NR_dup3:
5925 ret = get_errno(dup3(arg1, arg2, arg3));
5926 break;
5927#endif
j_mayer7a3148a2007-04-05 07:13:51 +00005928#ifdef TARGET_NR_getppid /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00005929 case TARGET_NR_getppid:
5930 ret = get_errno(getppid());
5931 break;
j_mayer7a3148a2007-04-05 07:13:51 +00005932#endif
bellard31e31b82003-02-18 22:55:36 +00005933 case TARGET_NR_getpgrp:
5934 ret = get_errno(getpgrp());
5935 break;
5936 case TARGET_NR_setsid:
5937 ret = get_errno(setsid());
5938 break;
thse5febef2007-04-01 18:31:35 +00005939#ifdef TARGET_NR_sigaction
bellard31e31b82003-02-18 22:55:36 +00005940 case TARGET_NR_sigaction:
bellard31e31b82003-02-18 22:55:36 +00005941 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005942#if defined(TARGET_ALPHA)
5943 struct target_sigaction act, oact, *pact = 0;
pbrook53a59602006-03-25 19:31:22 +00005944 struct target_old_sigaction *old_act;
pbrook53a59602006-03-25 19:31:22 +00005945 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005946 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5947 goto efault;
bellard66fb9762003-03-23 01:06:05 +00005948 act._sa_handler = old_act->_sa_handler;
5949 target_siginitset(&act.sa_mask, old_act->sa_mask);
5950 act.sa_flags = old_act->sa_flags;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005951 act.sa_restorer = 0;
pbrook53a59602006-03-25 19:31:22 +00005952 unlock_user_struct(old_act, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00005953 pact = &act;
bellard66fb9762003-03-23 01:06:05 +00005954 }
5955 ret = get_errno(do_sigaction(arg1, pact, &oact));
pbrook53a59602006-03-25 19:31:22 +00005956 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005957 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5958 goto efault;
pbrook53a59602006-03-25 19:31:22 +00005959 old_act->_sa_handler = oact._sa_handler;
5960 old_act->sa_mask = oact.sa_mask.sig[0];
5961 old_act->sa_flags = oact.sa_flags;
pbrook53a59602006-03-25 19:31:22 +00005962 unlock_user_struct(old_act, arg3, 1);
bellard66fb9762003-03-23 01:06:05 +00005963 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005964#elif defined(TARGET_MIPS)
bellard106ec872006-06-27 21:08:10 +00005965 struct target_sigaction act, oact, *pact, *old_act;
5966
5967 if (arg2) {
bellard579a97f2007-11-11 14:26:47 +00005968 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5969 goto efault;
bellard106ec872006-06-27 21:08:10 +00005970 act._sa_handler = old_act->_sa_handler;
5971 target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
5972 act.sa_flags = old_act->sa_flags;
5973 unlock_user_struct(old_act, arg2, 0);
5974 pact = &act;
5975 } else {
5976 pact = NULL;
5977 }
5978
5979 ret = get_errno(do_sigaction(arg1, pact, &oact));
5980
5981 if (!is_error(ret) && arg3) {
bellard579a97f2007-11-11 14:26:47 +00005982 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
5983 goto efault;
bellard106ec872006-06-27 21:08:10 +00005984 old_act->_sa_handler = oact._sa_handler;
5985 old_act->sa_flags = oact.sa_flags;
5986 old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
5987 old_act->sa_mask.sig[1] = 0;
5988 old_act->sa_mask.sig[2] = 0;
5989 old_act->sa_mask.sig[3] = 0;
5990 unlock_user_struct(old_act, arg3, 1);
5991 }
Richard Henderson6049f4f2009-12-27 18:30:03 -08005992#else
5993 struct target_old_sigaction *old_act;
5994 struct target_sigaction act, oact, *pact;
5995 if (arg2) {
5996 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
5997 goto efault;
5998 act._sa_handler = old_act->_sa_handler;
5999 target_siginitset(&act.sa_mask, old_act->sa_mask);
6000 act.sa_flags = old_act->sa_flags;
6001 act.sa_restorer = old_act->sa_restorer;
6002 unlock_user_struct(old_act, arg2, 0);
6003 pact = &act;
6004 } else {
6005 pact = NULL;
6006 }
6007 ret = get_errno(do_sigaction(arg1, pact, &oact));
6008 if (!is_error(ret) && arg3) {
6009 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
6010 goto efault;
6011 old_act->_sa_handler = oact._sa_handler;
6012 old_act->sa_mask = oact.sa_mask.sig[0];
6013 old_act->sa_flags = oact.sa_flags;
6014 old_act->sa_restorer = oact.sa_restorer;
6015 unlock_user_struct(old_act, arg3, 1);
6016 }
ths388bb212007-05-13 13:58:00 +00006017#endif
bellard31e31b82003-02-18 22:55:36 +00006018 }
6019 break;
thse5febef2007-04-01 18:31:35 +00006020#endif
bellard66fb9762003-03-23 01:06:05 +00006021 case TARGET_NR_rt_sigaction:
pbrook53a59602006-03-25 19:31:22 +00006022 {
Richard Henderson6049f4f2009-12-27 18:30:03 -08006023#if defined(TARGET_ALPHA)
6024 struct target_sigaction act, oact, *pact = 0;
6025 struct target_rt_sigaction *rt_act;
6026 /* ??? arg4 == sizeof(sigset_t). */
6027 if (arg2) {
6028 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
6029 goto efault;
6030 act._sa_handler = rt_act->_sa_handler;
6031 act.sa_mask = rt_act->sa_mask;
6032 act.sa_flags = rt_act->sa_flags;
6033 act.sa_restorer = arg5;
6034 unlock_user_struct(rt_act, arg2, 0);
6035 pact = &act;
6036 }
6037 ret = get_errno(do_sigaction(arg1, pact, &oact));
6038 if (!is_error(ret) && arg3) {
6039 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
6040 goto efault;
6041 rt_act->_sa_handler = oact._sa_handler;
6042 rt_act->sa_mask = oact.sa_mask;
6043 rt_act->sa_flags = oact.sa_flags;
6044 unlock_user_struct(rt_act, arg3, 1);
6045 }
6046#else
pbrook53a59602006-03-25 19:31:22 +00006047 struct target_sigaction *act;
6048 struct target_sigaction *oact;
6049
bellard579a97f2007-11-11 14:26:47 +00006050 if (arg2) {
6051 if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
6052 goto efault;
6053 } else
pbrook53a59602006-03-25 19:31:22 +00006054 act = NULL;
bellard579a97f2007-11-11 14:26:47 +00006055 if (arg3) {
6056 if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
6057 ret = -TARGET_EFAULT;
6058 goto rt_sigaction_fail;
6059 }
6060 } else
pbrook53a59602006-03-25 19:31:22 +00006061 oact = NULL;
6062 ret = get_errno(do_sigaction(arg1, act, oact));
bellard579a97f2007-11-11 14:26:47 +00006063 rt_sigaction_fail:
6064 if (act)
pbrook53a59602006-03-25 19:31:22 +00006065 unlock_user_struct(act, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00006066 if (oact)
pbrook53a59602006-03-25 19:31:22 +00006067 unlock_user_struct(oact, arg3, 1);
Richard Henderson6049f4f2009-12-27 18:30:03 -08006068#endif
pbrook53a59602006-03-25 19:31:22 +00006069 }
bellard66fb9762003-03-23 01:06:05 +00006070 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006071#ifdef TARGET_NR_sgetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006072 case TARGET_NR_sgetmask:
bellard66fb9762003-03-23 01:06:05 +00006073 {
6074 sigset_t cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006075 abi_ulong target_set;
Alex Barcelo1c275922014-03-14 14:36:55 +00006076 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006077 host_to_target_old_sigset(&target_set, &cur_set);
6078 ret = target_set;
6079 }
6080 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006081#endif
6082#ifdef TARGET_NR_ssetmask /* not on alpha */
bellard31e31b82003-02-18 22:55:36 +00006083 case TARGET_NR_ssetmask:
bellard66fb9762003-03-23 01:06:05 +00006084 {
6085 sigset_t set, oset, cur_set;
blueswir1992f48a2007-10-14 16:27:31 +00006086 abi_ulong target_set = arg1;
Alex Barcelo1c275922014-03-14 14:36:55 +00006087 do_sigprocmask(0, NULL, &cur_set);
bellard66fb9762003-03-23 01:06:05 +00006088 target_to_host_old_sigset(&set, &target_set);
6089 sigorset(&set, &set, &cur_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00006090 do_sigprocmask(SIG_SETMASK, &set, &oset);
bellard66fb9762003-03-23 01:06:05 +00006091 host_to_target_old_sigset(&target_set, &oset);
6092 ret = target_set;
6093 }
6094 break;
j_mayer7a3148a2007-04-05 07:13:51 +00006095#endif
thse5febef2007-04-01 18:31:35 +00006096#ifdef TARGET_NR_sigprocmask
bellard66fb9762003-03-23 01:06:05 +00006097 case TARGET_NR_sigprocmask:
6098 {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006099#if defined(TARGET_ALPHA)
6100 sigset_t set, oldset;
6101 abi_ulong mask;
6102 int how;
6103
6104 switch (arg1) {
6105 case TARGET_SIG_BLOCK:
6106 how = SIG_BLOCK;
6107 break;
6108 case TARGET_SIG_UNBLOCK:
6109 how = SIG_UNBLOCK;
6110 break;
6111 case TARGET_SIG_SETMASK:
6112 how = SIG_SETMASK;
6113 break;
6114 default:
6115 ret = -TARGET_EINVAL;
6116 goto fail;
6117 }
6118 mask = arg2;
6119 target_to_host_old_sigset(&set, &mask);
6120
Alex Barcelo1c275922014-03-14 14:36:55 +00006121 ret = get_errno(do_sigprocmask(how, &set, &oldset));
Richard Hendersona5b3b132010-05-03 10:07:55 -07006122 if (!is_error(ret)) {
6123 host_to_target_old_sigset(&mask, &oldset);
6124 ret = mask;
Richard Henderson0229f5a2012-06-07 15:02:49 -07006125 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
Richard Hendersona5b3b132010-05-03 10:07:55 -07006126 }
6127#else
bellard66fb9762003-03-23 01:06:05 +00006128 sigset_t set, oldset, *set_ptr;
Richard Hendersona5b3b132010-05-03 10:07:55 -07006129 int how;
ths3b46e622007-09-17 08:09:54 +00006130
pbrook53a59602006-03-25 19:31:22 +00006131 if (arg2) {
Richard Hendersona5b3b132010-05-03 10:07:55 -07006132 switch (arg1) {
bellard66fb9762003-03-23 01:06:05 +00006133 case TARGET_SIG_BLOCK:
6134 how = SIG_BLOCK;
6135 break;
6136 case TARGET_SIG_UNBLOCK:
6137 how = SIG_UNBLOCK;
6138 break;
6139 case TARGET_SIG_SETMASK:
6140 how = SIG_SETMASK;
6141 break;
6142 default:
ths0da46a62007-10-20 20:23:07 +00006143 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006144 goto fail;
6145 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006146 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006147 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006148 target_to_host_old_sigset(&set, p);
6149 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006150 set_ptr = &set;
6151 } else {
6152 how = 0;
6153 set_ptr = NULL;
6154 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006155 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006156 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006157 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006158 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006159 host_to_target_old_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006160 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006161 }
Richard Hendersona5b3b132010-05-03 10:07:55 -07006162#endif
bellard66fb9762003-03-23 01:06:05 +00006163 }
6164 break;
thse5febef2007-04-01 18:31:35 +00006165#endif
bellard66fb9762003-03-23 01:06:05 +00006166 case TARGET_NR_rt_sigprocmask:
6167 {
6168 int how = arg1;
6169 sigset_t set, oldset, *set_ptr;
ths3b46e622007-09-17 08:09:54 +00006170
pbrook53a59602006-03-25 19:31:22 +00006171 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006172 switch(how) {
6173 case TARGET_SIG_BLOCK:
6174 how = SIG_BLOCK;
6175 break;
6176 case TARGET_SIG_UNBLOCK:
6177 how = SIG_UNBLOCK;
6178 break;
6179 case TARGET_SIG_SETMASK:
6180 how = SIG_SETMASK;
6181 break;
6182 default:
ths0da46a62007-10-20 20:23:07 +00006183 ret = -TARGET_EINVAL;
bellard66fb9762003-03-23 01:06:05 +00006184 goto fail;
6185 }
Anthony Liguoric227f092009-10-01 16:12:16 -05006186 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006187 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006188 target_to_host_sigset(&set, p);
6189 unlock_user(p, arg2, 0);
bellard66fb9762003-03-23 01:06:05 +00006190 set_ptr = &set;
6191 } else {
6192 how = 0;
6193 set_ptr = NULL;
6194 }
Alex Barcelo1c275922014-03-14 14:36:55 +00006195 ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
pbrook53a59602006-03-25 19:31:22 +00006196 if (!is_error(ret) && arg3) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006197 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006198 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006199 host_to_target_sigset(p, &oldset);
Anthony Liguoric227f092009-10-01 16:12:16 -05006200 unlock_user(p, arg3, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006201 }
6202 }
6203 break;
thse5febef2007-04-01 18:31:35 +00006204#ifdef TARGET_NR_sigpending
bellard66fb9762003-03-23 01:06:05 +00006205 case TARGET_NR_sigpending:
6206 {
6207 sigset_t set;
6208 ret = get_errno(sigpending(&set));
6209 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006210 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006211 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006212 host_to_target_old_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006213 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006214 }
6215 }
6216 break;
thse5febef2007-04-01 18:31:35 +00006217#endif
bellard66fb9762003-03-23 01:06:05 +00006218 case TARGET_NR_rt_sigpending:
6219 {
6220 sigset_t set;
6221 ret = get_errno(sigpending(&set));
6222 if (!is_error(ret)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05006223 if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
bellard579a97f2007-11-11 14:26:47 +00006224 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006225 host_to_target_sigset(p, &set);
Anthony Liguoric227f092009-10-01 16:12:16 -05006226 unlock_user(p, arg1, sizeof(target_sigset_t));
bellard66fb9762003-03-23 01:06:05 +00006227 }
6228 }
6229 break;
thse5febef2007-04-01 18:31:35 +00006230#ifdef TARGET_NR_sigsuspend
bellard66fb9762003-03-23 01:06:05 +00006231 case TARGET_NR_sigsuspend:
6232 {
6233 sigset_t set;
Richard Hendersonf43ce122010-05-03 10:07:54 -07006234#if defined(TARGET_ALPHA)
6235 abi_ulong mask = arg1;
6236 target_to_host_old_sigset(&set, &mask);
6237#else
Anthony Liguoric227f092009-10-01 16:12:16 -05006238 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006239 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006240 target_to_host_old_sigset(&set, p);
6241 unlock_user(p, arg1, 0);
Richard Hendersonf43ce122010-05-03 10:07:54 -07006242#endif
bellard66fb9762003-03-23 01:06:05 +00006243 ret = get_errno(sigsuspend(&set));
6244 }
6245 break;
thse5febef2007-04-01 18:31:35 +00006246#endif
bellard66fb9762003-03-23 01:06:05 +00006247 case TARGET_NR_rt_sigsuspend:
6248 {
6249 sigset_t set;
Anthony Liguoric227f092009-10-01 16:12:16 -05006250 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006251 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006252 target_to_host_sigset(&set, p);
6253 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006254 ret = get_errno(sigsuspend(&set));
6255 }
6256 break;
6257 case TARGET_NR_rt_sigtimedwait:
6258 {
bellard66fb9762003-03-23 01:06:05 +00006259 sigset_t set;
6260 struct timespec uts, *puts;
6261 siginfo_t uinfo;
ths3b46e622007-09-17 08:09:54 +00006262
Anthony Liguoric227f092009-10-01 16:12:16 -05006263 if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006264 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006265 target_to_host_sigset(&set, p);
6266 unlock_user(p, arg1, 0);
6267 if (arg3) {
bellard66fb9762003-03-23 01:06:05 +00006268 puts = &uts;
pbrook53a59602006-03-25 19:31:22 +00006269 target_to_host_timespec(puts, arg3);
bellard66fb9762003-03-23 01:06:05 +00006270 } else {
6271 puts = NULL;
6272 }
6273 ret = get_errno(sigtimedwait(&set, &uinfo, puts));
Petar Jovanovic974a1962014-03-03 15:07:41 +01006274 if (!is_error(ret)) {
6275 if (arg2) {
6276 p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
6277 0);
6278 if (!p) {
6279 goto efault;
6280 }
6281 host_to_target_siginfo(p, &uinfo);
6282 unlock_user(p, arg2, sizeof(target_siginfo_t));
6283 }
6284 ret = host_to_target_signal(ret);
bellard66fb9762003-03-23 01:06:05 +00006285 }
6286 }
6287 break;
6288 case TARGET_NR_rt_sigqueueinfo:
6289 {
6290 siginfo_t uinfo;
Anthony Liguoric227f092009-10-01 16:12:16 -05006291 if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
bellard579a97f2007-11-11 14:26:47 +00006292 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006293 target_to_host_siginfo(&uinfo, p);
6294 unlock_user(p, arg1, 0);
bellard66fb9762003-03-23 01:06:05 +00006295 ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
6296 }
6297 break;
thse5febef2007-04-01 18:31:35 +00006298#ifdef TARGET_NR_sigreturn
bellard66fb9762003-03-23 01:06:05 +00006299 case TARGET_NR_sigreturn:
6300 /* NOTE: ret is eax, so not transcoding must be done */
6301 ret = do_sigreturn(cpu_env);
6302 break;
thse5febef2007-04-01 18:31:35 +00006303#endif
bellard66fb9762003-03-23 01:06:05 +00006304 case TARGET_NR_rt_sigreturn:
6305 /* NOTE: ret is eax, so not transcoding must be done */
6306 ret = do_rt_sigreturn(cpu_env);
6307 break;
bellard31e31b82003-02-18 22:55:36 +00006308 case TARGET_NR_sethostname:
bellard579a97f2007-11-11 14:26:47 +00006309 if (!(p = lock_user_string(arg1)))
6310 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006311 ret = get_errno(sethostname(p, arg2));
6312 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006313 break;
6314 case TARGET_NR_setrlimit:
bellard9de5e442003-03-23 16:49:39 +00006315 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006316 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006317 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006318 struct rlimit rlim;
bellard579a97f2007-11-11 14:26:47 +00006319 if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
6320 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006321 rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
6322 rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006323 unlock_user_struct(target_rlim, arg2, 0);
bellard9de5e442003-03-23 16:49:39 +00006324 ret = get_errno(setrlimit(resource, &rlim));
6325 }
6326 break;
bellard31e31b82003-02-18 22:55:36 +00006327 case TARGET_NR_getrlimit:
bellard9de5e442003-03-23 16:49:39 +00006328 {
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03006329 int resource = target_to_host_resource(arg1);
pbrook53a59602006-03-25 19:31:22 +00006330 struct target_rlimit *target_rlim;
bellard9de5e442003-03-23 16:49:39 +00006331 struct rlimit rlim;
ths3b46e622007-09-17 08:09:54 +00006332
bellard9de5e442003-03-23 16:49:39 +00006333 ret = get_errno(getrlimit(resource, &rlim));
6334 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00006335 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
6336 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09006337 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
6338 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00006339 unlock_user_struct(target_rlim, arg2, 1);
bellard9de5e442003-03-23 16:49:39 +00006340 }
6341 }
6342 break;
bellard31e31b82003-02-18 22:55:36 +00006343 case TARGET_NR_getrusage:
bellardb4091862003-05-16 15:39:34 +00006344 {
6345 struct rusage rusage;
bellardb4091862003-05-16 15:39:34 +00006346 ret = get_errno(getrusage(arg1, &rusage));
6347 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006348 host_to_target_rusage(arg2, &rusage);
bellardb4091862003-05-16 15:39:34 +00006349 }
6350 }
6351 break;
bellard31e31b82003-02-18 22:55:36 +00006352 case TARGET_NR_gettimeofday:
6353 {
bellard31e31b82003-02-18 22:55:36 +00006354 struct timeval tv;
6355 ret = get_errno(gettimeofday(&tv, NULL));
6356 if (!is_error(ret)) {
ths788f5ec2007-12-09 02:37:05 +00006357 if (copy_to_user_timeval(arg1, &tv))
6358 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006359 }
6360 }
6361 break;
6362 case TARGET_NR_settimeofday:
6363 {
bellard31e31b82003-02-18 22:55:36 +00006364 struct timeval tv;
ths788f5ec2007-12-09 02:37:05 +00006365 if (copy_from_user_timeval(&tv, arg1))
6366 goto efault;
bellard31e31b82003-02-18 22:55:36 +00006367 ret = get_errno(settimeofday(&tv, NULL));
6368 }
6369 break;
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006370#if defined(TARGET_NR_select)
bellard31e31b82003-02-18 22:55:36 +00006371 case TARGET_NR_select:
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006372#if defined(TARGET_S390X) || defined(TARGET_ALPHA)
6373 ret = do_select(arg1, arg2, arg3, arg4, arg5);
6374#else
bellardf2674e32003-07-09 12:26:09 +00006375 {
pbrook53a59602006-03-25 19:31:22 +00006376 struct target_sel_arg_struct *sel;
blueswir1992f48a2007-10-14 16:27:31 +00006377 abi_ulong inp, outp, exp, tvp;
pbrook53a59602006-03-25 19:31:22 +00006378 long nsel;
6379
bellard579a97f2007-11-11 14:26:47 +00006380 if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
6381 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006382 nsel = tswapal(sel->n);
6383 inp = tswapal(sel->inp);
6384 outp = tswapal(sel->outp);
6385 exp = tswapal(sel->exp);
6386 tvp = tswapal(sel->tvp);
pbrook53a59602006-03-25 19:31:22 +00006387 unlock_user_struct(sel, arg1, 0);
6388 ret = do_select(nsel, inp, outp, exp, tvp);
bellardf2674e32003-07-09 12:26:09 +00006389 }
Laurent Vivier9468a5d2013-01-10 22:30:50 +01006390#endif
bellardf2674e32003-07-09 12:26:09 +00006391 break;
bellard048f6b42005-11-26 18:47:20 +00006392#endif
Riku Voipio9e423822010-05-07 12:28:05 +00006393#ifdef TARGET_NR_pselect6
6394 case TARGET_NR_pselect6:
Mike Frysinger055e0902011-06-03 17:01:49 -04006395 {
6396 abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
6397 fd_set rfds, wfds, efds;
6398 fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
6399 struct timespec ts, *ts_ptr;
6400
6401 /*
6402 * The 6th arg is actually two args smashed together,
6403 * so we cannot use the C library.
6404 */
6405 sigset_t set;
6406 struct {
6407 sigset_t *set;
6408 size_t size;
6409 } sig, *sig_ptr;
6410
6411 abi_ulong arg_sigset, arg_sigsize, *arg7;
6412 target_sigset_t *target_sigset;
6413
6414 n = arg1;
6415 rfd_addr = arg2;
6416 wfd_addr = arg3;
6417 efd_addr = arg4;
6418 ts_addr = arg5;
6419
6420 ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
6421 if (ret) {
6422 goto fail;
6423 }
6424 ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
6425 if (ret) {
6426 goto fail;
6427 }
6428 ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
6429 if (ret) {
6430 goto fail;
6431 }
6432
6433 /*
6434 * This takes a timespec, and not a timeval, so we cannot
6435 * use the do_select() helper ...
6436 */
6437 if (ts_addr) {
6438 if (target_to_host_timespec(&ts, ts_addr)) {
6439 goto efault;
6440 }
6441 ts_ptr = &ts;
6442 } else {
6443 ts_ptr = NULL;
6444 }
6445
6446 /* Extract the two packed args for the sigset */
6447 if (arg6) {
6448 sig_ptr = &sig;
6449 sig.size = _NSIG / 8;
6450
6451 arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
6452 if (!arg7) {
6453 goto efault;
6454 }
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006455 arg_sigset = tswapal(arg7[0]);
6456 arg_sigsize = tswapal(arg7[1]);
Mike Frysinger055e0902011-06-03 17:01:49 -04006457 unlock_user(arg7, arg6, 0);
6458
6459 if (arg_sigset) {
6460 sig.set = &set;
Peter Maydell8f04eeb2011-06-28 12:21:57 +01006461 if (arg_sigsize != sizeof(*target_sigset)) {
6462 /* Like the kernel, we enforce correct size sigsets */
6463 ret = -TARGET_EINVAL;
6464 goto fail;
6465 }
Mike Frysinger055e0902011-06-03 17:01:49 -04006466 target_sigset = lock_user(VERIFY_READ, arg_sigset,
6467 sizeof(*target_sigset), 1);
6468 if (!target_sigset) {
6469 goto efault;
6470 }
6471 target_to_host_sigset(&set, target_sigset);
6472 unlock_user(target_sigset, arg_sigset, 0);
6473 } else {
6474 sig.set = NULL;
6475 }
6476 } else {
6477 sig_ptr = NULL;
6478 }
6479
6480 ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
6481 ts_ptr, sig_ptr));
6482
6483 if (!is_error(ret)) {
6484 if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
6485 goto efault;
6486 if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
6487 goto efault;
6488 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
6489 goto efault;
6490
6491 if (ts_addr && host_to_target_timespec(ts_addr, &ts))
6492 goto efault;
6493 }
6494 }
6495 break;
Riku Voipio9e423822010-05-07 12:28:05 +00006496#endif
bellard31e31b82003-02-18 22:55:36 +00006497 case TARGET_NR_symlink:
pbrook53a59602006-03-25 19:31:22 +00006498 {
6499 void *p2;
6500 p = lock_user_string(arg1);
6501 p2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006502 if (!p || !p2)
6503 ret = -TARGET_EFAULT;
6504 else
6505 ret = get_errno(symlink(p, p2));
pbrook53a59602006-03-25 19:31:22 +00006506 unlock_user(p2, arg2, 0);
6507 unlock_user(p, arg1, 0);
6508 }
bellard31e31b82003-02-18 22:55:36 +00006509 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006510#if defined(TARGET_NR_symlinkat)
thsf0b62432007-09-24 09:25:40 +00006511 case TARGET_NR_symlinkat:
thsf0b62432007-09-24 09:25:40 +00006512 {
bellard579a97f2007-11-11 14:26:47 +00006513 void *p2;
thsf0b62432007-09-24 09:25:40 +00006514 p = lock_user_string(arg1);
6515 p2 = lock_user_string(arg3);
bellard579a97f2007-11-11 14:26:47 +00006516 if (!p || !p2)
ths0da46a62007-10-20 20:23:07 +00006517 ret = -TARGET_EFAULT;
thsf0b62432007-09-24 09:25:40 +00006518 else
Peter Maydellc0d472b2013-06-12 16:20:21 +01006519 ret = get_errno(symlinkat(p, arg2, p2));
bellard579a97f2007-11-11 14:26:47 +00006520 unlock_user(p2, arg3, 0);
6521 unlock_user(p, arg1, 0);
thsf0b62432007-09-24 09:25:40 +00006522 }
6523 break;
6524#endif
bellardebc05482003-09-30 21:08:41 +00006525#ifdef TARGET_NR_oldlstat
bellard31e31b82003-02-18 22:55:36 +00006526 case TARGET_NR_oldlstat:
6527 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006528#endif
bellard31e31b82003-02-18 22:55:36 +00006529 case TARGET_NR_readlink:
pbrook53a59602006-03-25 19:31:22 +00006530 {
Andreas Schwab463d8e72013-07-02 14:04:12 +01006531 void *p2;
pbrook53a59602006-03-25 19:31:22 +00006532 p = lock_user_string(arg1);
bellard579a97f2007-11-11 14:26:47 +00006533 p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006534 if (!p || !p2) {
bellard579a97f2007-11-11 14:26:47 +00006535 ret = -TARGET_EFAULT;
Andreas Schwab463d8e72013-07-02 14:04:12 +01006536 } else if (is_proc_myself((const char *)p, "exe")) {
6537 char real[PATH_MAX], *temp;
6538 temp = realpath(exec_path, real);
6539 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6540 snprintf((char *)p2, arg3, "%s", real);
6541 } else {
6542 ret = get_errno(readlink(path(p), p2, arg3));
aurel32d088d662009-01-30 20:09:01 +00006543 }
pbrook53a59602006-03-25 19:31:22 +00006544 unlock_user(p2, arg2, ret);
6545 unlock_user(p, arg1, 0);
6546 }
bellard31e31b82003-02-18 22:55:36 +00006547 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006548#if defined(TARGET_NR_readlinkat)
ths5e0ccb12007-09-24 09:26:10 +00006549 case TARGET_NR_readlinkat:
ths5e0ccb12007-09-24 09:26:10 +00006550 {
bellard579a97f2007-11-11 14:26:47 +00006551 void *p2;
ths5e0ccb12007-09-24 09:26:10 +00006552 p = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +00006553 p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
Andreas Schwab463d8e72013-07-02 14:04:12 +01006554 if (!p || !p2) {
6555 ret = -TARGET_EFAULT;
6556 } else if (is_proc_myself((const char *)p, "exe")) {
6557 char real[PATH_MAX], *temp;
6558 temp = realpath(exec_path, real);
6559 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
6560 snprintf((char *)p2, arg4, "%s", real);
6561 } else {
Peter Maydellc0d472b2013-06-12 16:20:21 +01006562 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
Andreas Schwab463d8e72013-07-02 14:04:12 +01006563 }
bellard579a97f2007-11-11 14:26:47 +00006564 unlock_user(p2, arg3, ret);
6565 unlock_user(p, arg2, 0);
ths5e0ccb12007-09-24 09:26:10 +00006566 }
6567 break;
6568#endif
thse5febef2007-04-01 18:31:35 +00006569#ifdef TARGET_NR_uselib
bellard31e31b82003-02-18 22:55:36 +00006570 case TARGET_NR_uselib:
6571 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006572#endif
6573#ifdef TARGET_NR_swapon
bellard31e31b82003-02-18 22:55:36 +00006574 case TARGET_NR_swapon:
bellard579a97f2007-11-11 14:26:47 +00006575 if (!(p = lock_user_string(arg1)))
6576 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006577 ret = get_errno(swapon(p, arg2));
6578 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006579 break;
thse5febef2007-04-01 18:31:35 +00006580#endif
bellard31e31b82003-02-18 22:55:36 +00006581 case TARGET_NR_reboot:
Laurent Vivierc07ecc62013-01-07 11:40:06 +00006582 if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
6583 /* arg4 must be ignored in all other cases */
6584 p = lock_user_string(arg4);
6585 if (!p) {
6586 goto efault;
6587 }
6588 ret = get_errno(reboot(arg1, arg2, arg3, p));
6589 unlock_user(p, arg4, 0);
6590 } else {
6591 ret = get_errno(reboot(arg1, arg2, arg3, NULL));
6592 }
Alexander Graf0f6b4d22011-09-27 14:39:42 +02006593 break;
thse5febef2007-04-01 18:31:35 +00006594#ifdef TARGET_NR_readdir
bellard31e31b82003-02-18 22:55:36 +00006595 case TARGET_NR_readdir:
6596 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00006597#endif
6598#ifdef TARGET_NR_mmap
bellard31e31b82003-02-18 22:55:36 +00006599 case TARGET_NR_mmap:
Alexander Graf09701192013-09-03 20:12:15 +01006600#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
6601 (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
Ulrich Hechta4c075f2009-07-24 16:57:31 +02006602 defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
6603 || defined(TARGET_S390X)
bellard31e31b82003-02-18 22:55:36 +00006604 {
blueswir1992f48a2007-10-14 16:27:31 +00006605 abi_ulong *v;
6606 abi_ulong v1, v2, v3, v4, v5, v6;
bellard579a97f2007-11-11 14:26:47 +00006607 if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
6608 goto efault;
Matthias Brauncbb21ee2011-08-12 19:57:41 +02006609 v1 = tswapal(v[0]);
6610 v2 = tswapal(v[1]);
6611 v3 = tswapal(v[2]);
6612 v4 = tswapal(v[3]);
6613 v5 = tswapal(v[4]);
6614 v6 = tswapal(v[5]);
pbrook53a59602006-03-25 19:31:22 +00006615 unlock_user(v, arg1, 0);
ths5fafdf22007-09-16 21:08:06 +00006616 ret = get_errno(target_mmap(v1, v2, v3,
bellard5286db72003-06-05 00:57:30 +00006617 target_to_host_bitmask(v4, mmap_flags_tbl),
6618 v5, v6));
bellard31e31b82003-02-18 22:55:36 +00006619 }
bellard31e31b82003-02-18 22:55:36 +00006620#else
ths5fafdf22007-09-16 21:08:06 +00006621 ret = get_errno(target_mmap(arg1, arg2, arg3,
6622 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard6fb883e2003-07-09 17:12:39 +00006623 arg5,
6624 arg6));
bellard31e31b82003-02-18 22:55:36 +00006625#endif
bellard6fb883e2003-07-09 17:12:39 +00006626 break;
thse5febef2007-04-01 18:31:35 +00006627#endif
bellarda315a142005-01-30 22:59:18 +00006628#ifdef TARGET_NR_mmap2
bellard6fb883e2003-07-09 17:12:39 +00006629 case TARGET_NR_mmap2:
pbrookbb7ec042008-03-25 22:28:25 +00006630#ifndef MMAP_SHIFT
bellardc573ff62004-01-04 15:51:36 +00006631#define MMAP_SHIFT 12
bellardc573ff62004-01-04 15:51:36 +00006632#endif
ths5fafdf22007-09-16 21:08:06 +00006633 ret = get_errno(target_mmap(arg1, arg2, arg3,
6634 target_to_host_bitmask(arg4, mmap_flags_tbl),
bellard5286db72003-06-05 00:57:30 +00006635 arg5,
bellardc573ff62004-01-04 15:51:36 +00006636 arg6 << MMAP_SHIFT));
bellard31e31b82003-02-18 22:55:36 +00006637 break;
bellarda315a142005-01-30 22:59:18 +00006638#endif
bellard31e31b82003-02-18 22:55:36 +00006639 case TARGET_NR_munmap:
bellard54936002003-05-13 00:25:15 +00006640 ret = get_errno(target_munmap(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00006641 break;
bellard9de5e442003-03-23 16:49:39 +00006642 case TARGET_NR_mprotect:
Paul Brook97374d32010-06-16 13:03:51 +01006643 {
Andreas Färber0429a972013-08-26 18:14:44 +02006644 TaskState *ts = cpu->opaque;
Paul Brook97374d32010-06-16 13:03:51 +01006645 /* Special hack to detect libc making the stack executable. */
6646 if ((arg3 & PROT_GROWSDOWN)
6647 && arg1 >= ts->info->stack_limit
6648 && arg1 <= ts->info->start_stack) {
6649 arg3 &= ~PROT_GROWSDOWN;
6650 arg2 = arg2 + arg1 - ts->info->stack_limit;
6651 arg1 = ts->info->stack_limit;
6652 }
6653 }
bellard54936002003-05-13 00:25:15 +00006654 ret = get_errno(target_mprotect(arg1, arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006655 break;
thse5febef2007-04-01 18:31:35 +00006656#ifdef TARGET_NR_mremap
bellard9de5e442003-03-23 16:49:39 +00006657 case TARGET_NR_mremap:
bellard54936002003-05-13 00:25:15 +00006658 ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
bellard9de5e442003-03-23 16:49:39 +00006659 break;
thse5febef2007-04-01 18:31:35 +00006660#endif
pbrook53a59602006-03-25 19:31:22 +00006661 /* ??? msync/mlock/munlock are broken for softmmu. */
thse5febef2007-04-01 18:31:35 +00006662#ifdef TARGET_NR_msync
bellard9de5e442003-03-23 16:49:39 +00006663 case TARGET_NR_msync:
pbrook53a59602006-03-25 19:31:22 +00006664 ret = get_errno(msync(g2h(arg1), arg2, arg3));
bellard9de5e442003-03-23 16:49:39 +00006665 break;
thse5febef2007-04-01 18:31:35 +00006666#endif
6667#ifdef TARGET_NR_mlock
bellard9de5e442003-03-23 16:49:39 +00006668 case TARGET_NR_mlock:
pbrook53a59602006-03-25 19:31:22 +00006669 ret = get_errno(mlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006670 break;
thse5febef2007-04-01 18:31:35 +00006671#endif
6672#ifdef TARGET_NR_munlock
bellard9de5e442003-03-23 16:49:39 +00006673 case TARGET_NR_munlock:
pbrook53a59602006-03-25 19:31:22 +00006674 ret = get_errno(munlock(g2h(arg1), arg2));
bellard9de5e442003-03-23 16:49:39 +00006675 break;
thse5febef2007-04-01 18:31:35 +00006676#endif
6677#ifdef TARGET_NR_mlockall
bellard9de5e442003-03-23 16:49:39 +00006678 case TARGET_NR_mlockall:
6679 ret = get_errno(mlockall(arg1));
6680 break;
thse5febef2007-04-01 18:31:35 +00006681#endif
6682#ifdef TARGET_NR_munlockall
bellard9de5e442003-03-23 16:49:39 +00006683 case TARGET_NR_munlockall:
6684 ret = get_errno(munlockall());
6685 break;
thse5febef2007-04-01 18:31:35 +00006686#endif
bellard31e31b82003-02-18 22:55:36 +00006687 case TARGET_NR_truncate:
bellard579a97f2007-11-11 14:26:47 +00006688 if (!(p = lock_user_string(arg1)))
6689 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006690 ret = get_errno(truncate(p, arg2));
6691 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006692 break;
6693 case TARGET_NR_ftruncate:
6694 ret = get_errno(ftruncate(arg1, arg2));
6695 break;
6696 case TARGET_NR_fchmod:
6697 ret = get_errno(fchmod(arg1, arg2));
6698 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006699#if defined(TARGET_NR_fchmodat)
ths814d7972007-09-24 09:26:51 +00006700 case TARGET_NR_fchmodat:
bellard579a97f2007-11-11 14:26:47 +00006701 if (!(p = lock_user_string(arg2)))
6702 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01006703 ret = get_errno(fchmodat(arg1, p, arg3, 0));
bellard579a97f2007-11-11 14:26:47 +00006704 unlock_user(p, arg2, 0);
ths814d7972007-09-24 09:26:51 +00006705 break;
6706#endif
bellard31e31b82003-02-18 22:55:36 +00006707 case TARGET_NR_getpriority:
Richard Henderson95c09822012-06-07 15:14:50 -07006708 /* Note that negative values are valid for getpriority, so we must
6709 differentiate based on errno settings. */
6710 errno = 0;
6711 ret = getpriority(arg1, arg2);
6712 if (ret == -1 && errno != 0) {
6713 ret = -host_to_target_errno(errno);
6714 break;
6715 }
6716#ifdef TARGET_ALPHA
6717 /* Return value is the unbiased priority. Signal no error. */
6718 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
6719#else
6720 /* Return value is a biased priority to avoid negative numbers. */
6721 ret = 20 - ret;
6722#endif
bellard31e31b82003-02-18 22:55:36 +00006723 break;
6724 case TARGET_NR_setpriority:
6725 ret = get_errno(setpriority(arg1, arg2, arg3));
6726 break;
bellardebc05482003-09-30 21:08:41 +00006727#ifdef TARGET_NR_profil
bellard31e31b82003-02-18 22:55:36 +00006728 case TARGET_NR_profil:
6729 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006730#endif
bellard31e31b82003-02-18 22:55:36 +00006731 case TARGET_NR_statfs:
bellard579a97f2007-11-11 14:26:47 +00006732 if (!(p = lock_user_string(arg1)))
6733 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006734 ret = get_errno(statfs(path(p), &stfs));
6735 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006736 convert_statfs:
6737 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006738 struct target_statfs *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006739
bellard579a97f2007-11-11 14:26:47 +00006740 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
6741 goto efault;
6742 __put_user(stfs.f_type, &target_stfs->f_type);
6743 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6744 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6745 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6746 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6747 __put_user(stfs.f_files, &target_stfs->f_files);
6748 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6749 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6750 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6751 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006752 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6753 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
pbrook53a59602006-03-25 19:31:22 +00006754 unlock_user_struct(target_stfs, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006755 }
6756 break;
6757 case TARGET_NR_fstatfs:
bellard56c8f682005-11-28 22:28:41 +00006758 ret = get_errno(fstatfs(arg1, &stfs));
bellard31e31b82003-02-18 22:55:36 +00006759 goto convert_statfs;
bellard56c8f682005-11-28 22:28:41 +00006760#ifdef TARGET_NR_statfs64
6761 case TARGET_NR_statfs64:
bellard579a97f2007-11-11 14:26:47 +00006762 if (!(p = lock_user_string(arg1)))
6763 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006764 ret = get_errno(statfs(path(p), &stfs));
6765 unlock_user(p, arg1, 0);
bellard56c8f682005-11-28 22:28:41 +00006766 convert_statfs64:
6767 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006768 struct target_statfs64 *target_stfs;
ths3b46e622007-09-17 08:09:54 +00006769
bellard579a97f2007-11-11 14:26:47 +00006770 if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
6771 goto efault;
6772 __put_user(stfs.f_type, &target_stfs->f_type);
6773 __put_user(stfs.f_bsize, &target_stfs->f_bsize);
6774 __put_user(stfs.f_blocks, &target_stfs->f_blocks);
6775 __put_user(stfs.f_bfree, &target_stfs->f_bfree);
6776 __put_user(stfs.f_bavail, &target_stfs->f_bavail);
6777 __put_user(stfs.f_files, &target_stfs->f_files);
6778 __put_user(stfs.f_ffree, &target_stfs->f_ffree);
6779 __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
6780 __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
6781 __put_user(stfs.f_namelen, &target_stfs->f_namelen);
Alexander Graf229d3372012-09-19 04:39:53 +02006782 __put_user(stfs.f_frsize, &target_stfs->f_frsize);
6783 memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
bellard579a97f2007-11-11 14:26:47 +00006784 unlock_user_struct(target_stfs, arg3, 1);
bellard56c8f682005-11-28 22:28:41 +00006785 }
6786 break;
6787 case TARGET_NR_fstatfs64:
6788 ret = get_errno(fstatfs(arg1, &stfs));
6789 goto convert_statfs64;
6790#endif
bellardebc05482003-09-30 21:08:41 +00006791#ifdef TARGET_NR_ioperm
bellard31e31b82003-02-18 22:55:36 +00006792 case TARGET_NR_ioperm:
6793 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006794#endif
thse5febef2007-04-01 18:31:35 +00006795#ifdef TARGET_NR_socketcall
bellard31e31b82003-02-18 22:55:36 +00006796 case TARGET_NR_socketcall:
pbrook53a59602006-03-25 19:31:22 +00006797 ret = do_socketcall(arg1, arg2);
bellard31e31b82003-02-18 22:55:36 +00006798 break;
thse5febef2007-04-01 18:31:35 +00006799#endif
bellard3532fa72006-06-24 15:06:03 +00006800#ifdef TARGET_NR_accept
6801 case TARGET_NR_accept:
Peter Maydella94b4982013-02-08 04:35:04 +00006802 ret = do_accept4(arg1, arg2, arg3, 0);
6803 break;
6804#endif
6805#ifdef TARGET_NR_accept4
6806 case TARGET_NR_accept4:
6807#ifdef CONFIG_ACCEPT4
6808 ret = do_accept4(arg1, arg2, arg3, arg4);
6809#else
6810 goto unimplemented;
6811#endif
bellard3532fa72006-06-24 15:06:03 +00006812 break;
6813#endif
6814#ifdef TARGET_NR_bind
6815 case TARGET_NR_bind:
6816 ret = do_bind(arg1, arg2, arg3);
6817 break;
6818#endif
6819#ifdef TARGET_NR_connect
6820 case TARGET_NR_connect:
6821 ret = do_connect(arg1, arg2, arg3);
6822 break;
6823#endif
6824#ifdef TARGET_NR_getpeername
6825 case TARGET_NR_getpeername:
pbrook1be9e1d2006-11-19 15:26:04 +00006826 ret = do_getpeername(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006827 break;
6828#endif
6829#ifdef TARGET_NR_getsockname
6830 case TARGET_NR_getsockname:
pbrook1be9e1d2006-11-19 15:26:04 +00006831 ret = do_getsockname(arg1, arg2, arg3);
bellard3532fa72006-06-24 15:06:03 +00006832 break;
6833#endif
6834#ifdef TARGET_NR_getsockopt
6835 case TARGET_NR_getsockopt:
6836 ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
6837 break;
6838#endif
6839#ifdef TARGET_NR_listen
6840 case TARGET_NR_listen:
pbrook1be9e1d2006-11-19 15:26:04 +00006841 ret = get_errno(listen(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006842 break;
6843#endif
6844#ifdef TARGET_NR_recv
6845 case TARGET_NR_recv:
pbrook214201b2007-03-17 01:27:24 +00006846 ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006847 break;
6848#endif
6849#ifdef TARGET_NR_recvfrom
6850 case TARGET_NR_recvfrom:
pbrook214201b2007-03-17 01:27:24 +00006851 ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006852 break;
6853#endif
6854#ifdef TARGET_NR_recvmsg
6855 case TARGET_NR_recvmsg:
6856 ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
6857 break;
6858#endif
6859#ifdef TARGET_NR_send
6860 case TARGET_NR_send:
pbrook1be9e1d2006-11-19 15:26:04 +00006861 ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
bellard3532fa72006-06-24 15:06:03 +00006862 break;
6863#endif
6864#ifdef TARGET_NR_sendmsg
6865 case TARGET_NR_sendmsg:
6866 ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
6867 break;
6868#endif
Alexander Graff19e00d2014-03-02 19:36:42 +00006869#ifdef TARGET_NR_sendmmsg
6870 case TARGET_NR_sendmmsg:
6871 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
6872 break;
6873 case TARGET_NR_recvmmsg:
6874 ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
6875 break;
6876#endif
bellard3532fa72006-06-24 15:06:03 +00006877#ifdef TARGET_NR_sendto
6878 case TARGET_NR_sendto:
pbrook1be9e1d2006-11-19 15:26:04 +00006879 ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
bellard3532fa72006-06-24 15:06:03 +00006880 break;
6881#endif
6882#ifdef TARGET_NR_shutdown
6883 case TARGET_NR_shutdown:
pbrook1be9e1d2006-11-19 15:26:04 +00006884 ret = get_errno(shutdown(arg1, arg2));
bellard3532fa72006-06-24 15:06:03 +00006885 break;
6886#endif
6887#ifdef TARGET_NR_socket
6888 case TARGET_NR_socket:
6889 ret = do_socket(arg1, arg2, arg3);
6890 break;
6891#endif
6892#ifdef TARGET_NR_socketpair
6893 case TARGET_NR_socketpair:
pbrook1be9e1d2006-11-19 15:26:04 +00006894 ret = do_socketpair(arg1, arg2, arg3, arg4);
bellard3532fa72006-06-24 15:06:03 +00006895 break;
6896#endif
6897#ifdef TARGET_NR_setsockopt
6898 case TARGET_NR_setsockopt:
6899 ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
6900 break;
6901#endif
ths7494b0f2007-02-11 18:26:53 +00006902
bellard31e31b82003-02-18 22:55:36 +00006903 case TARGET_NR_syslog:
bellard579a97f2007-11-11 14:26:47 +00006904 if (!(p = lock_user_string(arg2)))
6905 goto efault;
thse5574482007-02-11 20:03:13 +00006906 ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
6907 unlock_user(p, arg2, 0);
ths7494b0f2007-02-11 18:26:53 +00006908 break;
6909
bellard31e31b82003-02-18 22:55:36 +00006910 case TARGET_NR_setitimer:
bellard66fb9762003-03-23 01:06:05 +00006911 {
bellard66fb9762003-03-23 01:06:05 +00006912 struct itimerval value, ovalue, *pvalue;
6913
pbrook53a59602006-03-25 19:31:22 +00006914 if (arg2) {
bellard66fb9762003-03-23 01:06:05 +00006915 pvalue = &value;
ths788f5ec2007-12-09 02:37:05 +00006916 if (copy_from_user_timeval(&pvalue->it_interval, arg2)
6917 || copy_from_user_timeval(&pvalue->it_value,
6918 arg2 + sizeof(struct target_timeval)))
6919 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006920 } else {
6921 pvalue = NULL;
6922 }
6923 ret = get_errno(setitimer(arg1, pvalue, &ovalue));
pbrook53a59602006-03-25 19:31:22 +00006924 if (!is_error(ret) && arg3) {
ths788f5ec2007-12-09 02:37:05 +00006925 if (copy_to_user_timeval(arg3,
6926 &ovalue.it_interval)
6927 || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
6928 &ovalue.it_value))
6929 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006930 }
6931 }
6932 break;
bellard31e31b82003-02-18 22:55:36 +00006933 case TARGET_NR_getitimer:
bellard66fb9762003-03-23 01:06:05 +00006934 {
bellard66fb9762003-03-23 01:06:05 +00006935 struct itimerval value;
ths3b46e622007-09-17 08:09:54 +00006936
bellard66fb9762003-03-23 01:06:05 +00006937 ret = get_errno(getitimer(arg1, &value));
pbrook53a59602006-03-25 19:31:22 +00006938 if (!is_error(ret) && arg2) {
ths788f5ec2007-12-09 02:37:05 +00006939 if (copy_to_user_timeval(arg2,
6940 &value.it_interval)
6941 || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
6942 &value.it_value))
6943 goto efault;
bellard66fb9762003-03-23 01:06:05 +00006944 }
6945 }
6946 break;
bellard31e31b82003-02-18 22:55:36 +00006947 case TARGET_NR_stat:
bellard579a97f2007-11-11 14:26:47 +00006948 if (!(p = lock_user_string(arg1)))
6949 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006950 ret = get_errno(stat(path(p), &st));
6951 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006952 goto do_stat;
6953 case TARGET_NR_lstat:
bellard579a97f2007-11-11 14:26:47 +00006954 if (!(p = lock_user_string(arg1)))
6955 goto efault;
pbrook53a59602006-03-25 19:31:22 +00006956 ret = get_errno(lstat(path(p), &st));
6957 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00006958 goto do_stat;
6959 case TARGET_NR_fstat:
6960 {
6961 ret = get_errno(fstat(arg1, &st));
6962 do_stat:
6963 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00006964 struct target_stat *target_st;
thse3584652007-06-01 11:49:38 +00006965
bellard579a97f2007-11-11 14:26:47 +00006966 if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
6967 goto efault;
Ulrich Hecht12727912009-07-24 19:10:32 +02006968 memset(target_st, 0, sizeof(*target_st));
bellardd2fd1af2007-11-14 18:08:56 +00006969 __put_user(st.st_dev, &target_st->st_dev);
6970 __put_user(st.st_ino, &target_st->st_ino);
6971 __put_user(st.st_mode, &target_st->st_mode);
6972 __put_user(st.st_uid, &target_st->st_uid);
6973 __put_user(st.st_gid, &target_st->st_gid);
6974 __put_user(st.st_nlink, &target_st->st_nlink);
6975 __put_user(st.st_rdev, &target_st->st_rdev);
6976 __put_user(st.st_size, &target_st->st_size);
6977 __put_user(st.st_blksize, &target_st->st_blksize);
6978 __put_user(st.st_blocks, &target_st->st_blocks);
6979 __put_user(st.st_atime, &target_st->target_st_atime);
6980 __put_user(st.st_mtime, &target_st->target_st_mtime);
6981 __put_user(st.st_ctime, &target_st->target_st_ctime);
pbrook53a59602006-03-25 19:31:22 +00006982 unlock_user_struct(target_st, arg2, 1);
bellard31e31b82003-02-18 22:55:36 +00006983 }
6984 }
6985 break;
bellardebc05482003-09-30 21:08:41 +00006986#ifdef TARGET_NR_olduname
bellard31e31b82003-02-18 22:55:36 +00006987 case TARGET_NR_olduname:
6988 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006989#endif
6990#ifdef TARGET_NR_iopl
bellard31e31b82003-02-18 22:55:36 +00006991 case TARGET_NR_iopl:
6992 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00006993#endif
bellard31e31b82003-02-18 22:55:36 +00006994 case TARGET_NR_vhangup:
6995 ret = get_errno(vhangup());
6996 break;
bellardebc05482003-09-30 21:08:41 +00006997#ifdef TARGET_NR_idle
bellard31e31b82003-02-18 22:55:36 +00006998 case TARGET_NR_idle:
6999 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007000#endif
bellard42ad6ae2005-01-03 22:48:11 +00007001#ifdef TARGET_NR_syscall
7002 case TARGET_NR_syscall:
Peter Maydell5945cfc2011-06-16 17:37:13 +01007003 ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
7004 arg6, arg7, arg8, 0);
7005 break;
bellard42ad6ae2005-01-03 22:48:11 +00007006#endif
bellard31e31b82003-02-18 22:55:36 +00007007 case TARGET_NR_wait4:
7008 {
7009 int status;
blueswir1992f48a2007-10-14 16:27:31 +00007010 abi_long status_ptr = arg2;
bellard31e31b82003-02-18 22:55:36 +00007011 struct rusage rusage, *rusage_ptr;
blueswir1992f48a2007-10-14 16:27:31 +00007012 abi_ulong target_rusage = arg4;
bellard31e31b82003-02-18 22:55:36 +00007013 if (target_rusage)
7014 rusage_ptr = &rusage;
7015 else
7016 rusage_ptr = NULL;
7017 ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
7018 if (!is_error(ret)) {
Alexander Graf53795572011-11-24 00:44:43 +01007019 if (status_ptr && ret) {
pbrook1d9d8b52009-04-16 15:17:02 +00007020 status = host_to_target_waitstatus(status);
bellard2f619692007-11-16 10:46:05 +00007021 if (put_user_s32(status, status_ptr))
7022 goto efault;
bellard31e31b82003-02-18 22:55:36 +00007023 }
bellard2f619692007-11-16 10:46:05 +00007024 if (target_rusage)
7025 host_to_target_rusage(target_rusage, &rusage);
bellard31e31b82003-02-18 22:55:36 +00007026 }
7027 }
7028 break;
thse5febef2007-04-01 18:31:35 +00007029#ifdef TARGET_NR_swapoff
bellard31e31b82003-02-18 22:55:36 +00007030 case TARGET_NR_swapoff:
bellard579a97f2007-11-11 14:26:47 +00007031 if (!(p = lock_user_string(arg1)))
7032 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007033 ret = get_errno(swapoff(p));
7034 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007035 break;
thse5febef2007-04-01 18:31:35 +00007036#endif
bellard31e31b82003-02-18 22:55:36 +00007037 case TARGET_NR_sysinfo:
bellarda5448a72004-06-19 16:59:03 +00007038 {
pbrook53a59602006-03-25 19:31:22 +00007039 struct target_sysinfo *target_value;
bellarda5448a72004-06-19 16:59:03 +00007040 struct sysinfo value;
7041 ret = get_errno(sysinfo(&value));
pbrook53a59602006-03-25 19:31:22 +00007042 if (!is_error(ret) && arg1)
bellarda5448a72004-06-19 16:59:03 +00007043 {
bellard579a97f2007-11-11 14:26:47 +00007044 if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
7045 goto efault;
bellarda5448a72004-06-19 16:59:03 +00007046 __put_user(value.uptime, &target_value->uptime);
7047 __put_user(value.loads[0], &target_value->loads[0]);
7048 __put_user(value.loads[1], &target_value->loads[1]);
7049 __put_user(value.loads[2], &target_value->loads[2]);
7050 __put_user(value.totalram, &target_value->totalram);
7051 __put_user(value.freeram, &target_value->freeram);
7052 __put_user(value.sharedram, &target_value->sharedram);
7053 __put_user(value.bufferram, &target_value->bufferram);
7054 __put_user(value.totalswap, &target_value->totalswap);
7055 __put_user(value.freeswap, &target_value->freeswap);
7056 __put_user(value.procs, &target_value->procs);
7057 __put_user(value.totalhigh, &target_value->totalhigh);
7058 __put_user(value.freehigh, &target_value->freehigh);
7059 __put_user(value.mem_unit, &target_value->mem_unit);
pbrook53a59602006-03-25 19:31:22 +00007060 unlock_user_struct(target_value, arg1, 1);
bellarda5448a72004-06-19 16:59:03 +00007061 }
7062 }
7063 break;
thse5febef2007-04-01 18:31:35 +00007064#ifdef TARGET_NR_ipc
bellard31e31b82003-02-18 22:55:36 +00007065 case TARGET_NR_ipc:
bellard8853f862004-02-22 14:57:26 +00007066 ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
7067 break;
thse5febef2007-04-01 18:31:35 +00007068#endif
aurel32e5289082009-04-18 16:16:12 +00007069#ifdef TARGET_NR_semget
7070 case TARGET_NR_semget:
7071 ret = get_errno(semget(arg1, arg2, arg3));
7072 break;
7073#endif
7074#ifdef TARGET_NR_semop
7075 case TARGET_NR_semop:
Petar Jovanovicc7128c92013-03-21 07:57:36 +00007076 ret = do_semop(arg1, arg2, arg3);
aurel32e5289082009-04-18 16:16:12 +00007077 break;
7078#endif
7079#ifdef TARGET_NR_semctl
7080 case TARGET_NR_semctl:
7081 ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
7082 break;
7083#endif
aurel32eeb438c2008-10-13 21:08:55 +00007084#ifdef TARGET_NR_msgctl
7085 case TARGET_NR_msgctl:
7086 ret = do_msgctl(arg1, arg2, arg3);
7087 break;
7088#endif
7089#ifdef TARGET_NR_msgget
7090 case TARGET_NR_msgget:
7091 ret = get_errno(msgget(arg1, arg2));
7092 break;
7093#endif
7094#ifdef TARGET_NR_msgrcv
7095 case TARGET_NR_msgrcv:
7096 ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
7097 break;
7098#endif
7099#ifdef TARGET_NR_msgsnd
7100 case TARGET_NR_msgsnd:
7101 ret = do_msgsnd(arg1, arg2, arg3, arg4);
7102 break;
7103#endif
Riku Voipio88a8c982009-04-03 10:42:00 +03007104#ifdef TARGET_NR_shmget
7105 case TARGET_NR_shmget:
7106 ret = get_errno(shmget(arg1, arg2, arg3));
7107 break;
7108#endif
7109#ifdef TARGET_NR_shmctl
7110 case TARGET_NR_shmctl:
7111 ret = do_shmctl(arg1, arg2, arg3);
7112 break;
7113#endif
7114#ifdef TARGET_NR_shmat
7115 case TARGET_NR_shmat:
7116 ret = do_shmat(arg1, arg2, arg3);
7117 break;
7118#endif
7119#ifdef TARGET_NR_shmdt
7120 case TARGET_NR_shmdt:
7121 ret = do_shmdt(arg1);
7122 break;
7123#endif
bellard31e31b82003-02-18 22:55:36 +00007124 case TARGET_NR_fsync:
7125 ret = get_errno(fsync(arg1));
7126 break;
bellard31e31b82003-02-18 22:55:36 +00007127 case TARGET_NR_clone:
Peter Maydell4ce62432013-07-16 18:44:57 +01007128 /* Linux manages to have three different orderings for its
7129 * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
7130 * match the kernel's CONFIG_CLONE_* settings.
7131 * Microblaze is further special in that it uses a sixth
7132 * implicit argument to clone for the TLS pointer.
7133 */
7134#if defined(TARGET_MICROBLAZE)
Edgar E. Iglesiasa5b3bdc2012-04-26 14:17:41 +02007135 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
Peter Maydell4ce62432013-07-16 18:44:57 +01007136#elif defined(TARGET_CLONE_BACKWARDS)
7137 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
7138#elif defined(TARGET_CLONE_BACKWARDS2)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02007139 ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007140#else
Peter Maydell4ce62432013-07-16 18:44:57 +01007141 ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
aurel320b6d3ae2008-09-15 07:43:43 +00007142#endif
bellard1b6b0292003-03-22 17:31:38 +00007143 break;
bellardec86b0f2003-04-11 00:15:04 +00007144#ifdef __NR_exit_group
7145 /* new thread calls */
7146 case TARGET_NR_exit_group:
Juan Quintela9788c9c2009-07-27 16:13:02 +02007147#ifdef TARGET_GPROF
aurel326d946cd2008-11-06 16:15:18 +00007148 _mcleanup();
7149#endif
bellarde9009672005-04-26 20:42:36 +00007150 gdb_exit(cpu_env, arg1);
bellardec86b0f2003-04-11 00:15:04 +00007151 ret = get_errno(exit_group(arg1));
7152 break;
7153#endif
bellard31e31b82003-02-18 22:55:36 +00007154 case TARGET_NR_setdomainname:
bellard579a97f2007-11-11 14:26:47 +00007155 if (!(p = lock_user_string(arg1)))
7156 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007157 ret = get_errno(setdomainname(p, arg2));
7158 unlock_user(p, arg1, 0);
bellard31e31b82003-02-18 22:55:36 +00007159 break;
7160 case TARGET_NR_uname:
7161 /* no need to transcode because we use the linux syscall */
bellard29e619b2004-09-13 21:41:04 +00007162 {
7163 struct new_utsname * buf;
ths3b46e622007-09-17 08:09:54 +00007164
bellard579a97f2007-11-11 14:26:47 +00007165 if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
7166 goto efault;
bellard29e619b2004-09-13 21:41:04 +00007167 ret = get_errno(sys_uname(buf));
7168 if (!is_error(ret)) {
7169 /* Overrite the native machine name with whatever is being
7170 emulated. */
Loïc Minierda790302009-12-29 22:06:13 +01007171 strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
pbrookc5937222006-05-14 11:30:38 +00007172 /* Allow the user to override the reported release. */
7173 if (qemu_uname_release && *qemu_uname_release)
7174 strcpy (buf->release, qemu_uname_release);
bellard29e619b2004-09-13 21:41:04 +00007175 }
pbrook53a59602006-03-25 19:31:22 +00007176 unlock_user_struct(buf, arg1, 1);
bellard29e619b2004-09-13 21:41:04 +00007177 }
bellard31e31b82003-02-18 22:55:36 +00007178 break;
bellard6dbad632003-03-16 18:05:05 +00007179#ifdef TARGET_I386
bellard31e31b82003-02-18 22:55:36 +00007180 case TARGET_NR_modify_ldt:
bellard03acab62007-11-11 14:57:14 +00007181 ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
bellard5cd43932003-03-29 16:54:36 +00007182 break;
j_mayer84409dd2007-04-06 08:56:50 +00007183#if !defined(TARGET_X86_64)
bellard5cd43932003-03-29 16:54:36 +00007184 case TARGET_NR_vm86old:
7185 goto unimplemented;
7186 case TARGET_NR_vm86:
pbrook53a59602006-03-25 19:31:22 +00007187 ret = do_vm86(cpu_env, arg1, arg2);
bellard6dbad632003-03-16 18:05:05 +00007188 break;
7189#endif
j_mayer84409dd2007-04-06 08:56:50 +00007190#endif
bellard31e31b82003-02-18 22:55:36 +00007191 case TARGET_NR_adjtimex:
7192 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007193#ifdef TARGET_NR_create_module
bellard31e31b82003-02-18 22:55:36 +00007194 case TARGET_NR_create_module:
thse5febef2007-04-01 18:31:35 +00007195#endif
bellard31e31b82003-02-18 22:55:36 +00007196 case TARGET_NR_init_module:
7197 case TARGET_NR_delete_module:
thse5febef2007-04-01 18:31:35 +00007198#ifdef TARGET_NR_get_kernel_syms
bellard31e31b82003-02-18 22:55:36 +00007199 case TARGET_NR_get_kernel_syms:
thse5febef2007-04-01 18:31:35 +00007200#endif
bellard31e31b82003-02-18 22:55:36 +00007201 goto unimplemented;
7202 case TARGET_NR_quotactl:
7203 goto unimplemented;
7204 case TARGET_NR_getpgid:
7205 ret = get_errno(getpgid(arg1));
7206 break;
7207 case TARGET_NR_fchdir:
7208 ret = get_errno(fchdir(arg1));
7209 break;
j_mayer84409dd2007-04-06 08:56:50 +00007210#ifdef TARGET_NR_bdflush /* not on x86_64 */
bellard31e31b82003-02-18 22:55:36 +00007211 case TARGET_NR_bdflush:
7212 goto unimplemented;
j_mayer84409dd2007-04-06 08:56:50 +00007213#endif
thse5febef2007-04-01 18:31:35 +00007214#ifdef TARGET_NR_sysfs
bellard31e31b82003-02-18 22:55:36 +00007215 case TARGET_NR_sysfs:
7216 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007217#endif
bellard31e31b82003-02-18 22:55:36 +00007218 case TARGET_NR_personality:
bellard1b6b0292003-03-22 17:31:38 +00007219 ret = get_errno(personality(arg1));
bellard31e31b82003-02-18 22:55:36 +00007220 break;
thse5febef2007-04-01 18:31:35 +00007221#ifdef TARGET_NR_afs_syscall
bellard31e31b82003-02-18 22:55:36 +00007222 case TARGET_NR_afs_syscall:
7223 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007224#endif
j_mayer7a3148a2007-04-05 07:13:51 +00007225#ifdef TARGET_NR__llseek /* Not on alpha */
bellard31e31b82003-02-18 22:55:36 +00007226 case TARGET_NR__llseek:
7227 {
7228 int64_t res;
Peter Maydell0c1592d2011-02-22 13:02:26 +00007229#if !defined(__NR_llseek)
7230 res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
7231 if (res == -1) {
7232 ret = get_errno(res);
7233 } else {
7234 ret = 0;
7235 }
7236#else
bellard31e31b82003-02-18 22:55:36 +00007237 ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
bellard4f2ac232004-04-26 19:44:02 +00007238#endif
Peter Maydell0c1592d2011-02-22 13:02:26 +00007239 if ((ret == 0) && put_user_s64(res, arg4)) {
7240 goto efault;
7241 }
bellard31e31b82003-02-18 22:55:36 +00007242 }
7243 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007244#endif
bellard31e31b82003-02-18 22:55:36 +00007245 case TARGET_NR_getdents:
Peter Maydell3307e232013-06-12 16:20:21 +01007246#ifdef __NR_getdents
Ulrich Hechtd83c8732009-07-24 19:10:28 +02007247#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
bellard4add45b2003-06-05 01:52:59 +00007248 {
pbrook53a59602006-03-25 19:31:22 +00007249 struct target_dirent *target_dirp;
aurel326556a832008-10-13 21:08:17 +00007250 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007251 abi_long count = arg3;
bellard4add45b2003-06-05 01:52:59 +00007252
7253 dirp = malloc(count);
ths0da46a62007-10-20 20:23:07 +00007254 if (!dirp) {
bellard579a97f2007-11-11 14:26:47 +00007255 ret = -TARGET_ENOMEM;
ths0da46a62007-10-20 20:23:07 +00007256 goto fail;
7257 }
ths3b46e622007-09-17 08:09:54 +00007258
bellard4add45b2003-06-05 01:52:59 +00007259 ret = get_errno(sys_getdents(arg1, dirp, count));
7260 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007261 struct linux_dirent *de;
bellard4add45b2003-06-05 01:52:59 +00007262 struct target_dirent *tde;
7263 int len = ret;
7264 int reclen, treclen;
7265 int count1, tnamelen;
7266
7267 count1 = 0;
7268 de = dirp;
bellard579a97f2007-11-11 14:26:47 +00007269 if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7270 goto efault;
bellard4add45b2003-06-05 01:52:59 +00007271 tde = target_dirp;
7272 while (len > 0) {
7273 reclen = de->d_reclen;
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007274 tnamelen = reclen - offsetof(struct linux_dirent, d_name);
7275 assert(tnamelen >= 0);
7276 treclen = tnamelen + offsetof(struct target_dirent, d_name);
7277 assert(count1 + treclen <= count);
bellard4add45b2003-06-05 01:52:59 +00007278 tde->d_reclen = tswap16(treclen);
Matthias Brauncbb21ee2011-08-12 19:57:41 +02007279 tde->d_ino = tswapal(de->d_ino);
7280 tde->d_off = tswapal(de->d_off);
Dmitry V. Levin333858b2012-08-21 02:13:12 +04007281 memcpy(tde->d_name, de->d_name, tnamelen);
aurel326556a832008-10-13 21:08:17 +00007282 de = (struct linux_dirent *)((char *)de + reclen);
bellard4add45b2003-06-05 01:52:59 +00007283 len -= reclen;
j_mayer1c5bf3b2007-04-14 12:17:59 +00007284 tde = (struct target_dirent *)((char *)tde + treclen);
bellard4add45b2003-06-05 01:52:59 +00007285 count1 += treclen;
7286 }
7287 ret = count1;
bellard579a97f2007-11-11 14:26:47 +00007288 unlock_user(target_dirp, arg2, ret);
bellard4add45b2003-06-05 01:52:59 +00007289 }
7290 free(dirp);
7291 }
7292#else
bellard31e31b82003-02-18 22:55:36 +00007293 {
aurel326556a832008-10-13 21:08:17 +00007294 struct linux_dirent *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007295 abi_long count = arg3;
bellarddab2ed92003-03-22 15:23:14 +00007296
bellard579a97f2007-11-11 14:26:47 +00007297 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7298 goto efault;
bellard72f03902003-02-18 23:33:18 +00007299 ret = get_errno(sys_getdents(arg1, dirp, count));
bellard31e31b82003-02-18 22:55:36 +00007300 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007301 struct linux_dirent *de;
bellard31e31b82003-02-18 22:55:36 +00007302 int len = ret;
7303 int reclen;
7304 de = dirp;
7305 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007306 reclen = de->d_reclen;
bellard31e31b82003-02-18 22:55:36 +00007307 if (reclen > len)
7308 break;
bellard8083a3e2003-03-24 23:12:16 +00007309 de->d_reclen = tswap16(reclen);
bellard31e31b82003-02-18 22:55:36 +00007310 tswapls(&de->d_ino);
7311 tswapls(&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007312 de = (struct linux_dirent *)((char *)de + reclen);
bellard31e31b82003-02-18 22:55:36 +00007313 len -= reclen;
7314 }
7315 }
pbrook53a59602006-03-25 19:31:22 +00007316 unlock_user(dirp, arg2, ret);
bellard31e31b82003-02-18 22:55:36 +00007317 }
bellard4add45b2003-06-05 01:52:59 +00007318#endif
Peter Maydell3307e232013-06-12 16:20:21 +01007319#else
7320 /* Implement getdents in terms of getdents64 */
7321 {
7322 struct linux_dirent64 *dirp;
7323 abi_long count = arg3;
7324
7325 dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
7326 if (!dirp) {
7327 goto efault;
7328 }
7329 ret = get_errno(sys_getdents64(arg1, dirp, count));
7330 if (!is_error(ret)) {
7331 /* Convert the dirent64 structs to target dirent. We do this
7332 * in-place, since we can guarantee that a target_dirent is no
7333 * larger than a dirent64; however this means we have to be
7334 * careful to read everything before writing in the new format.
7335 */
7336 struct linux_dirent64 *de;
7337 struct target_dirent *tde;
7338 int len = ret;
7339 int tlen = 0;
7340
7341 de = dirp;
7342 tde = (struct target_dirent *)dirp;
7343 while (len > 0) {
7344 int namelen, treclen;
7345 int reclen = de->d_reclen;
7346 uint64_t ino = de->d_ino;
7347 int64_t off = de->d_off;
7348 uint8_t type = de->d_type;
7349
7350 namelen = strlen(de->d_name);
7351 treclen = offsetof(struct target_dirent, d_name)
7352 + namelen + 2;
7353 treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
7354
7355 memmove(tde->d_name, de->d_name, namelen + 1);
7356 tde->d_ino = tswapal(ino);
7357 tde->d_off = tswapal(off);
7358 tde->d_reclen = tswap16(treclen);
7359 /* The target_dirent type is in what was formerly a padding
7360 * byte at the end of the structure:
7361 */
7362 *(((char *)tde) + treclen - 1) = type;
7363
7364 de = (struct linux_dirent64 *)((char *)de + reclen);
7365 tde = (struct target_dirent *)((char *)tde + treclen);
7366 len -= reclen;
7367 tlen += treclen;
7368 }
7369 ret = tlen;
7370 }
7371 unlock_user(dirp, arg2, ret);
7372 }
7373#endif
bellard31e31b82003-02-18 22:55:36 +00007374 break;
ths3ae43202007-09-16 21:39:48 +00007375#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
bellarddab2ed92003-03-22 15:23:14 +00007376 case TARGET_NR_getdents64:
7377 {
aurel326556a832008-10-13 21:08:17 +00007378 struct linux_dirent64 *dirp;
blueswir1992f48a2007-10-14 16:27:31 +00007379 abi_long count = arg3;
bellard579a97f2007-11-11 14:26:47 +00007380 if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
7381 goto efault;
bellarddab2ed92003-03-22 15:23:14 +00007382 ret = get_errno(sys_getdents64(arg1, dirp, count));
7383 if (!is_error(ret)) {
aurel326556a832008-10-13 21:08:17 +00007384 struct linux_dirent64 *de;
bellarddab2ed92003-03-22 15:23:14 +00007385 int len = ret;
7386 int reclen;
7387 de = dirp;
7388 while (len > 0) {
bellard8083a3e2003-03-24 23:12:16 +00007389 reclen = de->d_reclen;
bellarddab2ed92003-03-22 15:23:14 +00007390 if (reclen > len)
7391 break;
bellard8083a3e2003-03-24 23:12:16 +00007392 de->d_reclen = tswap16(reclen);
bellard8582a532007-11-11 23:11:36 +00007393 tswap64s((uint64_t *)&de->d_ino);
7394 tswap64s((uint64_t *)&de->d_off);
aurel326556a832008-10-13 21:08:17 +00007395 de = (struct linux_dirent64 *)((char *)de + reclen);
bellarddab2ed92003-03-22 15:23:14 +00007396 len -= reclen;
7397 }
7398 }
pbrook53a59602006-03-25 19:31:22 +00007399 unlock_user(dirp, arg2, ret);
bellarddab2ed92003-03-22 15:23:14 +00007400 }
7401 break;
bellarda541f292004-04-12 20:39:29 +00007402#endif /* TARGET_NR_getdents64 */
Laurent Vivier9468a5d2013-01-10 22:30:50 +01007403#if defined(TARGET_NR__newselect)
bellard31e31b82003-02-18 22:55:36 +00007404 case TARGET_NR__newselect:
pbrook53a59602006-03-25 19:31:22 +00007405 ret = do_select(arg1, arg2, arg3, arg4, arg5);
bellard31e31b82003-02-18 22:55:36 +00007406 break;
thse5febef2007-04-01 18:31:35 +00007407#endif
Mike Frysingerd8035d42011-02-07 01:05:51 -05007408#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
7409# ifdef TARGET_NR_poll
bellard9de5e442003-03-23 16:49:39 +00007410 case TARGET_NR_poll:
Mike Frysingerd8035d42011-02-07 01:05:51 -05007411# endif
7412# ifdef TARGET_NR_ppoll
7413 case TARGET_NR_ppoll:
7414# endif
bellard9de5e442003-03-23 16:49:39 +00007415 {
pbrook53a59602006-03-25 19:31:22 +00007416 struct target_pollfd *target_pfd;
bellard9de5e442003-03-23 16:49:39 +00007417 unsigned int nfds = arg2;
7418 int timeout = arg3;
7419 struct pollfd *pfd;
bellard7854b052003-03-29 17:22:23 +00007420 unsigned int i;
bellard9de5e442003-03-23 16:49:39 +00007421
bellard579a97f2007-11-11 14:26:47 +00007422 target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
7423 if (!target_pfd)
7424 goto efault;
Mike Frysingerd8035d42011-02-07 01:05:51 -05007425
bellard9de5e442003-03-23 16:49:39 +00007426 pfd = alloca(sizeof(struct pollfd) * nfds);
7427 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007428 pfd[i].fd = tswap32(target_pfd[i].fd);
7429 pfd[i].events = tswap16(target_pfd[i].events);
bellard9de5e442003-03-23 16:49:39 +00007430 }
Mike Frysingerd8035d42011-02-07 01:05:51 -05007431
7432# ifdef TARGET_NR_ppoll
7433 if (num == TARGET_NR_ppoll) {
7434 struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
7435 target_sigset_t *target_set;
7436 sigset_t _set, *set = &_set;
7437
7438 if (arg3) {
7439 if (target_to_host_timespec(timeout_ts, arg3)) {
7440 unlock_user(target_pfd, arg1, 0);
7441 goto efault;
7442 }
7443 } else {
7444 timeout_ts = NULL;
7445 }
7446
7447 if (arg4) {
7448 target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
7449 if (!target_set) {
7450 unlock_user(target_pfd, arg1, 0);
7451 goto efault;
7452 }
7453 target_to_host_sigset(set, target_set);
7454 } else {
7455 set = NULL;
7456 }
7457
7458 ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
7459
7460 if (!is_error(ret) && arg3) {
7461 host_to_target_timespec(arg3, timeout_ts);
7462 }
7463 if (arg4) {
7464 unlock_user(target_set, arg4, 0);
7465 }
7466 } else
7467# endif
7468 ret = get_errno(poll(pfd, nfds, timeout));
7469
bellard9de5e442003-03-23 16:49:39 +00007470 if (!is_error(ret)) {
7471 for(i = 0; i < nfds; i++) {
bellard5cd43932003-03-29 16:54:36 +00007472 target_pfd[i].revents = tswap16(pfd[i].revents);
bellard9de5e442003-03-23 16:49:39 +00007473 }
7474 }
Peter Maydell30cb4cd2011-02-25 10:27:40 +00007475 unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
bellard9de5e442003-03-23 16:49:39 +00007476 }
7477 break;
thse5febef2007-04-01 18:31:35 +00007478#endif
bellard31e31b82003-02-18 22:55:36 +00007479 case TARGET_NR_flock:
bellard9de5e442003-03-23 16:49:39 +00007480 /* NOTE: the flock constant seems to be the same for every
7481 Linux platform */
7482 ret = get_errno(flock(arg1, arg2));
bellard31e31b82003-02-18 22:55:36 +00007483 break;
7484 case TARGET_NR_readv:
7485 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007486 struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
7487 if (vec != NULL) {
7488 ret = get_errno(readv(arg1, vec, arg3));
7489 unlock_iovec(vec, arg2, arg3, 1);
7490 } else {
7491 ret = -host_to_target_errno(errno);
7492 }
bellard31e31b82003-02-18 22:55:36 +00007493 }
7494 break;
7495 case TARGET_NR_writev:
7496 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07007497 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
7498 if (vec != NULL) {
7499 ret = get_errno(writev(arg1, vec, arg3));
7500 unlock_iovec(vec, arg2, arg3, 0);
7501 } else {
7502 ret = -host_to_target_errno(errno);
7503 }
bellard31e31b82003-02-18 22:55:36 +00007504 }
7505 break;
7506 case TARGET_NR_getsid:
7507 ret = get_errno(getsid(arg1));
7508 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007509#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
bellard31e31b82003-02-18 22:55:36 +00007510 case TARGET_NR_fdatasync:
bellard5cd43932003-03-29 16:54:36 +00007511 ret = get_errno(fdatasync(arg1));
7512 break;
j_mayer7a3148a2007-04-05 07:13:51 +00007513#endif
bellard31e31b82003-02-18 22:55:36 +00007514 case TARGET_NR__sysctl:
ths0da46a62007-10-20 20:23:07 +00007515 /* We don't implement this, but ENOTDIR is always a safe
bellard29e619b2004-09-13 21:41:04 +00007516 return value. */
ths0da46a62007-10-20 20:23:07 +00007517 ret = -TARGET_ENOTDIR;
7518 break;
Mike Frysinger737de1d2011-02-07 01:05:55 -05007519 case TARGET_NR_sched_getaffinity:
7520 {
7521 unsigned int mask_size;
7522 unsigned long *mask;
7523
7524 /*
7525 * sched_getaffinity needs multiples of ulong, so need to take
7526 * care of mismatches between target ulong and host ulong sizes.
7527 */
7528 if (arg2 & (sizeof(abi_ulong) - 1)) {
7529 ret = -TARGET_EINVAL;
7530 break;
7531 }
7532 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7533
7534 mask = alloca(mask_size);
7535 ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
7536
7537 if (!is_error(ret)) {
Mike McCormackcd18f052011-04-18 14:43:36 +09007538 if (copy_to_user(arg3, mask, ret)) {
Mike Frysinger737de1d2011-02-07 01:05:55 -05007539 goto efault;
7540 }
Mike Frysinger737de1d2011-02-07 01:05:55 -05007541 }
7542 }
7543 break;
7544 case TARGET_NR_sched_setaffinity:
7545 {
7546 unsigned int mask_size;
7547 unsigned long *mask;
7548
7549 /*
7550 * sched_setaffinity needs multiples of ulong, so need to take
7551 * care of mismatches between target ulong and host ulong sizes.
7552 */
7553 if (arg2 & (sizeof(abi_ulong) - 1)) {
7554 ret = -TARGET_EINVAL;
7555 break;
7556 }
7557 mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
7558
7559 mask = alloca(mask_size);
7560 if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
7561 goto efault;
7562 }
7563 memcpy(mask, p, arg2);
7564 unlock_user_struct(p, arg2, 0);
7565
7566 ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
7567 }
7568 break;
bellard31e31b82003-02-18 22:55:36 +00007569 case TARGET_NR_sched_setparam:
bellard5cd43932003-03-29 16:54:36 +00007570 {
pbrook53a59602006-03-25 19:31:22 +00007571 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007572 struct sched_param schp;
pbrook53a59602006-03-25 19:31:22 +00007573
bellard579a97f2007-11-11 14:26:47 +00007574 if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
7575 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007576 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007577 unlock_user_struct(target_schp, arg2, 0);
bellard5cd43932003-03-29 16:54:36 +00007578 ret = get_errno(sched_setparam(arg1, &schp));
7579 }
7580 break;
bellard31e31b82003-02-18 22:55:36 +00007581 case TARGET_NR_sched_getparam:
bellard5cd43932003-03-29 16:54:36 +00007582 {
pbrook53a59602006-03-25 19:31:22 +00007583 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007584 struct sched_param schp;
7585 ret = get_errno(sched_getparam(arg1, &schp));
7586 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00007587 if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
7588 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007589 target_schp->sched_priority = tswap32(schp.sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007590 unlock_user_struct(target_schp, arg2, 1);
bellard5cd43932003-03-29 16:54:36 +00007591 }
7592 }
7593 break;
bellard31e31b82003-02-18 22:55:36 +00007594 case TARGET_NR_sched_setscheduler:
bellard5cd43932003-03-29 16:54:36 +00007595 {
pbrook53a59602006-03-25 19:31:22 +00007596 struct sched_param *target_schp;
bellard5cd43932003-03-29 16:54:36 +00007597 struct sched_param schp;
bellard579a97f2007-11-11 14:26:47 +00007598 if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
7599 goto efault;
bellard5cd43932003-03-29 16:54:36 +00007600 schp.sched_priority = tswap32(target_schp->sched_priority);
pbrook53a59602006-03-25 19:31:22 +00007601 unlock_user_struct(target_schp, arg3, 0);
bellard5cd43932003-03-29 16:54:36 +00007602 ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
7603 }
7604 break;
bellard31e31b82003-02-18 22:55:36 +00007605 case TARGET_NR_sched_getscheduler:
bellard5cd43932003-03-29 16:54:36 +00007606 ret = get_errno(sched_getscheduler(arg1));
7607 break;
bellard31e31b82003-02-18 22:55:36 +00007608 case TARGET_NR_sched_yield:
7609 ret = get_errno(sched_yield());
7610 break;
7611 case TARGET_NR_sched_get_priority_max:
bellard5cd43932003-03-29 16:54:36 +00007612 ret = get_errno(sched_get_priority_max(arg1));
7613 break;
bellard31e31b82003-02-18 22:55:36 +00007614 case TARGET_NR_sched_get_priority_min:
bellard5cd43932003-03-29 16:54:36 +00007615 ret = get_errno(sched_get_priority_min(arg1));
7616 break;
bellard31e31b82003-02-18 22:55:36 +00007617 case TARGET_NR_sched_rr_get_interval:
bellard5cd43932003-03-29 16:54:36 +00007618 {
bellard5cd43932003-03-29 16:54:36 +00007619 struct timespec ts;
7620 ret = get_errno(sched_rr_get_interval(arg1, &ts));
7621 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007622 host_to_target_timespec(arg2, &ts);
bellard5cd43932003-03-29 16:54:36 +00007623 }
7624 }
7625 break;
bellard31e31b82003-02-18 22:55:36 +00007626 case TARGET_NR_nanosleep:
bellard1b6b0292003-03-22 17:31:38 +00007627 {
bellard1b6b0292003-03-22 17:31:38 +00007628 struct timespec req, rem;
pbrook53a59602006-03-25 19:31:22 +00007629 target_to_host_timespec(&req, arg1);
bellard1b6b0292003-03-22 17:31:38 +00007630 ret = get_errno(nanosleep(&req, &rem));
pbrook53a59602006-03-25 19:31:22 +00007631 if (is_error(ret) && arg2) {
7632 host_to_target_timespec(arg2, &rem);
bellard1b6b0292003-03-22 17:31:38 +00007633 }
7634 }
7635 break;
thse5febef2007-04-01 18:31:35 +00007636#ifdef TARGET_NR_query_module
bellard31e31b82003-02-18 22:55:36 +00007637 case TARGET_NR_query_module:
bellard5cd43932003-03-29 16:54:36 +00007638 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007639#endif
7640#ifdef TARGET_NR_nfsservctl
bellard31e31b82003-02-18 22:55:36 +00007641 case TARGET_NR_nfsservctl:
bellard5cd43932003-03-29 16:54:36 +00007642 goto unimplemented;
thse5febef2007-04-01 18:31:35 +00007643#endif
bellard31e31b82003-02-18 22:55:36 +00007644 case TARGET_NR_prctl:
Peter Maydell1e6722f2012-02-03 14:48:03 +00007645 switch (arg1) {
7646 case PR_GET_PDEATHSIG:
7647 {
7648 int deathsig;
7649 ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
7650 if (!is_error(ret) && arg2
7651 && put_user_ual(deathsig, arg2)) {
7652 goto efault;
thse5574482007-02-11 20:03:13 +00007653 }
Peter Maydell1e6722f2012-02-03 14:48:03 +00007654 break;
7655 }
Peter Maydelldb9526b2012-02-03 14:48:03 +00007656#ifdef PR_GET_NAME
7657 case PR_GET_NAME:
7658 {
7659 void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
7660 if (!name) {
7661 goto efault;
7662 }
7663 ret = get_errno(prctl(arg1, (unsigned long)name,
7664 arg3, arg4, arg5));
7665 unlock_user(name, arg2, 16);
7666 break;
7667 }
7668 case PR_SET_NAME:
7669 {
7670 void *name = lock_user(VERIFY_READ, arg2, 16, 1);
7671 if (!name) {
7672 goto efault;
7673 }
7674 ret = get_errno(prctl(arg1, (unsigned long)name,
7675 arg3, arg4, arg5));
7676 unlock_user(name, arg2, 0);
7677 break;
7678 }
7679#endif
Peter Maydell1e6722f2012-02-03 14:48:03 +00007680 default:
7681 /* Most prctl options have no pointer arguments */
7682 ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
7683 break;
7684 }
ths39b9aae2007-02-11 18:36:44 +00007685 break;
bellardd2fd1af2007-11-14 18:08:56 +00007686#ifdef TARGET_NR_arch_prctl
7687 case TARGET_NR_arch_prctl:
7688#if defined(TARGET_I386) && !defined(TARGET_ABI32)
7689 ret = do_arch_prctl(cpu_env, arg1, arg2);
7690 break;
7691#else
7692 goto unimplemented;
7693#endif
7694#endif
aurel32f2c7ba12008-03-28 22:32:06 +00007695#ifdef TARGET_NR_pread64
7696 case TARGET_NR_pread64:
Alexander Grafae017a52012-09-29 15:32:39 +00007697 if (regpairs_aligned(cpu_env)) {
7698 arg4 = arg5;
7699 arg5 = arg6;
7700 }
aurel32f2c7ba12008-03-28 22:32:06 +00007701 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
7702 goto efault;
7703 ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
7704 unlock_user(p, arg2, ret);
7705 break;
7706 case TARGET_NR_pwrite64:
Alexander Grafae017a52012-09-29 15:32:39 +00007707 if (regpairs_aligned(cpu_env)) {
7708 arg4 = arg5;
7709 arg5 = arg6;
7710 }
aurel32f2c7ba12008-03-28 22:32:06 +00007711 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
7712 goto efault;
7713 ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
7714 unlock_user(p, arg2, 0);
7715 break;
7716#endif
bellard31e31b82003-02-18 22:55:36 +00007717 case TARGET_NR_getcwd:
bellard579a97f2007-11-11 14:26:47 +00007718 if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
7719 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007720 ret = get_errno(sys_getcwd1(p, arg2));
7721 unlock_user(p, arg1, ret);
bellard31e31b82003-02-18 22:55:36 +00007722 break;
7723 case TARGET_NR_capget:
7724 case TARGET_NR_capset:
Peter Maydelle0eb2102014-03-17 12:15:35 +00007725 {
7726 struct target_user_cap_header *target_header;
7727 struct target_user_cap_data *target_data = NULL;
7728 struct __user_cap_header_struct header;
7729 struct __user_cap_data_struct data[2];
7730 struct __user_cap_data_struct *dataptr = NULL;
7731 int i, target_datalen;
7732 int data_items = 1;
7733
7734 if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
7735 goto efault;
7736 }
7737 header.version = tswap32(target_header->version);
7738 header.pid = tswap32(target_header->pid);
7739
Peter Maydellec864872014-03-19 16:07:30 +00007740 if (header.version != _LINUX_CAPABILITY_VERSION) {
Peter Maydelle0eb2102014-03-17 12:15:35 +00007741 /* Version 2 and up takes pointer to two user_data structs */
7742 data_items = 2;
7743 }
7744
7745 target_datalen = sizeof(*target_data) * data_items;
7746
7747 if (arg2) {
7748 if (num == TARGET_NR_capget) {
7749 target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
7750 } else {
7751 target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
7752 }
7753 if (!target_data) {
7754 unlock_user_struct(target_header, arg1, 0);
7755 goto efault;
7756 }
7757
7758 if (num == TARGET_NR_capset) {
7759 for (i = 0; i < data_items; i++) {
7760 data[i].effective = tswap32(target_data[i].effective);
7761 data[i].permitted = tswap32(target_data[i].permitted);
7762 data[i].inheritable = tswap32(target_data[i].inheritable);
7763 }
7764 }
7765
7766 dataptr = data;
7767 }
7768
7769 if (num == TARGET_NR_capget) {
7770 ret = get_errno(capget(&header, dataptr));
7771 } else {
7772 ret = get_errno(capset(&header, dataptr));
7773 }
7774
7775 /* The kernel always updates version for both capget and capset */
7776 target_header->version = tswap32(header.version);
7777 unlock_user_struct(target_header, arg1, 1);
7778
7779 if (arg2) {
7780 if (num == TARGET_NR_capget) {
7781 for (i = 0; i < data_items; i++) {
7782 target_data[i].effective = tswap32(data[i].effective);
7783 target_data[i].permitted = tswap32(data[i].permitted);
7784 target_data[i].inheritable = tswap32(data[i].inheritable);
7785 }
7786 unlock_user(target_data, arg2, target_datalen);
7787 } else {
7788 unlock_user(target_data, arg2, 0);
7789 }
7790 }
7791 break;
7792 }
bellard31e31b82003-02-18 22:55:36 +00007793 case TARGET_NR_sigaltstack:
ths198a74d2007-09-27 16:44:32 +00007794#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
Laurent Vivierc761c152009-08-03 16:12:19 +02007795 defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
Jia Liud9627832012-07-20 15:50:52 +08007796 defined(TARGET_M68K) || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
Andreas Färber9349b4f2012-03-14 01:38:32 +01007797 ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
thsa04e1342007-09-27 13:57:58 +00007798 break;
7799#else
bellard5cd43932003-03-29 16:54:36 +00007800 goto unimplemented;
thsa04e1342007-09-27 13:57:58 +00007801#endif
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007802
7803#ifdef CONFIG_SENDFILE
bellard31e31b82003-02-18 22:55:36 +00007804 case TARGET_NR_sendfile:
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007805 {
7806 off_t *offp = NULL;
7807 off_t off;
7808 if (arg3) {
7809 ret = get_user_sal(off, arg3);
7810 if (is_error(ret)) {
7811 break;
7812 }
7813 offp = &off;
7814 }
7815 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7816 if (!is_error(ret) && arg3) {
7817 abi_long ret2 = put_user_sal(off, arg3);
7818 if (is_error(ret2)) {
7819 ret = ret2;
7820 }
7821 }
7822 break;
7823 }
7824#ifdef TARGET_NR_sendfile64
7825 case TARGET_NR_sendfile64:
7826 {
7827 off_t *offp = NULL;
7828 off_t off;
7829 if (arg3) {
7830 ret = get_user_s64(off, arg3);
7831 if (is_error(ret)) {
7832 break;
7833 }
7834 offp = &off;
7835 }
7836 ret = get_errno(sendfile(arg1, arg2, offp, arg4));
7837 if (!is_error(ret) && arg3) {
7838 abi_long ret2 = put_user_s64(off, arg3);
7839 if (is_error(ret2)) {
7840 ret = ret2;
7841 }
7842 }
7843 break;
7844 }
7845#endif
7846#else
7847 case TARGET_NR_sendfile:
Peter Maydell7edd2cf2013-04-21 13:30:03 +01007848#ifdef TARGET_NR_sendfile64
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007849 case TARGET_NR_sendfile64:
7850#endif
bellard5cd43932003-03-29 16:54:36 +00007851 goto unimplemented;
Peter Maydella8fd1ab2013-02-08 07:31:55 +00007852#endif
7853
bellardebc05482003-09-30 21:08:41 +00007854#ifdef TARGET_NR_getpmsg
bellard31e31b82003-02-18 22:55:36 +00007855 case TARGET_NR_getpmsg:
bellard5cd43932003-03-29 16:54:36 +00007856 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007857#endif
7858#ifdef TARGET_NR_putpmsg
bellard31e31b82003-02-18 22:55:36 +00007859 case TARGET_NR_putpmsg:
bellard5cd43932003-03-29 16:54:36 +00007860 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00007861#endif
bellard048f6b42005-11-26 18:47:20 +00007862#ifdef TARGET_NR_vfork
bellard31e31b82003-02-18 22:55:36 +00007863 case TARGET_NR_vfork:
pbrookd865bab2008-06-07 22:12:17 +00007864 ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
7865 0, 0, 0, 0));
bellard31e31b82003-02-18 22:55:36 +00007866 break;
bellard048f6b42005-11-26 18:47:20 +00007867#endif
bellardebc05482003-09-30 21:08:41 +00007868#ifdef TARGET_NR_ugetrlimit
bellard31e31b82003-02-18 22:55:36 +00007869 case TARGET_NR_ugetrlimit:
bellard728584b2003-04-29 20:43:36 +00007870 {
7871 struct rlimit rlim;
Wesley W. Terpstrae22b7012011-07-12 14:42:00 +03007872 int resource = target_to_host_resource(arg1);
7873 ret = get_errno(getrlimit(resource, &rlim));
bellard728584b2003-04-29 20:43:36 +00007874 if (!is_error(ret)) {
pbrook53a59602006-03-25 19:31:22 +00007875 struct target_rlimit *target_rlim;
bellard579a97f2007-11-11 14:26:47 +00007876 if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
7877 goto efault;
takasi-y@ops.dti.ne.jp81bbe902010-04-12 04:07:35 +09007878 target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
7879 target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
pbrook53a59602006-03-25 19:31:22 +00007880 unlock_user_struct(target_rlim, arg2, 1);
bellard728584b2003-04-29 20:43:36 +00007881 }
7882 break;
7883 }
bellardebc05482003-09-30 21:08:41 +00007884#endif
bellarda315a142005-01-30 22:59:18 +00007885#ifdef TARGET_NR_truncate64
bellard31e31b82003-02-18 22:55:36 +00007886 case TARGET_NR_truncate64:
bellard579a97f2007-11-11 14:26:47 +00007887 if (!(p = lock_user_string(arg1)))
7888 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007889 ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
7890 unlock_user(p, arg1, 0);
bellard667f38b2005-07-23 14:46:27 +00007891 break;
bellarda315a142005-01-30 22:59:18 +00007892#endif
7893#ifdef TARGET_NR_ftruncate64
bellard31e31b82003-02-18 22:55:36 +00007894 case TARGET_NR_ftruncate64:
pbrookce4defa2006-02-09 16:49:55 +00007895 ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
bellard667f38b2005-07-23 14:46:27 +00007896 break;
bellarda315a142005-01-30 22:59:18 +00007897#endif
7898#ifdef TARGET_NR_stat64
bellard31e31b82003-02-18 22:55:36 +00007899 case TARGET_NR_stat64:
bellard579a97f2007-11-11 14:26:47 +00007900 if (!(p = lock_user_string(arg1)))
7901 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007902 ret = get_errno(stat(path(p), &st));
7903 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007904 if (!is_error(ret))
7905 ret = host_to_target_stat64(cpu_env, arg2, &st);
7906 break;
bellarda315a142005-01-30 22:59:18 +00007907#endif
7908#ifdef TARGET_NR_lstat64
bellard31e31b82003-02-18 22:55:36 +00007909 case TARGET_NR_lstat64:
bellard579a97f2007-11-11 14:26:47 +00007910 if (!(p = lock_user_string(arg1)))
7911 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007912 ret = get_errno(lstat(path(p), &st));
7913 unlock_user(p, arg1, 0);
balrog6a24a772008-09-20 02:23:36 +00007914 if (!is_error(ret))
7915 ret = host_to_target_stat64(cpu_env, arg2, &st);
7916 break;
bellarda315a142005-01-30 22:59:18 +00007917#endif
7918#ifdef TARGET_NR_fstat64
bellard31e31b82003-02-18 22:55:36 +00007919 case TARGET_NR_fstat64:
balrog6a24a772008-09-20 02:23:36 +00007920 ret = get_errno(fstat(arg1, &st));
7921 if (!is_error(ret))
7922 ret = host_to_target_stat64(cpu_env, arg2, &st);
7923 break;
bellardec86b0f2003-04-11 00:15:04 +00007924#endif
Peter Maydellc0d472b2013-06-12 16:20:21 +01007925#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
aurel329d33b762009-04-08 23:07:05 +00007926#ifdef TARGET_NR_fstatat64
balrog6a24a772008-09-20 02:23:36 +00007927 case TARGET_NR_fstatat64:
aurel329d33b762009-04-08 23:07:05 +00007928#endif
7929#ifdef TARGET_NR_newfstatat
7930 case TARGET_NR_newfstatat:
7931#endif
balrog6a24a772008-09-20 02:23:36 +00007932 if (!(p = lock_user_string(arg2)))
7933 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01007934 ret = get_errno(fstatat(arg1, path(p), &st, arg4));
balrog6a24a772008-09-20 02:23:36 +00007935 if (!is_error(ret))
7936 ret = host_to_target_stat64(cpu_env, arg3, &st);
bellard60cd49d2003-03-16 22:53:56 +00007937 break;
bellarda315a142005-01-30 22:59:18 +00007938#endif
bellard67867302003-11-23 17:05:30 +00007939 case TARGET_NR_lchown:
bellard579a97f2007-11-11 14:26:47 +00007940 if (!(p = lock_user_string(arg1)))
7941 goto efault;
pbrook53a59602006-03-25 19:31:22 +00007942 ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
7943 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00007944 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007945#ifdef TARGET_NR_getuid
bellard67867302003-11-23 17:05:30 +00007946 case TARGET_NR_getuid:
7947 ret = get_errno(high2lowuid(getuid()));
7948 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007949#endif
7950#ifdef TARGET_NR_getgid
bellard67867302003-11-23 17:05:30 +00007951 case TARGET_NR_getgid:
7952 ret = get_errno(high2lowgid(getgid()));
7953 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007954#endif
7955#ifdef TARGET_NR_geteuid
bellard67867302003-11-23 17:05:30 +00007956 case TARGET_NR_geteuid:
7957 ret = get_errno(high2lowuid(geteuid()));
7958 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007959#endif
7960#ifdef TARGET_NR_getegid
bellard67867302003-11-23 17:05:30 +00007961 case TARGET_NR_getegid:
7962 ret = get_errno(high2lowgid(getegid()));
7963 break;
Riku Voipio0c866a72011-04-18 15:23:06 +03007964#endif
bellard67867302003-11-23 17:05:30 +00007965 case TARGET_NR_setreuid:
7966 ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
7967 break;
7968 case TARGET_NR_setregid:
7969 ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
7970 break;
7971 case TARGET_NR_getgroups:
7972 {
7973 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007974 target_id *target_grouplist;
bellard67867302003-11-23 17:05:30 +00007975 gid_t *grouplist;
7976 int i;
7977
7978 grouplist = alloca(gidsetsize * sizeof(gid_t));
7979 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00007980 if (gidsetsize == 0)
7981 break;
bellard67867302003-11-23 17:05:30 +00007982 if (!is_error(ret)) {
Andreas Schwab03903ff2013-04-09 05:41:33 +00007983 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
bellard579a97f2007-11-11 14:26:47 +00007984 if (!target_grouplist)
7985 goto efault;
balroga2155fc2008-09-20 02:12:08 +00007986 for(i = 0;i < ret; i++)
Riku Voipio0c866a72011-04-18 15:23:06 +03007987 target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
Andreas Schwab03903ff2013-04-09 05:41:33 +00007988 unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
bellard67867302003-11-23 17:05:30 +00007989 }
7990 }
7991 break;
7992 case TARGET_NR_setgroups:
7993 {
7994 int gidsetsize = arg1;
Riku Voipio0c866a72011-04-18 15:23:06 +03007995 target_id *target_grouplist;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007996 gid_t *grouplist = NULL;
bellard67867302003-11-23 17:05:30 +00007997 int i;
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05007998 if (gidsetsize) {
7999 grouplist = alloca(gidsetsize * sizeof(gid_t));
Andreas Schwab03903ff2013-04-09 05:41:33 +00008000 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
Dillon Amburgeyf2b79ce2013-02-02 18:04:48 -05008001 if (!target_grouplist) {
8002 ret = -TARGET_EFAULT;
8003 goto fail;
8004 }
8005 for (i = 0; i < gidsetsize; i++) {
8006 grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
8007 }
8008 unlock_user(target_grouplist, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +00008009 }
bellard67867302003-11-23 17:05:30 +00008010 ret = get_errno(setgroups(gidsetsize, grouplist));
8011 }
8012 break;
8013 case TARGET_NR_fchown:
8014 ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
8015 break;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008016#if defined(TARGET_NR_fchownat)
thsccfa72b2007-09-24 09:23:34 +00008017 case TARGET_NR_fchownat:
bellard579a97f2007-11-11 14:26:47 +00008018 if (!(p = lock_user_string(arg2)))
8019 goto efault;
Peter Maydellc0d472b2013-06-12 16:20:21 +01008020 ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
8021 low2highgid(arg4), arg5));
bellard579a97f2007-11-11 14:26:47 +00008022 unlock_user(p, arg2, 0);
thsccfa72b2007-09-24 09:23:34 +00008023 break;
8024#endif
bellard67867302003-11-23 17:05:30 +00008025#ifdef TARGET_NR_setresuid
8026 case TARGET_NR_setresuid:
ths5fafdf22007-09-16 21:08:06 +00008027 ret = get_errno(setresuid(low2highuid(arg1),
8028 low2highuid(arg2),
bellard67867302003-11-23 17:05:30 +00008029 low2highuid(arg3)));
8030 break;
8031#endif
8032#ifdef TARGET_NR_getresuid
8033 case TARGET_NR_getresuid:
8034 {
pbrook53a59602006-03-25 19:31:22 +00008035 uid_t ruid, euid, suid;
bellard67867302003-11-23 17:05:30 +00008036 ret = get_errno(getresuid(&ruid, &euid, &suid));
8037 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008038 if (put_user_id(high2lowuid(ruid), arg1)
8039 || put_user_id(high2lowuid(euid), arg2)
8040 || put_user_id(high2lowuid(suid), arg3))
bellard2f619692007-11-16 10:46:05 +00008041 goto efault;
bellard67867302003-11-23 17:05:30 +00008042 }
8043 }
8044 break;
8045#endif
8046#ifdef TARGET_NR_getresgid
8047 case TARGET_NR_setresgid:
ths5fafdf22007-09-16 21:08:06 +00008048 ret = get_errno(setresgid(low2highgid(arg1),
8049 low2highgid(arg2),
bellard67867302003-11-23 17:05:30 +00008050 low2highgid(arg3)));
8051 break;
8052#endif
8053#ifdef TARGET_NR_getresgid
8054 case TARGET_NR_getresgid:
8055 {
pbrook53a59602006-03-25 19:31:22 +00008056 gid_t rgid, egid, sgid;
bellard67867302003-11-23 17:05:30 +00008057 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8058 if (!is_error(ret)) {
Peter Maydell76ca3102014-03-02 19:36:41 +00008059 if (put_user_id(high2lowgid(rgid), arg1)
8060 || put_user_id(high2lowgid(egid), arg2)
8061 || put_user_id(high2lowgid(sgid), arg3))
bellard2f619692007-11-16 10:46:05 +00008062 goto efault;
bellard67867302003-11-23 17:05:30 +00008063 }
8064 }
8065 break;
8066#endif
8067 case TARGET_NR_chown:
bellard579a97f2007-11-11 14:26:47 +00008068 if (!(p = lock_user_string(arg1)))
8069 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008070 ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
8071 unlock_user(p, arg1, 0);
bellard67867302003-11-23 17:05:30 +00008072 break;
8073 case TARGET_NR_setuid:
8074 ret = get_errno(setuid(low2highuid(arg1)));
8075 break;
8076 case TARGET_NR_setgid:
8077 ret = get_errno(setgid(low2highgid(arg1)));
8078 break;
8079 case TARGET_NR_setfsuid:
8080 ret = get_errno(setfsuid(arg1));
8081 break;
8082 case TARGET_NR_setfsgid:
8083 ret = get_errno(setfsgid(arg1));
8084 break;
bellard67867302003-11-23 17:05:30 +00008085
bellarda315a142005-01-30 22:59:18 +00008086#ifdef TARGET_NR_lchown32
bellard31e31b82003-02-18 22:55:36 +00008087 case TARGET_NR_lchown32:
bellard579a97f2007-11-11 14:26:47 +00008088 if (!(p = lock_user_string(arg1)))
8089 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008090 ret = get_errno(lchown(p, arg2, arg3));
8091 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008092 break;
bellarda315a142005-01-30 22:59:18 +00008093#endif
8094#ifdef TARGET_NR_getuid32
bellard31e31b82003-02-18 22:55:36 +00008095 case TARGET_NR_getuid32:
bellardb03c60f2003-03-23 17:19:56 +00008096 ret = get_errno(getuid());
8097 break;
bellarda315a142005-01-30 22:59:18 +00008098#endif
aurel3264b4d282008-11-14 17:20:15 +00008099
8100#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
8101 /* Alpha specific */
8102 case TARGET_NR_getxuid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008103 {
8104 uid_t euid;
8105 euid=geteuid();
8106 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
8107 }
aurel3264b4d282008-11-14 17:20:15 +00008108 ret = get_errno(getuid());
8109 break;
8110#endif
8111#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
8112 /* Alpha specific */
8113 case TARGET_NR_getxgid:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008114 {
8115 uid_t egid;
8116 egid=getegid();
8117 ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
8118 }
aurel3264b4d282008-11-14 17:20:15 +00008119 ret = get_errno(getgid());
8120 break;
8121#endif
Richard Hendersonba0e2762009-12-09 15:56:29 -08008122#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
8123 /* Alpha specific */
8124 case TARGET_NR_osf_getsysinfo:
8125 ret = -TARGET_EOPNOTSUPP;
8126 switch (arg1) {
8127 case TARGET_GSI_IEEE_FP_CONTROL:
8128 {
8129 uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
8130
8131 /* Copied from linux ieee_fpcr_to_swcr. */
8132 swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
8133 swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
8134 swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
8135 | SWCR_TRAP_ENABLE_DZE
8136 | SWCR_TRAP_ENABLE_OVF);
8137 swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
8138 | SWCR_TRAP_ENABLE_INE);
8139 swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
8140 swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
8141
8142 if (put_user_u64 (swcr, arg2))
8143 goto efault;
8144 ret = 0;
8145 }
8146 break;
8147
8148 /* case GSI_IEEE_STATE_AT_SIGNAL:
8149 -- Not implemented in linux kernel.
8150 case GSI_UACPROC:
8151 -- Retrieves current unaligned access state; not much used.
8152 case GSI_PROC_TYPE:
8153 -- Retrieves implver information; surely not used.
8154 case GSI_GET_HWRPB:
8155 -- Grabs a copy of the HWRPB; surely not used.
8156 */
8157 }
8158 break;
8159#endif
8160#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
8161 /* Alpha specific */
8162 case TARGET_NR_osf_setsysinfo:
8163 ret = -TARGET_EOPNOTSUPP;
8164 switch (arg1) {
8165 case TARGET_SSI_IEEE_FP_CONTROL:
Richard Hendersonba0e2762009-12-09 15:56:29 -08008166 {
8167 uint64_t swcr, fpcr, orig_fpcr;
8168
Richard Henderson6e06d512012-06-01 09:08:21 -07008169 if (get_user_u64 (swcr, arg2)) {
Richard Hendersonba0e2762009-12-09 15:56:29 -08008170 goto efault;
Richard Henderson6e06d512012-06-01 09:08:21 -07008171 }
8172 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008173 fpcr = orig_fpcr & FPCR_DYN_MASK;
8174
8175 /* Copied from linux ieee_swcr_to_fpcr. */
8176 fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
8177 fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
8178 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
8179 | SWCR_TRAP_ENABLE_DZE
8180 | SWCR_TRAP_ENABLE_OVF)) << 48;
8181 fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
8182 | SWCR_TRAP_ENABLE_INE)) << 57;
8183 fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
8184 fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
8185
Richard Henderson6e06d512012-06-01 09:08:21 -07008186 cpu_alpha_store_fpcr(cpu_env, fpcr);
8187 ret = 0;
8188 }
8189 break;
8190
8191 case TARGET_SSI_IEEE_RAISE_EXCEPTION:
8192 {
8193 uint64_t exc, fpcr, orig_fpcr;
8194 int si_code;
8195
8196 if (get_user_u64(exc, arg2)) {
8197 goto efault;
8198 }
8199
8200 orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
8201
8202 /* We only add to the exception status here. */
8203 fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
8204
8205 cpu_alpha_store_fpcr(cpu_env, fpcr);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008206 ret = 0;
8207
Richard Henderson6e06d512012-06-01 09:08:21 -07008208 /* Old exceptions are not signaled. */
8209 fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008210
Richard Henderson6e06d512012-06-01 09:08:21 -07008211 /* If any exceptions set by this call,
8212 and are unmasked, send a signal. */
8213 si_code = 0;
8214 if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
8215 si_code = TARGET_FPE_FLTRES;
8216 }
8217 if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
8218 si_code = TARGET_FPE_FLTUND;
8219 }
8220 if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
8221 si_code = TARGET_FPE_FLTOVF;
8222 }
8223 if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
8224 si_code = TARGET_FPE_FLTDIV;
8225 }
8226 if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
8227 si_code = TARGET_FPE_FLTINV;
8228 }
8229 if (si_code != 0) {
8230 target_siginfo_t info;
8231 info.si_signo = SIGFPE;
8232 info.si_errno = 0;
8233 info.si_code = si_code;
8234 info._sifields._sigfault._addr
8235 = ((CPUArchState *)cpu_env)->pc;
8236 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008237 }
8238 }
8239 break;
8240
8241 /* case SSI_NVPAIRS:
8242 -- Used with SSIN_UACPROC to enable unaligned accesses.
8243 case SSI_IEEE_STATE_AT_SIGNAL:
8244 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
8245 -- Not implemented in linux kernel
8246 */
8247 }
8248 break;
8249#endif
8250#ifdef TARGET_NR_osf_sigprocmask
8251 /* Alpha specific. */
8252 case TARGET_NR_osf_sigprocmask:
8253 {
8254 abi_ulong mask;
Juan Quintelabc088ba2011-06-16 17:37:10 +01008255 int how;
Richard Hendersonba0e2762009-12-09 15:56:29 -08008256 sigset_t set, oldset;
8257
8258 switch(arg1) {
8259 case TARGET_SIG_BLOCK:
8260 how = SIG_BLOCK;
8261 break;
8262 case TARGET_SIG_UNBLOCK:
8263 how = SIG_UNBLOCK;
8264 break;
8265 case TARGET_SIG_SETMASK:
8266 how = SIG_SETMASK;
8267 break;
8268 default:
8269 ret = -TARGET_EINVAL;
8270 goto fail;
8271 }
8272 mask = arg2;
8273 target_to_host_old_sigset(&set, &mask);
Alex Barcelo1c275922014-03-14 14:36:55 +00008274 do_sigprocmask(how, &set, &oldset);
Richard Hendersonba0e2762009-12-09 15:56:29 -08008275 host_to_target_old_sigset(&mask, &oldset);
8276 ret = mask;
8277 }
8278 break;
8279#endif
aurel3264b4d282008-11-14 17:20:15 +00008280
bellarda315a142005-01-30 22:59:18 +00008281#ifdef TARGET_NR_getgid32
bellard31e31b82003-02-18 22:55:36 +00008282 case TARGET_NR_getgid32:
bellardb03c60f2003-03-23 17:19:56 +00008283 ret = get_errno(getgid());
8284 break;
bellarda315a142005-01-30 22:59:18 +00008285#endif
8286#ifdef TARGET_NR_geteuid32
bellard31e31b82003-02-18 22:55:36 +00008287 case TARGET_NR_geteuid32:
bellardb03c60f2003-03-23 17:19:56 +00008288 ret = get_errno(geteuid());
8289 break;
bellarda315a142005-01-30 22:59:18 +00008290#endif
8291#ifdef TARGET_NR_getegid32
bellard31e31b82003-02-18 22:55:36 +00008292 case TARGET_NR_getegid32:
bellardb03c60f2003-03-23 17:19:56 +00008293 ret = get_errno(getegid());
8294 break;
bellarda315a142005-01-30 22:59:18 +00008295#endif
8296#ifdef TARGET_NR_setreuid32
bellard31e31b82003-02-18 22:55:36 +00008297 case TARGET_NR_setreuid32:
bellardb03c60f2003-03-23 17:19:56 +00008298 ret = get_errno(setreuid(arg1, arg2));
8299 break;
bellarda315a142005-01-30 22:59:18 +00008300#endif
8301#ifdef TARGET_NR_setregid32
bellard31e31b82003-02-18 22:55:36 +00008302 case TARGET_NR_setregid32:
bellardb03c60f2003-03-23 17:19:56 +00008303 ret = get_errno(setregid(arg1, arg2));
8304 break;
bellarda315a142005-01-30 22:59:18 +00008305#endif
8306#ifdef TARGET_NR_getgroups32
bellard31e31b82003-02-18 22:55:36 +00008307 case TARGET_NR_getgroups32:
bellard99c475a2005-01-31 20:45:13 +00008308 {
8309 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008310 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008311 gid_t *grouplist;
8312 int i;
8313
8314 grouplist = alloca(gidsetsize * sizeof(gid_t));
8315 ret = get_errno(getgroups(gidsetsize, grouplist));
balrogcb3bc232008-09-20 02:08:13 +00008316 if (gidsetsize == 0)
8317 break;
bellard99c475a2005-01-31 20:45:13 +00008318 if (!is_error(ret)) {
bellard579a97f2007-11-11 14:26:47 +00008319 target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
8320 if (!target_grouplist) {
8321 ret = -TARGET_EFAULT;
8322 goto fail;
8323 }
balroga2155fc2008-09-20 02:12:08 +00008324 for(i = 0;i < ret; i++)
pbrook53a59602006-03-25 19:31:22 +00008325 target_grouplist[i] = tswap32(grouplist[i]);
8326 unlock_user(target_grouplist, arg2, gidsetsize * 4);
bellard99c475a2005-01-31 20:45:13 +00008327 }
8328 }
8329 break;
bellarda315a142005-01-30 22:59:18 +00008330#endif
8331#ifdef TARGET_NR_setgroups32
bellard31e31b82003-02-18 22:55:36 +00008332 case TARGET_NR_setgroups32:
bellard99c475a2005-01-31 20:45:13 +00008333 {
8334 int gidsetsize = arg1;
pbrook53a59602006-03-25 19:31:22 +00008335 uint32_t *target_grouplist;
bellard99c475a2005-01-31 20:45:13 +00008336 gid_t *grouplist;
8337 int i;
ths3b46e622007-09-17 08:09:54 +00008338
bellard99c475a2005-01-31 20:45:13 +00008339 grouplist = alloca(gidsetsize * sizeof(gid_t));
bellard579a97f2007-11-11 14:26:47 +00008340 target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
8341 if (!target_grouplist) {
8342 ret = -TARGET_EFAULT;
8343 goto fail;
8344 }
bellard99c475a2005-01-31 20:45:13 +00008345 for(i = 0;i < gidsetsize; i++)
pbrook53a59602006-03-25 19:31:22 +00008346 grouplist[i] = tswap32(target_grouplist[i]);
8347 unlock_user(target_grouplist, arg2, 0);
bellard99c475a2005-01-31 20:45:13 +00008348 ret = get_errno(setgroups(gidsetsize, grouplist));
8349 }
8350 break;
bellarda315a142005-01-30 22:59:18 +00008351#endif
8352#ifdef TARGET_NR_fchown32
bellard31e31b82003-02-18 22:55:36 +00008353 case TARGET_NR_fchown32:
bellardb03c60f2003-03-23 17:19:56 +00008354 ret = get_errno(fchown(arg1, arg2, arg3));
8355 break;
bellarda315a142005-01-30 22:59:18 +00008356#endif
8357#ifdef TARGET_NR_setresuid32
bellard31e31b82003-02-18 22:55:36 +00008358 case TARGET_NR_setresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008359 ret = get_errno(setresuid(arg1, arg2, arg3));
8360 break;
bellarda315a142005-01-30 22:59:18 +00008361#endif
8362#ifdef TARGET_NR_getresuid32
bellard31e31b82003-02-18 22:55:36 +00008363 case TARGET_NR_getresuid32:
bellardb03c60f2003-03-23 17:19:56 +00008364 {
pbrook53a59602006-03-25 19:31:22 +00008365 uid_t ruid, euid, suid;
bellardb03c60f2003-03-23 17:19:56 +00008366 ret = get_errno(getresuid(&ruid, &euid, &suid));
8367 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008368 if (put_user_u32(ruid, arg1)
8369 || put_user_u32(euid, arg2)
8370 || put_user_u32(suid, arg3))
8371 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008372 }
8373 }
8374 break;
bellarda315a142005-01-30 22:59:18 +00008375#endif
8376#ifdef TARGET_NR_setresgid32
bellard31e31b82003-02-18 22:55:36 +00008377 case TARGET_NR_setresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008378 ret = get_errno(setresgid(arg1, arg2, arg3));
8379 break;
bellarda315a142005-01-30 22:59:18 +00008380#endif
8381#ifdef TARGET_NR_getresgid32
bellard31e31b82003-02-18 22:55:36 +00008382 case TARGET_NR_getresgid32:
bellardb03c60f2003-03-23 17:19:56 +00008383 {
pbrook53a59602006-03-25 19:31:22 +00008384 gid_t rgid, egid, sgid;
bellardb03c60f2003-03-23 17:19:56 +00008385 ret = get_errno(getresgid(&rgid, &egid, &sgid));
8386 if (!is_error(ret)) {
bellard2f619692007-11-16 10:46:05 +00008387 if (put_user_u32(rgid, arg1)
8388 || put_user_u32(egid, arg2)
8389 || put_user_u32(sgid, arg3))
8390 goto efault;
bellardb03c60f2003-03-23 17:19:56 +00008391 }
8392 }
8393 break;
bellarda315a142005-01-30 22:59:18 +00008394#endif
8395#ifdef TARGET_NR_chown32
bellard31e31b82003-02-18 22:55:36 +00008396 case TARGET_NR_chown32:
bellard579a97f2007-11-11 14:26:47 +00008397 if (!(p = lock_user_string(arg1)))
8398 goto efault;
pbrook53a59602006-03-25 19:31:22 +00008399 ret = get_errno(chown(p, arg2, arg3));
8400 unlock_user(p, arg1, 0);
bellardb03c60f2003-03-23 17:19:56 +00008401 break;
bellarda315a142005-01-30 22:59:18 +00008402#endif
8403#ifdef TARGET_NR_setuid32
bellard31e31b82003-02-18 22:55:36 +00008404 case TARGET_NR_setuid32:
bellardb03c60f2003-03-23 17:19:56 +00008405 ret = get_errno(setuid(arg1));
8406 break;
bellarda315a142005-01-30 22:59:18 +00008407#endif
8408#ifdef TARGET_NR_setgid32
bellard31e31b82003-02-18 22:55:36 +00008409 case TARGET_NR_setgid32:
bellardb03c60f2003-03-23 17:19:56 +00008410 ret = get_errno(setgid(arg1));
8411 break;
bellarda315a142005-01-30 22:59:18 +00008412#endif
8413#ifdef TARGET_NR_setfsuid32
bellard31e31b82003-02-18 22:55:36 +00008414 case TARGET_NR_setfsuid32:
bellardb03c60f2003-03-23 17:19:56 +00008415 ret = get_errno(setfsuid(arg1));
8416 break;
bellarda315a142005-01-30 22:59:18 +00008417#endif
8418#ifdef TARGET_NR_setfsgid32
bellard31e31b82003-02-18 22:55:36 +00008419 case TARGET_NR_setfsgid32:
bellardb03c60f2003-03-23 17:19:56 +00008420 ret = get_errno(setfsgid(arg1));
8421 break;
bellarda315a142005-01-30 22:59:18 +00008422#endif
bellard67867302003-11-23 17:05:30 +00008423
bellard31e31b82003-02-18 22:55:36 +00008424 case TARGET_NR_pivot_root:
bellardb03c60f2003-03-23 17:19:56 +00008425 goto unimplemented;
bellardffa65c32004-01-04 23:57:22 +00008426#ifdef TARGET_NR_mincore
bellard31e31b82003-02-18 22:55:36 +00008427 case TARGET_NR_mincore:
aurel3204bb9ac2008-10-01 21:46:41 +00008428 {
8429 void *a;
8430 ret = -TARGET_EFAULT;
8431 if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
8432 goto efault;
8433 if (!(p = lock_user_string(arg3)))
8434 goto mincore_fail;
8435 ret = get_errno(mincore(a, arg2, p));
8436 unlock_user(p, arg3, ret);
8437 mincore_fail:
8438 unlock_user(a, arg1, 0);
8439 }
8440 break;
bellardffa65c32004-01-04 23:57:22 +00008441#endif
aurel32408321b2008-10-01 21:46:32 +00008442#ifdef TARGET_NR_arm_fadvise64_64
8443 case TARGET_NR_arm_fadvise64_64:
8444 {
8445 /*
8446 * arm_fadvise64_64 looks like fadvise64_64 but
8447 * with different argument order
8448 */
8449 abi_long temp;
8450 temp = arg3;
8451 arg3 = arg4;
8452 arg4 = temp;
8453 }
8454#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008455#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
aurel32408321b2008-10-01 21:46:32 +00008456#ifdef TARGET_NR_fadvise64_64
8457 case TARGET_NR_fadvise64_64:
8458#endif
Ulrich Hechte72d2cc2009-07-24 19:10:31 +02008459#ifdef TARGET_NR_fadvise64
8460 case TARGET_NR_fadvise64:
8461#endif
8462#ifdef TARGET_S390X
8463 switch (arg4) {
8464 case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
8465 case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
8466 case 6: arg4 = POSIX_FADV_DONTNEED; break;
8467 case 7: arg4 = POSIX_FADV_NOREUSE; break;
8468 default: break;
8469 }
8470#endif
8471 ret = -posix_fadvise(arg1, arg2, arg3, arg4);
aurel32408321b2008-10-01 21:46:32 +00008472 break;
8473#endif
bellardffa65c32004-01-04 23:57:22 +00008474#ifdef TARGET_NR_madvise
bellard31e31b82003-02-18 22:55:36 +00008475 case TARGET_NR_madvise:
pbrook24836682006-04-16 14:14:53 +00008476 /* A straight passthrough may not be safe because qemu sometimes
Lei Lid2d6b852013-05-20 17:20:50 +08008477 turns private file-backed mappings into anonymous mappings.
pbrook24836682006-04-16 14:14:53 +00008478 This will break MADV_DONTNEED.
8479 This is a hint, so ignoring and returning success is ok. */
8480 ret = get_errno(0);
8481 break;
bellardffa65c32004-01-04 23:57:22 +00008482#endif
blueswir1992f48a2007-10-14 16:27:31 +00008483#if TARGET_ABI_BITS == 32
bellard31e31b82003-02-18 22:55:36 +00008484 case TARGET_NR_fcntl64:
bellard77e46722003-04-29 20:39:06 +00008485 {
thsb1e341e2007-03-20 21:50:52 +00008486 int cmd;
bellard77e46722003-04-29 20:39:06 +00008487 struct flock64 fl;
pbrook53a59602006-03-25 19:31:22 +00008488 struct target_flock64 *target_fl;
pbrookce4defa2006-02-09 16:49:55 +00008489#ifdef TARGET_ARM
pbrook53a59602006-03-25 19:31:22 +00008490 struct target_eabi_flock64 *target_efl;
pbrookce4defa2006-02-09 16:49:55 +00008491#endif
bellard77e46722003-04-29 20:39:06 +00008492
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008493 cmd = target_to_host_fcntl_cmd(arg2);
Peter Maydell31b63192011-12-05 23:11:50 +00008494 if (cmd == -TARGET_EINVAL) {
8495 ret = cmd;
8496 break;
8497 }
thsb1e341e2007-03-20 21:50:52 +00008498
bellard60cd49d2003-03-16 22:53:56 +00008499 switch(arg2) {
thsb1e341e2007-03-20 21:50:52 +00008500 case TARGET_F_GETLK64:
ths58134272007-03-31 18:59:32 +00008501#ifdef TARGET_ARM
8502 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008503 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8504 goto efault;
ths58134272007-03-31 18:59:32 +00008505 fl.l_type = tswap16(target_efl->l_type);
8506 fl.l_whence = tswap16(target_efl->l_whence);
8507 fl.l_start = tswap64(target_efl->l_start);
8508 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008509 fl.l_pid = tswap32(target_efl->l_pid);
ths58134272007-03-31 18:59:32 +00008510 unlock_user_struct(target_efl, arg3, 0);
8511 } else
8512#endif
8513 {
bellard9ee1fa22007-11-11 15:11:19 +00008514 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8515 goto efault;
ths58134272007-03-31 18:59:32 +00008516 fl.l_type = tswap16(target_fl->l_type);
8517 fl.l_whence = tswap16(target_fl->l_whence);
8518 fl.l_start = tswap64(target_fl->l_start);
8519 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008520 fl.l_pid = tswap32(target_fl->l_pid);
ths58134272007-03-31 18:59:32 +00008521 unlock_user_struct(target_fl, arg3, 0);
8522 }
thsb1e341e2007-03-20 21:50:52 +00008523 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008524 if (ret == 0) {
pbrookce4defa2006-02-09 16:49:55 +00008525#ifdef TARGET_ARM
8526 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008527 if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
8528 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008529 target_efl->l_type = tswap16(fl.l_type);
8530 target_efl->l_whence = tswap16(fl.l_whence);
8531 target_efl->l_start = tswap64(fl.l_start);
8532 target_efl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008533 target_efl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008534 unlock_user_struct(target_efl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008535 } else
8536#endif
8537 {
bellard9ee1fa22007-11-11 15:11:19 +00008538 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
8539 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008540 target_fl->l_type = tswap16(fl.l_type);
8541 target_fl->l_whence = tswap16(fl.l_whence);
8542 target_fl->l_start = tswap64(fl.l_start);
8543 target_fl->l_len = tswap64(fl.l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008544 target_fl->l_pid = tswap32(fl.l_pid);
pbrook53a59602006-03-25 19:31:22 +00008545 unlock_user_struct(target_fl, arg3, 1);
pbrookce4defa2006-02-09 16:49:55 +00008546 }
bellard77e46722003-04-29 20:39:06 +00008547 }
8548 break;
8549
thsb1e341e2007-03-20 21:50:52 +00008550 case TARGET_F_SETLK64:
8551 case TARGET_F_SETLKW64:
pbrookce4defa2006-02-09 16:49:55 +00008552#ifdef TARGET_ARM
8553 if (((CPUARMState *)cpu_env)->eabi) {
bellard9ee1fa22007-11-11 15:11:19 +00008554 if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
8555 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008556 fl.l_type = tswap16(target_efl->l_type);
8557 fl.l_whence = tswap16(target_efl->l_whence);
8558 fl.l_start = tswap64(target_efl->l_start);
8559 fl.l_len = tswap64(target_efl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008560 fl.l_pid = tswap32(target_efl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008561 unlock_user_struct(target_efl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008562 } else
8563#endif
8564 {
bellard9ee1fa22007-11-11 15:11:19 +00008565 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
8566 goto efault;
pbrookce4defa2006-02-09 16:49:55 +00008567 fl.l_type = tswap16(target_fl->l_type);
8568 fl.l_whence = tswap16(target_fl->l_whence);
8569 fl.l_start = tswap64(target_fl->l_start);
8570 fl.l_len = tswap64(target_fl->l_len);
Ulrich Hecht7e22e542009-07-24 19:10:27 +02008571 fl.l_pid = tswap32(target_fl->l_pid);
pbrook53a59602006-03-25 19:31:22 +00008572 unlock_user_struct(target_fl, arg3, 0);
pbrookce4defa2006-02-09 16:49:55 +00008573 }
thsb1e341e2007-03-20 21:50:52 +00008574 ret = get_errno(fcntl(arg1, cmd, &fl));
bellard77e46722003-04-29 20:39:06 +00008575 break;
bellard60cd49d2003-03-16 22:53:56 +00008576 default:
Arnaud Patard (Rtp)5f106812009-06-03 14:35:04 +02008577 ret = do_fcntl(arg1, arg2, arg3);
bellard60cd49d2003-03-16 22:53:56 +00008578 break;
8579 }
bellard77e46722003-04-29 20:39:06 +00008580 break;
8581 }
bellard60cd49d2003-03-16 22:53:56 +00008582#endif
ths7d600c82006-12-08 01:32:58 +00008583#ifdef TARGET_NR_cacheflush
8584 case TARGET_NR_cacheflush:
8585 /* self-modifying code is handled automatically, so nothing needed */
8586 ret = 0;
8587 break;
8588#endif
bellardebc05482003-09-30 21:08:41 +00008589#ifdef TARGET_NR_security
bellard31e31b82003-02-18 22:55:36 +00008590 case TARGET_NR_security:
8591 goto unimplemented;
bellardebc05482003-09-30 21:08:41 +00008592#endif
bellardc573ff62004-01-04 15:51:36 +00008593#ifdef TARGET_NR_getpagesize
8594 case TARGET_NR_getpagesize:
8595 ret = TARGET_PAGE_SIZE;
8596 break;
8597#endif
bellard31e31b82003-02-18 22:55:36 +00008598 case TARGET_NR_gettid:
8599 ret = get_errno(gettid());
8600 break;
thse5febef2007-04-01 18:31:35 +00008601#ifdef TARGET_NR_readahead
bellard31e31b82003-02-18 22:55:36 +00008602 case TARGET_NR_readahead:
aurel322054ac92008-10-13 21:08:07 +00008603#if TARGET_ABI_BITS == 32
Riku Voipio48e515d2011-07-12 15:40:51 +03008604 if (regpairs_aligned(cpu_env)) {
aurel322054ac92008-10-13 21:08:07 +00008605 arg2 = arg3;
8606 arg3 = arg4;
8607 arg4 = arg5;
8608 }
aurel322054ac92008-10-13 21:08:07 +00008609 ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
8610#else
8611 ret = get_errno(readahead(arg1, arg2, arg3));
8612#endif
8613 break;
thse5febef2007-04-01 18:31:35 +00008614#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008615#ifdef CONFIG_ATTR
bellardebc05482003-09-30 21:08:41 +00008616#ifdef TARGET_NR_setxattr
bellard31e31b82003-02-18 22:55:36 +00008617 case TARGET_NR_listxattr:
8618 case TARGET_NR_llistxattr:
Peter Maydellfb5590f2011-12-14 15:37:19 +00008619 {
8620 void *p, *b = 0;
8621 if (arg2) {
8622 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8623 if (!b) {
8624 ret = -TARGET_EFAULT;
8625 break;
8626 }
8627 }
8628 p = lock_user_string(arg1);
8629 if (p) {
8630 if (num == TARGET_NR_listxattr) {
8631 ret = get_errno(listxattr(p, b, arg3));
8632 } else {
8633 ret = get_errno(llistxattr(p, b, arg3));
8634 }
8635 } else {
8636 ret = -TARGET_EFAULT;
8637 }
8638 unlock_user(p, arg1, 0);
8639 unlock_user(b, arg2, arg3);
Arnaud Patard6f932f92009-04-21 21:04:18 +03008640 break;
Peter Maydellfb5590f2011-12-14 15:37:19 +00008641 }
8642 case TARGET_NR_flistxattr:
8643 {
8644 void *b = 0;
8645 if (arg2) {
8646 b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
8647 if (!b) {
8648 ret = -TARGET_EFAULT;
8649 break;
8650 }
8651 }
8652 ret = get_errno(flistxattr(arg1, b, arg3));
8653 unlock_user(b, arg2, arg3);
8654 break;
8655 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008656 case TARGET_NR_setxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008657 case TARGET_NR_lsetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008658 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008659 void *p, *n, *v = 0;
8660 if (arg3) {
8661 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8662 if (!v) {
8663 ret = -TARGET_EFAULT;
8664 break;
8665 }
8666 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008667 p = lock_user_string(arg1);
8668 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008669 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008670 if (num == TARGET_NR_setxattr) {
8671 ret = get_errno(setxattr(p, n, v, arg4, arg5));
8672 } else {
8673 ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
8674 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008675 } else {
8676 ret = -TARGET_EFAULT;
8677 }
8678 unlock_user(p, arg1, 0);
8679 unlock_user(n, arg2, 0);
8680 unlock_user(v, arg3, 0);
8681 }
8682 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008683 case TARGET_NR_fsetxattr:
8684 {
8685 void *n, *v = 0;
8686 if (arg3) {
8687 v = lock_user(VERIFY_READ, arg3, arg4, 1);
8688 if (!v) {
8689 ret = -TARGET_EFAULT;
8690 break;
8691 }
8692 }
8693 n = lock_user_string(arg2);
8694 if (n) {
8695 ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
8696 } else {
8697 ret = -TARGET_EFAULT;
8698 }
8699 unlock_user(n, arg2, 0);
8700 unlock_user(v, arg3, 0);
8701 }
8702 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008703 case TARGET_NR_getxattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008704 case TARGET_NR_lgetxattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008705 {
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008706 void *p, *n, *v = 0;
8707 if (arg3) {
8708 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8709 if (!v) {
8710 ret = -TARGET_EFAULT;
8711 break;
8712 }
8713 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008714 p = lock_user_string(arg1);
8715 n = lock_user_string(arg2);
Peter Maydelle3c33ec2011-12-14 15:37:17 +00008716 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008717 if (num == TARGET_NR_getxattr) {
8718 ret = get_errno(getxattr(p, n, v, arg4));
8719 } else {
8720 ret = get_errno(lgetxattr(p, n, v, arg4));
8721 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008722 } else {
8723 ret = -TARGET_EFAULT;
8724 }
8725 unlock_user(p, arg1, 0);
8726 unlock_user(n, arg2, 0);
8727 unlock_user(v, arg3, arg4);
8728 }
8729 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008730 case TARGET_NR_fgetxattr:
8731 {
8732 void *n, *v = 0;
8733 if (arg3) {
8734 v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
8735 if (!v) {
8736 ret = -TARGET_EFAULT;
8737 break;
8738 }
8739 }
8740 n = lock_user_string(arg2);
8741 if (n) {
8742 ret = get_errno(fgetxattr(arg1, n, v, arg4));
8743 } else {
8744 ret = -TARGET_EFAULT;
8745 }
8746 unlock_user(n, arg2, 0);
8747 unlock_user(v, arg3, arg4);
8748 }
8749 break;
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008750 case TARGET_NR_removexattr:
Peter Maydell30297b52011-12-14 15:37:18 +00008751 case TARGET_NR_lremovexattr:
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008752 {
8753 void *p, *n;
8754 p = lock_user_string(arg1);
8755 n = lock_user_string(arg2);
8756 if (p && n) {
Peter Maydell30297b52011-12-14 15:37:18 +00008757 if (num == TARGET_NR_removexattr) {
8758 ret = get_errno(removexattr(p, n));
8759 } else {
8760 ret = get_errno(lremovexattr(p, n));
8761 }
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008762 } else {
8763 ret = -TARGET_EFAULT;
8764 }
8765 unlock_user(p, arg1, 0);
8766 unlock_user(n, arg2, 0);
8767 }
8768 break;
Peter Maydell30297b52011-12-14 15:37:18 +00008769 case TARGET_NR_fremovexattr:
8770 {
8771 void *n;
8772 n = lock_user_string(arg2);
8773 if (n) {
8774 ret = get_errno(fremovexattr(arg1, n));
8775 } else {
8776 ret = -TARGET_EFAULT;
8777 }
8778 unlock_user(n, arg2, 0);
8779 }
8780 break;
bellardebc05482003-09-30 21:08:41 +00008781#endif
An-Cheng Huanga790ae32011-08-09 12:34:06 -07008782#endif /* CONFIG_ATTR */
bellardebc05482003-09-30 21:08:41 +00008783#ifdef TARGET_NR_set_thread_area
bellard5cd43932003-03-29 16:54:36 +00008784 case TARGET_NR_set_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008785#if defined(TARGET_MIPS)
ths6f5b89a2007-03-02 20:48:00 +00008786 ((CPUMIPSState *) cpu_env)->tls_value = arg1;
8787 ret = 0;
8788 break;
edgar_iglef967792009-01-07 14:19:38 +00008789#elif defined(TARGET_CRIS)
8790 if (arg1 & 0xff)
8791 ret = -TARGET_EINVAL;
8792 else {
8793 ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
8794 ret = 0;
8795 }
8796 break;
bellard8d18e892007-11-14 15:18:40 +00008797#elif defined(TARGET_I386) && defined(TARGET_ABI32)
8798 ret = do_set_thread_area(cpu_env, arg1);
8799 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008800#elif defined(TARGET_M68K)
8801 {
Andreas Färber0429a972013-08-26 18:14:44 +02008802 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008803 ts->tp_value = arg1;
Peter Maydell95c1eb12013-07-29 11:31:49 +01008804 ret = 0;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008805 break;
8806 }
ths6f5b89a2007-03-02 20:48:00 +00008807#else
8808 goto unimplemented_nowarn;
8809#endif
8810#endif
8811#ifdef TARGET_NR_get_thread_area
bellard5cd43932003-03-29 16:54:36 +00008812 case TARGET_NR_get_thread_area:
bellard8d18e892007-11-14 15:18:40 +00008813#if defined(TARGET_I386) && defined(TARGET_ABI32)
8814 ret = do_get_thread_area(cpu_env, arg1);
Peter Maydelld312bbe2013-07-16 18:44:56 +01008815 break;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008816#elif defined(TARGET_M68K)
8817 {
Andreas Färber0429a972013-08-26 18:14:44 +02008818 TaskState *ts = cpu->opaque;
Peter Maydell1ccd9372013-07-16 18:44:55 +01008819 ret = ts->tp_value;
8820 break;
8821 }
bellard8d18e892007-11-14 15:18:40 +00008822#else
bellard5cd43932003-03-29 16:54:36 +00008823 goto unimplemented_nowarn;
bellardebc05482003-09-30 21:08:41 +00008824#endif
bellard8d18e892007-11-14 15:18:40 +00008825#endif
bellard48dc41e2006-06-21 18:15:50 +00008826#ifdef TARGET_NR_getdomainname
8827 case TARGET_NR_getdomainname:
8828 goto unimplemented_nowarn;
8829#endif
ths6f5b89a2007-03-02 20:48:00 +00008830
thsb5906f92007-03-19 13:32:45 +00008831#ifdef TARGET_NR_clock_gettime
8832 case TARGET_NR_clock_gettime:
8833 {
8834 struct timespec ts;
8835 ret = get_errno(clock_gettime(arg1, &ts));
8836 if (!is_error(ret)) {
8837 host_to_target_timespec(arg2, &ts);
8838 }
8839 break;
8840 }
8841#endif
8842#ifdef TARGET_NR_clock_getres
8843 case TARGET_NR_clock_getres:
8844 {
8845 struct timespec ts;
8846 ret = get_errno(clock_getres(arg1, &ts));
8847 if (!is_error(ret)) {
8848 host_to_target_timespec(arg2, &ts);
8849 }
8850 break;
8851 }
8852#endif
pbrook63d76512008-05-29 13:43:29 +00008853#ifdef TARGET_NR_clock_nanosleep
8854 case TARGET_NR_clock_nanosleep:
8855 {
8856 struct timespec ts;
8857 target_to_host_timespec(&ts, arg3);
8858 ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
8859 if (arg4)
8860 host_to_target_timespec(arg4, &ts);
8861 break;
8862 }
8863#endif
thsb5906f92007-03-19 13:32:45 +00008864
ths6f5b89a2007-03-02 20:48:00 +00008865#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
8866 case TARGET_NR_set_tid_address:
bellard579a97f2007-11-11 14:26:47 +00008867 ret = get_errno(set_tid_address((int *)g2h(arg1)));
8868 break;
ths6f5b89a2007-03-02 20:48:00 +00008869#endif
8870
ths3ae43202007-09-16 21:39:48 +00008871#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
ths4cae1d12007-07-12 11:06:53 +00008872 case TARGET_NR_tkill:
pbrook4cb05962008-05-30 18:05:19 +00008873 ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
ths4cae1d12007-07-12 11:06:53 +00008874 break;
8875#endif
8876
ths3ae43202007-09-16 21:39:48 +00008877#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
ths71455572007-06-21 21:45:30 +00008878 case TARGET_NR_tgkill:
pbrook4cb05962008-05-30 18:05:19 +00008879 ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
8880 target_to_host_signal(arg3)));
ths71455572007-06-21 21:45:30 +00008881 break;
8882#endif
8883
ths4f2b1fe2007-06-21 21:57:12 +00008884#ifdef TARGET_NR_set_robust_list
8885 case TARGET_NR_set_robust_list:
Peter Maydelle9a970a2013-02-08 04:34:54 +00008886 case TARGET_NR_get_robust_list:
8887 /* The ABI for supporting robust futexes has userspace pass
8888 * the kernel a pointer to a linked list which is updated by
8889 * userspace after the syscall; the list is walked by the kernel
8890 * when the thread exits. Since the linked list in QEMU guest
8891 * memory isn't a valid linked list for the host and we have
8892 * no way to reliably intercept the thread-death event, we can't
8893 * support these. Silently return ENOSYS so that guest userspace
8894 * falls back to a non-robust futex implementation (which should
8895 * be OK except in the corner case of the guest crashing while
8896 * holding a mutex that is shared with another process via
8897 * shared memory).
8898 */
8899 goto unimplemented_nowarn;
ths4f2b1fe2007-06-21 21:57:12 +00008900#endif
8901
Peter Maydell1acae9f2013-07-02 14:04:12 +01008902#if defined(TARGET_NR_utimensat)
ths9007f0e2007-09-25 17:50:37 +00008903 case TARGET_NR_utimensat:
8904 {
Riku Voipioebc996f2009-04-21 15:01:51 +03008905 struct timespec *tsp, ts[2];
8906 if (!arg3) {
8907 tsp = NULL;
8908 } else {
8909 target_to_host_timespec(ts, arg3);
8910 target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
8911 tsp = ts;
8912 }
ths9007f0e2007-09-25 17:50:37 +00008913 if (!arg2)
Riku Voipioebc996f2009-04-21 15:01:51 +03008914 ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
ths9007f0e2007-09-25 17:50:37 +00008915 else {
bellard579a97f2007-11-11 14:26:47 +00008916 if (!(p = lock_user_string(arg2))) {
ths0da46a62007-10-20 20:23:07 +00008917 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +00008918 goto fail;
8919 }
Riku Voipioebc996f2009-04-21 15:01:51 +03008920 ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
bellard579a97f2007-11-11 14:26:47 +00008921 unlock_user(p, arg2, 0);
ths9007f0e2007-09-25 17:50:37 +00008922 }
8923 }
8924 break;
8925#endif
pbrookbd0c5662008-05-29 14:34:11 +00008926 case TARGET_NR_futex:
8927 ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
8928 break;
aurel32dbfe4c32009-04-08 21:29:30 +00008929#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
aurel3239b59762008-10-01 21:46:50 +00008930 case TARGET_NR_inotify_init:
8931 ret = get_errno(sys_inotify_init());
8932 break;
8933#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008934#ifdef CONFIG_INOTIFY1
Riku Voipioc05c7a72010-03-26 15:25:11 +00008935#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
8936 case TARGET_NR_inotify_init1:
8937 ret = get_errno(sys_inotify_init1(arg1));
8938 break;
8939#endif
Stefan Weila1606b02010-03-28 11:44:41 +02008940#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008941#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
aurel3239b59762008-10-01 21:46:50 +00008942 case TARGET_NR_inotify_add_watch:
8943 p = lock_user_string(arg2);
8944 ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
8945 unlock_user(p, arg2, 0);
8946 break;
8947#endif
aurel32dbfe4c32009-04-08 21:29:30 +00008948#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
aurel3239b59762008-10-01 21:46:50 +00008949 case TARGET_NR_inotify_rm_watch:
8950 ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
8951 break;
8952#endif
ths9007f0e2007-09-25 17:50:37 +00008953
Nathan Froyd8ec9cf82009-07-22 09:14:36 -07008954#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
aurel3224e10032009-04-15 16:11:43 +00008955 case TARGET_NR_mq_open:
8956 {
8957 struct mq_attr posix_mq_attr;
8958
8959 p = lock_user_string(arg1 - 1);
8960 if (arg4 != 0)
8961 copy_from_user_mq_attr (&posix_mq_attr, arg4);
8962 ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
8963 unlock_user (p, arg1, 0);
8964 }
8965 break;
8966
8967 case TARGET_NR_mq_unlink:
8968 p = lock_user_string(arg1 - 1);
8969 ret = get_errno(mq_unlink(p));
8970 unlock_user (p, arg1, 0);
8971 break;
8972
8973 case TARGET_NR_mq_timedsend:
8974 {
8975 struct timespec ts;
8976
8977 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8978 if (arg5 != 0) {
8979 target_to_host_timespec(&ts, arg5);
8980 ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
8981 host_to_target_timespec(arg5, &ts);
8982 }
8983 else
8984 ret = get_errno(mq_send(arg1, p, arg3, arg4));
8985 unlock_user (p, arg2, arg3);
8986 }
8987 break;
8988
8989 case TARGET_NR_mq_timedreceive:
8990 {
8991 struct timespec ts;
8992 unsigned int prio;
8993
8994 p = lock_user (VERIFY_READ, arg2, arg3, 1);
8995 if (arg5 != 0) {
8996 target_to_host_timespec(&ts, arg5);
8997 ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
8998 host_to_target_timespec(arg5, &ts);
8999 }
9000 else
9001 ret = get_errno(mq_receive(arg1, p, arg3, &prio));
9002 unlock_user (p, arg2, arg3);
9003 if (arg4 != 0)
9004 put_user_u32(prio, arg4);
9005 }
9006 break;
9007
9008 /* Not implemented for now... */
9009/* case TARGET_NR_mq_notify: */
9010/* break; */
9011
9012 case TARGET_NR_mq_getsetattr:
9013 {
9014 struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
9015 ret = 0;
9016 if (arg3 != 0) {
9017 ret = mq_getattr(arg1, &posix_mq_attr_out);
9018 copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
9019 }
9020 if (arg2 != 0) {
9021 copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
9022 ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
9023 }
9024
9025 }
9026 break;
9027#endif
9028
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309029#ifdef CONFIG_SPLICE
9030#ifdef TARGET_NR_tee
9031 case TARGET_NR_tee:
9032 {
9033 ret = get_errno(tee(arg1,arg2,arg3,arg4));
9034 }
9035 break;
9036#endif
9037#ifdef TARGET_NR_splice
9038 case TARGET_NR_splice:
9039 {
9040 loff_t loff_in, loff_out;
9041 loff_t *ploff_in = NULL, *ploff_out = NULL;
9042 if(arg2) {
9043 get_user_u64(loff_in, arg2);
9044 ploff_in = &loff_in;
9045 }
9046 if(arg4) {
9047 get_user_u64(loff_out, arg2);
9048 ploff_out = &loff_out;
9049 }
9050 ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
9051 }
9052 break;
9053#endif
9054#ifdef TARGET_NR_vmsplice
9055 case TARGET_NR_vmsplice:
9056 {
Richard Hendersonf287b2c2012-09-15 13:20:25 -07009057 struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
9058 if (vec != NULL) {
9059 ret = get_errno(vmsplice(arg1, vec, arg3, arg4));
9060 unlock_iovec(vec, arg2, arg3, 0);
9061 } else {
9062 ret = -host_to_target_errno(errno);
9063 }
vibisreenivasan3ce34df2009-05-16 18:32:41 +05309064 }
9065 break;
9066#endif
9067#endif /* CONFIG_SPLICE */
Riku Voipioc2882b92009-08-12 15:08:24 +03009068#ifdef CONFIG_EVENTFD
9069#if defined(TARGET_NR_eventfd)
9070 case TARGET_NR_eventfd:
9071 ret = get_errno(eventfd(arg1, 0));
9072 break;
9073#endif
9074#if defined(TARGET_NR_eventfd2)
9075 case TARGET_NR_eventfd2:
Petar Jovanovic5947c692013-04-08 20:26:10 +02009076 {
9077 int host_flags = arg2 & (~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC));
9078 if (arg2 & TARGET_O_NONBLOCK) {
9079 host_flags |= O_NONBLOCK;
9080 }
9081 if (arg2 & TARGET_O_CLOEXEC) {
9082 host_flags |= O_CLOEXEC;
9083 }
9084 ret = get_errno(eventfd(arg1, host_flags));
Riku Voipioc2882b92009-08-12 15:08:24 +03009085 break;
Petar Jovanovic5947c692013-04-08 20:26:10 +02009086 }
Riku Voipioc2882b92009-08-12 15:08:24 +03009087#endif
9088#endif /* CONFIG_EVENTFD */
Ulrich Hechtd0927932009-09-17 20:22:14 +03009089#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
9090 case TARGET_NR_fallocate:
Alexander Graf20249ae2012-02-06 21:37:07 +01009091#if TARGET_ABI_BITS == 32
9092 ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
9093 target_offset64(arg5, arg6)));
9094#else
Ulrich Hechtd0927932009-09-17 20:22:14 +03009095 ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
Alexander Graf20249ae2012-02-06 21:37:07 +01009096#endif
Ulrich Hechtd0927932009-09-17 20:22:14 +03009097 break;
9098#endif
Peter Maydellc727f472011-01-06 11:05:10 +00009099#if defined(CONFIG_SYNC_FILE_RANGE)
9100#if defined(TARGET_NR_sync_file_range)
9101 case TARGET_NR_sync_file_range:
9102#if TARGET_ABI_BITS == 32
Riku Voipiobfcedc52011-06-20 16:24:39 +03009103#if defined(TARGET_MIPS)
9104 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9105 target_offset64(arg5, arg6), arg7));
9106#else
Peter Maydellc727f472011-01-06 11:05:10 +00009107 ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
9108 target_offset64(arg4, arg5), arg6));
Riku Voipiobfcedc52011-06-20 16:24:39 +03009109#endif /* !TARGET_MIPS */
Peter Maydellc727f472011-01-06 11:05:10 +00009110#else
9111 ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
9112#endif
9113 break;
9114#endif
9115#if defined(TARGET_NR_sync_file_range2)
9116 case TARGET_NR_sync_file_range2:
9117 /* This is like sync_file_range but the arguments are reordered */
9118#if TARGET_ABI_BITS == 32
9119 ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
9120 target_offset64(arg5, arg6), arg2));
9121#else
9122 ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
9123#endif
9124 break;
9125#endif
9126#endif
Peter Maydell3b6edd12011-02-15 18:35:05 +00009127#if defined(CONFIG_EPOLL)
9128#if defined(TARGET_NR_epoll_create)
9129 case TARGET_NR_epoll_create:
9130 ret = get_errno(epoll_create(arg1));
9131 break;
9132#endif
9133#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
9134 case TARGET_NR_epoll_create1:
9135 ret = get_errno(epoll_create1(arg1));
9136 break;
9137#endif
9138#if defined(TARGET_NR_epoll_ctl)
9139 case TARGET_NR_epoll_ctl:
9140 {
9141 struct epoll_event ep;
9142 struct epoll_event *epp = 0;
9143 if (arg4) {
9144 struct target_epoll_event *target_ep;
9145 if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
9146 goto efault;
9147 }
9148 ep.events = tswap32(target_ep->events);
9149 /* The epoll_data_t union is just opaque data to the kernel,
9150 * so we transfer all 64 bits across and need not worry what
9151 * actual data type it is.
9152 */
9153 ep.data.u64 = tswap64(target_ep->data.u64);
9154 unlock_user_struct(target_ep, arg4, 0);
9155 epp = &ep;
9156 }
9157 ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
9158 break;
9159 }
9160#endif
9161
9162#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
9163#define IMPLEMENT_EPOLL_PWAIT
9164#endif
9165#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
9166#if defined(TARGET_NR_epoll_wait)
9167 case TARGET_NR_epoll_wait:
9168#endif
9169#if defined(IMPLEMENT_EPOLL_PWAIT)
9170 case TARGET_NR_epoll_pwait:
9171#endif
9172 {
9173 struct target_epoll_event *target_ep;
9174 struct epoll_event *ep;
9175 int epfd = arg1;
9176 int maxevents = arg3;
9177 int timeout = arg4;
9178
9179 target_ep = lock_user(VERIFY_WRITE, arg2,
9180 maxevents * sizeof(struct target_epoll_event), 1);
9181 if (!target_ep) {
9182 goto efault;
9183 }
9184
9185 ep = alloca(maxevents * sizeof(struct epoll_event));
9186
9187 switch (num) {
9188#if defined(IMPLEMENT_EPOLL_PWAIT)
9189 case TARGET_NR_epoll_pwait:
9190 {
9191 target_sigset_t *target_set;
9192 sigset_t _set, *set = &_set;
9193
9194 if (arg5) {
9195 target_set = lock_user(VERIFY_READ, arg5,
9196 sizeof(target_sigset_t), 1);
9197 if (!target_set) {
9198 unlock_user(target_ep, arg2, 0);
9199 goto efault;
9200 }
9201 target_to_host_sigset(set, target_set);
9202 unlock_user(target_set, arg5, 0);
9203 } else {
9204 set = NULL;
9205 }
9206
9207 ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
9208 break;
9209 }
9210#endif
9211#if defined(TARGET_NR_epoll_wait)
9212 case TARGET_NR_epoll_wait:
9213 ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
9214 break;
9215#endif
9216 default:
9217 ret = -TARGET_ENOSYS;
9218 }
9219 if (!is_error(ret)) {
9220 int i;
9221 for (i = 0; i < ret; i++) {
9222 target_ep[i].events = tswap32(ep[i].events);
9223 target_ep[i].data.u64 = tswap64(ep[i].data.u64);
9224 }
9225 }
9226 unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
9227 break;
9228 }
9229#endif
9230#endif
Peter Maydell163a05a2011-06-27 17:44:52 +01009231#ifdef TARGET_NR_prlimit64
9232 case TARGET_NR_prlimit64:
9233 {
9234 /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
9235 struct target_rlimit64 *target_rnew, *target_rold;
9236 struct host_rlimit64 rnew, rold, *rnewp = 0;
9237 if (arg3) {
9238 if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
9239 goto efault;
9240 }
9241 rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
9242 rnew.rlim_max = tswap64(target_rnew->rlim_max);
9243 unlock_user_struct(target_rnew, arg3, 0);
9244 rnewp = &rnew;
9245 }
9246
9247 ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
9248 if (!is_error(ret) && arg4) {
9249 if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
9250 goto efault;
9251 }
9252 target_rold->rlim_cur = tswap64(rold.rlim_cur);
9253 target_rold->rlim_max = tswap64(rold.rlim_max);
9254 unlock_user_struct(target_rold, arg4, 1);
9255 }
9256 break;
9257 }
9258#endif
Richard Henderson3d21d292012-09-15 13:20:46 -07009259#ifdef TARGET_NR_gethostname
9260 case TARGET_NR_gethostname:
9261 {
9262 char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0);
9263 if (name) {
9264 ret = get_errno(gethostname(name, arg2));
9265 unlock_user(name, arg1, arg2);
9266 } else {
9267 ret = -TARGET_EFAULT;
9268 }
9269 break;
9270 }
9271#endif
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009272#ifdef TARGET_NR_atomic_cmpxchg_32
9273 case TARGET_NR_atomic_cmpxchg_32:
9274 {
9275 /* should use start_exclusive from main.c */
9276 abi_ulong mem_value;
9277 if (get_user_u32(mem_value, arg6)) {
9278 target_siginfo_t info;
9279 info.si_signo = SIGSEGV;
9280 info.si_errno = 0;
9281 info.si_code = TARGET_SEGV_MAPERR;
9282 info._sifields._sigfault._addr = arg6;
9283 queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
9284 ret = 0xdeadbeef;
9285
9286 }
9287 if (mem_value == arg2)
9288 put_user_u32(arg1, arg6);
9289 ret = mem_value;
9290 break;
9291 }
9292#endif
9293#ifdef TARGET_NR_atomic_barrier
9294 case TARGET_NR_atomic_barrier:
9295 {
9296 /* Like the kernel implementation and the qemu arm barrier, no-op this? */
Peter Maydell3b899ea2014-03-12 13:06:01 +00009297 ret = 0;
Riku Voipio89aaf1a2013-07-24 09:44:26 +03009298 break;
9299 }
9300#endif
Erik de Castro Lopof4f1e102013-11-29 18:39:23 +11009301
9302#ifdef TARGET_NR_timer_create
9303 case TARGET_NR_timer_create:
9304 {
9305 /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
9306
9307 struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
9308 struct target_sigevent *ptarget_sevp;
9309 struct target_timer_t *ptarget_timer;
9310
9311 int clkid = arg1;
9312 int timer_index = next_free_host_timer();
9313
9314 if (timer_index < 0) {
9315 ret = -TARGET_EAGAIN;
9316 } else {
9317 timer_t *phtimer = g_posix_timers + timer_index;
9318
9319 if (arg2) {
9320 if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) {
9321 goto efault;
9322 }
9323
9324 host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo);
9325 host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify);
9326
9327 phost_sevp = &host_sevp;
9328 }
9329
9330 ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
9331 if (ret) {
9332 phtimer = NULL;
9333 } else {
9334 if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
9335 goto efault;
9336 }
9337 ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
9338 unlock_user_struct(ptarget_timer, arg3, 1);
9339 }
9340 }
9341 break;
9342 }
9343#endif
9344
9345#ifdef TARGET_NR_timer_settime
9346 case TARGET_NR_timer_settime:
9347 {
9348 /* args: timer_t timerid, int flags, const struct itimerspec *new_value,
9349 * struct itimerspec * old_value */
9350 arg1 &= 0xffff;
9351 if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9352 ret = -TARGET_EINVAL;
9353 } else {
9354 timer_t htimer = g_posix_timers[arg1];
9355 struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
9356
9357 target_to_host_itimerspec(&hspec_new, arg3);
9358 ret = get_errno(
9359 timer_settime(htimer, arg2, &hspec_new, &hspec_old));
9360 host_to_target_itimerspec(arg2, &hspec_old);
9361 }
9362 break;
9363 }
9364#endif
9365
9366#ifdef TARGET_NR_timer_gettime
9367 case TARGET_NR_timer_gettime:
9368 {
9369 /* args: timer_t timerid, struct itimerspec *curr_value */
9370 arg1 &= 0xffff;
9371 if (!arg2) {
9372 return -TARGET_EFAULT;
9373 } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9374 ret = -TARGET_EINVAL;
9375 } else {
9376 timer_t htimer = g_posix_timers[arg1];
9377 struct itimerspec hspec;
9378 ret = get_errno(timer_gettime(htimer, &hspec));
9379
9380 if (host_to_target_itimerspec(arg2, &hspec)) {
9381 ret = -TARGET_EFAULT;
9382 }
9383 }
9384 break;
9385 }
9386#endif
9387
9388#ifdef TARGET_NR_timer_getoverrun
9389 case TARGET_NR_timer_getoverrun:
9390 {
9391 /* args: timer_t timerid */
9392 arg1 &= 0xffff;
9393 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9394 ret = -TARGET_EINVAL;
9395 } else {
9396 timer_t htimer = g_posix_timers[arg1];
9397 ret = get_errno(timer_getoverrun(htimer));
9398 }
9399 break;
9400 }
9401#endif
9402
9403#ifdef TARGET_NR_timer_delete
9404 case TARGET_NR_timer_delete:
9405 {
9406 /* args: timer_t timerid */
9407 arg1 &= 0xffff;
9408 if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) {
9409 ret = -TARGET_EINVAL;
9410 } else {
9411 timer_t htimer = g_posix_timers[arg1];
9412 ret = get_errno(timer_delete(htimer));
9413 g_posix_timers[arg1] = 0;
9414 }
9415 break;
9416 }
9417#endif
9418
bellard31e31b82003-02-18 22:55:36 +00009419 default:
9420 unimplemented:
bellard5cd43932003-03-29 16:54:36 +00009421 gemu_log("qemu: Unsupported syscall: %d\n", num);
ths4f2b1fe2007-06-21 21:57:12 +00009422#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 +00009423 unimplemented_nowarn:
bellard80a9d032005-01-03 23:31:27 +00009424#endif
ths0da46a62007-10-20 20:23:07 +00009425 ret = -TARGET_ENOSYS;
bellard31e31b82003-02-18 22:55:36 +00009426 break;
9427 }
bellard579a97f2007-11-11 14:26:47 +00009428fail:
bellardc573ff62004-01-04 15:51:36 +00009429#ifdef DEBUG
Blue Swirl0bf9e312009-07-20 17:19:25 +00009430 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
bellardc573ff62004-01-04 15:51:36 +00009431#endif
thsb92c47c2007-11-01 00:07:38 +00009432 if(do_strace)
9433 print_syscall_ret(num, ret);
bellard31e31b82003-02-18 22:55:36 +00009434 return ret;
bellard579a97f2007-11-11 14:26:47 +00009435efault:
9436 ret = -TARGET_EFAULT;
9437 goto fail;
bellard31e31b82003-02-18 22:55:36 +00009438}